移動量は極座標

投稿者: | 2012年5月22日

1.はじめに

移動量の定義をするには、「極座標」が向いている、ということを理解してもらえれば、と思います。

2.デカルト座標の欠点

ゲームプログラムをよく分かっていなかったとき、私はこんな構造体を定義していました。

/**
 * 2次元ベクトル
 */
struct Vec2
{
	float x, y;
};

/**
 * スプライト構造体
 */
struct Sprite
{
	Vec2 pos; // 座標
	Vec2 mov; // 移動量
};

こうすると、移動させる場合は、

	pos += mov;

と、そのまま足せるので(もちろん演算子のオーバーロードが必要です)楽なのですが、実は移動量の算出が、とっても不便だったりします。というのは、例えばシューティングの定番弾幕である「扇形弾幕」を生成するとします。この場合、直感的に必要なパラメータは、

  • 角度
  • 速さ

となりますね。


ですが、movが持っているのは、x,yの移動量なので、求めたい「角度」と「速さ」を算出するのは大変です。というのはx方向への移動量を-1、y方向への移動量を1とすれば、確かに225度の方向へ飛んでいきます。でもそこから扇形を作るには、数度ズラして、、、とするわけですが、mov.xやmov.yがすごい数になってしまいますね。また、速度を決めるのも大変です。

そこで、移動量を簡単に決めるために、x,yの座標ではなく、「角度」と「速さ」を持つ座標系に変換します。

この「速さ(length)」と「角度(θ)」を持つ座標を、「極座標」と言います。

3.扱いやすい極座標

こんな構造体を定義しておくと便利ですね。

/**
 * 極座標構造体
 */
struct Polar
{
	float theta; // 角度
	float speed; // 速度
};

これで、直感的に弾幕を作成することができます。生成方法はこんな感じです。(移動量の設定のみ抜粋)

	// 扇形弾幕生成(5度ずつズラす)
	bullet[0].mov = Polar(225, 5);
	bullet[1].mov = Polar(230, 5);
	bullet[2].mov = Polar(235, 5);
	bullet[3].mov = Polar(240, 5);
	bullet[4].mov = Polar(245, 5);

でも、いざ移動をする場合には、このままでは移動後の座標を求めることができません。そこで、「極座標」をx,y座標に変換する必要があります。「極座標」から「x,y座標」への変換には「三角関数」を利用します。

	// 移動する
	pos.x += cos(mov.theta)*speed;
	pos.y += sin(mov.theta)*speed;

これで、移動量の算出が完成です

4.まとめ

  • 極座標は、移動量を算出する場合に「直感的」にパラメータを決めることができる
  • コンピュータが理解できるようには、極座標をx,y座標に変換する必要がある

5.おまけ

関連事項として、プレイヤーの移動量の算出について触れておきます。

まず、悪い例です。

	if(IsPress(KEY_LEFT))  player.pos.x -= 5;
	if(IsPress(KEY_UP))    player.pos.y -= 5;
	if(IsPress(KEY_RIGHT)) player.pos.x += 5;
	if(IsPress(KEY_DONW))  player.pos.y += 5;

こうしてしまうと、図のように斜めの移動量が大きくなってしまいます。これは、正確な操作が求められるシューティングやアクションゲームでは、致命的な欠点になってしまいます。

というのは例えば、スルリと敵の間をすり抜けようとしたのに、斜めだけ移動量が大きくて、勢い余って、敵に衝突してやられてしまった、という事態が発生するからです。(たいていのプレイヤーは、斜めの移動量が大きいなんてことには気づかないことが多い)

良いゲームをデザインする方法として、「プレイヤーの納得しない理由でミスをさせてはいけない」ということがあげられます。これだと、プレイヤーは自分のミスに納得できませんよね。

そこで、例えば、

	if(IsPress(KEY_LEFT) && IsPress(KEY_UP))
	{
		player.mov.theta = 135;
		player.mov.speed = 5;
	}
	・
	・
	・
	player.pos += player.mov.ToVec2(); // 極座標をx,y座標に変換して加算

とするのが良い方法となります。