ブログ「サイバー少年」

ブログ「サイバー少年」へようこそ!
小学六年生ごろからプログラミングを趣味にしている高校生のブログです。
勉強したことについての記事などを書いています。フリーソフトも制作、公開しています。
(当ブログについて詳しくは「ブログ概要紹介」を参照)

サイバー少年が作ったフリーソフトは「サイバー少年の作品展示場」へ

三平方の定理でゲームキャラの距離をわり出す。

最近、数学ネタが多いですね。
刹那さんもおっしゃっているのですが、
ゲームと数学って密着しているんですよ。

さて、今日はFlash Boyさんの記事で三平方の定理をゲームに使う記事があったので、
(Flash Boyさんのブログ記事「ピタゴラスの定理」を参照)
その事について考えます。

ゲームに使う、何に使うのかと言うと、
二つのキャラクターのx,y座標から、その二つの間の直線の距離をわり出す事ができるのです
この直線距離をいろいろ(後述)すれば
シューティングゲームなどでプレーヤーを追尾する弾を撃たせることが可能です。


え~、私も数学に詳しくないので、式しか説明できませんが、

三平方の定理とは
直角三角形の
縦の長さ … a、横の長さ … b(逆でも良いよ)、
そして斜辺の長さをcとして

"a2 + b2 = c2"
になると言う物です。

先ほども述べたように、なぜそうなるのかは分かりません。
私がこれを勉強するのはまだまだ先ですから。

さて、なぜ上の式が直線距離の計算と関係するのか説明します。

まずはビジュアルから入りましょう。
始めにシューティングゲームでの弾とプレーヤー(自機)の配置図を描いてみます。
自機と弾の配置図
図1

ヘタクソな図ですが、お許しください。
背景に広大な宇宙でもイメージしてください(笑)

とにかく図1のようにキャラクターが配置されています。
このままでは、ばらばらに配置されているようで分かりにくいので、位置関係を図で表せないでしょうか。

位置関係の図形つき
図2

自機と弾の間に直角三角形が作られています。
どう描いたかと言うと

1.自機の座標(自機の左上)から右へ弾のx座標に届くまで線を引く。
2.そこから上へ、弾の座標のyまで線を引く。
3.さらにそこから1の開始点まで線を引き、つなげる。

このルールに従い線を引くと、自機と弾がどんな位置関係でも直角三角形が描き上がります。
(位置によって上下、左右、何向きに引くか異なりますが、要はxやyの座標に届くまで引くと言うことです。)

さて、自機と弾、二つの物体があれば直角三角形が描けると分かりました。
しかしよく考えてみたら、直角三角形は斜辺さえあれば引けるので
自機と弾を線でつなぎ、残りをまっすぐ縦横引けば直角三角形が出来るのは普通の事です。

ところで、記事の冒頭で直角三角形が関わる数式を見ませんでしたか。

そう、三平方の定理
"a2 + b2 = c2"です。
cが斜線ですので、cが自機と弾の距離です。
(cは図2の青い線を表します。)

先ほどの話とこの式を組み合わせて自機と弾の間の距離が分かります。

aとbは先ほどの三角形の横線と縦線の長さを表します。
言い換えると自機と弾の距離差と言えます。

aとbは斜めの線を表しておらず、x座標やy座標と平行なので、すぐに割り出せます。
(出したいのはcなのです。)

距離差などの数と数の差数を出したい時は引き算を使いますね。
距離差を出す式を作りましょう。
(下のaとbが表す向きは縦横逆でも構いません。)

自機と弾の横の距離差(a) = 自機のx座標 - 弾のx座標
自機と弾の縦の距離差(b) = 自機のy座標 - 弾のy座標

この引き算で距離差が出ます。

もちろん弾の座標の方が自機の座標より大きかった場合は答えがマイナスになります。
マイナスになった場合はプラスに変えてください。
出したいのは距離なのでプラスマイナス関係ありません。
(むしろマイナスのままではこの先へ進めません。)

