Help us understand the problem. What is going on with this article?

2Dゲーム制作に Go の複素数を使い倒そう

More than 1 year has passed since last update.

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)
}

キャプチャ.PNG

はい。とてもシンプルなコードで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ゲームを作るなら活用してみてはいかがでしょうか。
ご覧いただきありがとうございました。


  1. 絶対値とするべきですが、わかり易さ優先で。 

ei1chi
ハローエブリワン
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away