「回転移動する」弾幕を作りたいんだ!

この記事は何

この記事では、アフィン変換を使う具体例について説明します。今までのシリーズとは異なり、行列の定義と簡単な計算方法を知っていないとわりと難しいと思います。

記事の最後には動作例もあるのでそちらは是非見てくださいね。

ご挨拶

みなさんこんにちは。RiG++コーディング課の田きです。4回目ですね。今までは正直高校生レベルの内容でしたが、今回は行列の演算の話があるので大学生っぽく張り切っていけそうです(?)。模様を描くためのちょっとだけ難しい話をしていきたいと思います。

今回やる事

この記事では、Unityエンジン上で弾幕を回転させようと思います。その方法を書いていこうと思います。

登場する変数

$x,y,z$それぞれのオイラー角の変化速度(角速度) $R = (x_r,y_r,z_r)$
$x,y,z$それぞれの速度$V = (x_m,y_m,z_m)$ (まあ2D弾幕ならzは0が多いですが)
変換の中心点$P_0 = (x_0,y_0,z_0)$

以上!(今回はたくさんあるぞ!!)

実際に考察してみましょう

弾が移動しながら回転する事を考えてみます。愚直に弾を回転させようと思うと以下のステップが必要になります。

回転の中心まで弾をずらす→弾の向きを取得する→向きから角度を求める→角度をずらして座標更新→最初ずらしただけ弾をもとの位置に戻す

大変ですね。これをいちいち考えながら行うのはとても大変です。そのため、先人の知識であるアフィン変換を使ってこれを何とかしましょう。

アフィン変換とは(たぶん違う)

拡大縮小、反転、回転、平行移動、せん断などができる変換行列を用いて、新たなる座標を求めることです。今回用いるのはこの変換部分だけです。

今回行いたいのは平行移動と回転ですが、結局それ用の変換行列を求めなければなりません。行列計算は大変です。

とみせかけて、実はUnityが変換行列を生成してくれます。それこそが、Matrix4x4.TRS()です。引数に、平行移動の量、回転の量、拡大の量を渡してやることで、簡単に変換行列を作成してくれます。さらに、それで求めた行列.MultiplyPointで、引数にもともとの座標を渡してやると、変換された座標が返ってきます。

よって、使う側が意識するのはこれだけになりました。

回転の中心まで弾をずらす→Matrix4x4.TRS()→MultiplyPoint→最初ずらしただけ弾をもとの位置に戻す

ここまでくれば後は何とかなりそうな気がしてきましたね!ではやっていきましょう。

変換行列 $M$は、Matrix4x4.TRS($V,R,(1,1,1)$)でごく簡単に求められます。

これを適用したい弾すべてに適用させましょう。

$弾_i$があり、その位置が$P_i = (x_i,y_i,z_i)$であるとしましょう。

まずは中心まで位置をずらした値$P_i-P_0$を記録します。その後、M.MultiplyPoint( $P_i-P_0$ )$+ P_0 $を計算すれば、求めたい座標が求まりました。あとは新しい座標を更新してやればOKです。

なぜ、$弾_i$や$P_i$を置いたかといいますと、変換行列$M$を使いまわせているからです。そう、どんな座標に対しても、同様の変換は同様の行列で行う事ができるのです。

まとめ

私の説明能力もあり、何を言っているのかわからないかもしれませんが、アフィン変換やUnityの機能を用いることで弾幕を回転させることが出来ました。

アフィン変換はCGでは頻繁に用いられる変換です。当然、ゲームエンジンの内部ではよく使われています。シェーダーなどにも使いそうですね。また、アフィン変換を移動の拡張と取ることで、アイデア次第で今までの弾幕にもアフィン変換を取り入れられるかもしれません。また、弾の移動処理も速度でUnityにお任せするのではなく、自身でフレームごとにアフィン変換してみるのもいいかもしれません。私もまだまだアフィン変換の事はわかりませんが、表現の幅が広がるので1回生や2回生の方にはぜひ理解していただきたいと思っています。

弾幕を楽しんでくださいね。

動作例

拙作ではありますが、以下のようなものが作れます。

音が出ます!!!!!

上の動画では、多角形を、x軸かy軸かz軸に対して回転させています。それと同時に、下方向に移動させています。2Dゲームなのに、3Dっぽい回転(など)を、4行4列の行列を使って表現できるのは面白いですね。2Dだけでは味わえない美しさを感じられると思います。

コメントを残す

CAPTCHA