Goきってのドマイナー機能(主観)である複素数演算が、実は2Dゲーム制作ではちょっと便利というお話をしたいと思います。
ベクトル演算をしよう
https://qiita.com/intelf___/items/039eccffd422321ec6dd
https://qiita.com/intelf___/items/f92f5c9ff2e515e16d47
基本的な使い方は上の記事をご覧ください(丸投げ)。
そして、ゲーム制作において主に役立つのは、 複素数に虚数をかけると回転できる という性質です。
実例をご覧ください。
// 発射元の位置
pos := complex(320, 240)
// 一発目のベクトル
vec := complex(100, 0)
// 9方向に発射
n := 9
// 9分の1回転するベクトル
rot := cmplx.Rect(1, 2*math.Pi/float64(n))
// 実際に発射してみる
for i := 0; i < n; i++ {
bullet := pos + vec
vec *= rot
// 以下、いい感じに弾を描画
x, y := real(bullet), imag(bullet)
ox, oy := real(pos), imag(pos)
ebitenutil.DrawLine(screen, ox, oy, x, y, color.White)
}
はい。とてもシンプルなコードで9way弾(のつもり)が発射できました。実に綺麗ですね。僕はそう思います。
手元で動かしたい方はこちらのリポジトリをクローンして go run .
してください。当然ebitenが必須です。
解説が要るのは回転ベクトルの辺りかなと思うので、ここを少し詳しく見てみます。
// 9分の1回転するベクトル
rot := cmplx.Rect(1, 2*math.Pi/float64(n))
cmplx.Rect
は長さと角度を指定して1つの複素数値を得る関数です。
なので、 rot
は長さ1、角度2π/n(つまり9分の1回転)のベクトルに相当します。
そして、これが複素数型の美味しい性質なのですが、ある複素数に長さ11の他の複素数を掛けると、 長さを変えずに回転する ことができます。
それが以下のコードです。
vec *= rot
この計算を一回行うごとにvec
は9分の1回転します。これを9回行うので、丁度綺麗に一周できる寸法ですね。
他にも、
- 移動ベクトルに毎フレーム120分の1回転ベクトルを掛けて、曲がる弾にする。
- プレイヤーと敵の差のベクトルを正規化して掛けて、ホーミング弾にする。
など、いろいろと応用は効きますが、結局はこの 掛け算で回転できる という性質を利用する形になります。
ライブラリに依存せず、ただの掛け算が活躍するのって、少し気持ちよくないですか? 僕は気持ち良いです。
というわけで、以上Goのマイナー機能である複素数型のご紹介でした。
3Dゲームでは使いまわせませんが、ebitenで2Dゲームを作るなら活用してみてはいかがでしょうか。
ご覧いただきありがとうございました。
-
絶対値とするべきですが、わかり易さ優先で。 ↩