移動量は極座標

はじめに

今回は初心者向けの内容です。
 
移動量の定義をするには、「極座標」が向いている、
ということを理解してもらえれば、と思います。
 

デカルト座標の欠点

今まで良く考えずに、こんな構造体を定義していました。

/**
 * 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の座標ではなく、「速さ」と「方向」を持つ座標系に変換します。

この「速さ」と「方向」を持つ座標を、「極座標」と言います。

極座標

/**
 * 極座標構造体
 */
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座標に変換する必要があります。
方法としては、三角関数を利用します。

	pos.x += cos(mov.theta)*speed;
	pos.y += sin(mov.theta)*speed;

 
 

まとめ

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

 

おまけ

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

まず、悪い例です。

	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座標に変換して加算

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