また、答えのプラスマイナス関係はないと言う事は
引き算の引く方、引かれる方は逆でも良い事を意味しています。


さて、この手順を終えると直角三角形の横縦線の長さa、bが出せました。
後は斜線の長さのcを出せば自機と弾の距離が出ます。
(何度も言うようですが、斜線の長さ = 自機と弾の距離差です。これは図2を見ればよく分かります。)

では、どのようにしてcを出せばいいのでしょうか。
aとbは分かっているので…
そう、三平方の定理を使えばいいのです。

"a2 + b2 = c2"

まずはaとbをそれぞれ2乗しましょう。
ちゃんとマイナスはプラスにしましたね。
2乗の処理は各言語に任せます。

これでようやくc2が出せました。
気づいている方もいるのではないでしょうか。
お疲れ様でしたと言いたい所ですが、出せたのはでc2あってcではありません。
斜線の距離はcですので、cを割り出さなければなりません。

そこで2乗済みの数値から元を出すには数値の2乗根、つまり数値の平方根をとればいいのです。
平方根を出す処理は各言語に任せます。

さて、これでとうとうcが出せました。
自機と弾の距離が分かったのです!




追伸: 弾を追尾させる処理

距離を出しただけでは役に立つことはまずないと思います。
プレイヤー(自機)に向かって、弾を追尾させる方法をご紹介します。

弾を自機にぶつける為には三角のaとbをx, yにそれぞれ足せば良いのは分かるでしょうか。
差を足して差を無くすと言うことです。
(ここではマイナスをプラスに変えず、そのままにします。)

弾の現在の座標にx, yをそのまま足すと、
弾の座標と自機の座標が同じになります。
これは一種の追尾(とてもスピードが速い追尾)です。

このスピードを遅くしてやれば行きかけの状態、追尾状態になります。

そこに斜線距離cが登場します。
(縦横のa, cは逆でも構いません。)
注意: ここではa, bの符号を変えずに、マイナスならマイナスのままにしてください。

x = a / c
y = b /c

このx, yを弾の現在座標のx, yに毎回加算すると、一応、自機を追尾します。
しかし、これでは動く速さが固定となっています。
(約、1ピクセルですのでかなり遅いです。)

なのでxやyにお好みの自然数を乗算してください。
かける数が大きいほど弾は速くなります。

かける自然数 … s

自機のx座標 += x * s
自機のy座標 += y * s

これで追尾の処理が書けます。
書き方は各言語によって異なります。

なんでa, bをcで割ると追尾できるのかは私もよく分かりません。
この記事は、なぜcが自機と弾の距離なのかの説明なので、
詳しいことを知りたい方は他のソースから学習してください。

では本当にお疲れ様でした!
(記事書いた私も相当疲れました!)

tag:

コメント

3平方の定理にこんな使い方があるとは思いませんでした。
とても参考になりました。
ありがとうございます。

  • 2012/10/23(火) 22:31:00 |
  • URL |
  • 17keito #-
  • [ 編集 ]

コメントの投稿

トラックバック

トラックバック URL
http://cyberboy6.blog.fc2.com/tb.php/147-5208bda8
この記事にトラックバックする(FC2ブログユーザー)

【AndroidでOpenGL ES】3D空間の距離を測る

  はじめに 2Dでも3Dでも、世の中に出ているゲームの大半は物理法則を人工的に埋め込んでいます。 敵と衝突したら一定量、逆のベクトルへ飛び、壁があればその先へ進むことができません。 プログラムでは、密着しているかどうかを判定することになりますが、同じように、木箱と一人称カメラの距離はどのくらいなのか?という問題はどうやって解決すればいいのでしょうか。 今回はAndroid×Ope...

  • 2014/01/08(水) 20:45:16 |
  • OpenGL ESからJBulletまで3DAndroid入門@プロバナ

当ブログをご利用(閲覧等)になる場合は必ず「当ブログの利用規定」をお守りください。