キノコの自省録

日々適当クリエイト

プレーヤーに向かってくる弾を撃つ、照準に向かって撃つプログラム用数学

中高生向けのゲームプログラミング用数学の内容です。

敵が真っ直ぐ自分の方向に向かって弾を発射したり、自機が照準に向かって弾を発射したりといった実装をしたいことは多々あると思います。 これ自分が中学生だか高校生くらいの時、実装方法がわからなかったんですよね(なんとなーくそれっぽく動く実装していました)。 昔できなかった自分を思い出して、ちょっとTips書いてみました。

図解と物凄く簡単な実装

超シンプルな実装

f:id:kinokorori:20200106232329p:plain
弾発射

自機が(0, 0)の位置に、敵が(15, 15)の位置にいます。敵が自機に向かって弾を発射したいと思います。弾の速度はどう設定すれば良いでしょうか?

f:id:kinokorori:20200106232752p:plain
-15,-15で動く

弾の速度(velocity)を(-15, -15)に設定すればプレーヤーの方向に飛びます。1フレームで(-15, -15)の場合、絶対に直撃します。

超シンプルな実装2

f:id:kinokorori:20200106233305p:plain
場所移動

では、ちょっと移動して、自機が(1, 6)、敵が(12, 15)の位置にいた場合、どうすれば真っ直ぐ飛ぶでしょう?

要するに、x=12から1へ, y= 15から6へ移動させれば良いので、vx=1 - 12=-11, y=6-15=-9となり、弾の速度を(-11, -9)に設定すればプレーヤー方向へ真っ直ぐ飛びます。

弾の速度を調整する

しかしこれだと、弾速がまちまちになります。簡単に言えば、敵が遠く、例えば(50, 100)にいるときは、(-50, -100)の猛スピードで飛んできますが、敵が近く、例えば(1, 2)にいるときは、(-1, -2)のゆったりスピードで飛んできます。これでは困ります。

要するに、距離に応じて速度が変わるのが困るので、距離で割って距離の影響を取り除いてあげれば良いのです。(-50, -100)の場合の距離は、

 \sqrt{(-50)\times(-50)+(-100)\times(-100)} = \sqrt{12500} (≒ 111.8)

なので、弾の速度を (-\frac{50}{\sqrt{12500}}, -\frac{100}{\sqrt{12500}})とすると、距離の影響が排除できます。

(-1, -2)の場合の距離は、

 \sqrt{(-1)\times(-1)+(-2)\times(-2)} = \sqrt{5}

なので、弾の速度を (-\frac{1}{\sqrt{5}}, -\frac{2}{\sqrt{5}})とすると、距離の影響が排除できます。

これで、 (-\frac{50}{\sqrt{12500}}, -\frac{100}{\sqrt{12500}}) (-\frac{1}{\sqrt{5}}, -\frac{2}{\sqrt{5}})は、進行方向は違えど、速度は同じになりました。

ちなみに弾の速度(-50, -100)や(-1, -2)は、純粋な大きさだけでなく向きを持っていますね。これをベクトルと言います。このベクトルの向きをそのままに、大きさだけを1にしたものを単位ベクトルと言います。 (-1, -2)を単位ベクトルに変換したものが (-\frac{1}{\sqrt{5}}, -\frac{2}{\sqrt{5}})ということです。数学の授業で習います。

単位ベクトルに対して所定値を乗算することで、スピードが調整できます。例えば、 (-\frac{1}{\sqrt{5}}, -\frac{2}{\sqrt{5}})が遅すぎるので速度10倍にしたいなーという場合は、

 (-\frac{10}{\sqrt{5}}, -\frac{20}{\sqrt{5}})

とすれば良いということです。

3次元の場合は?

3次元でも4次元でも同じです。例えば、(2, 4, 5)の方向に弾を撃つ場合、(2, 4, 5)の距離は(\sqrt{2^ 2 + 4^ 2 + 5^ 2}) = \sqrt{45} なので、

単位ベクトルは(\frac{2}{\sqrt{45}}, \frac{4}{\sqrt{45}}, \frac{5}{\sqrt{45}})です。この単位ベクトルに任意の数値を掛けると、速度調整ができます。

MoveTowards

ちなみにUnityの場合は、MoveTowards()という便利なメソッドが用意されています。