円運動

■サンプル

●環境
	VisualStudio 2017

	DirectX9(June 2010)

●リンク
	サンプル

		プロジェクト詳細
			Sample01
				中心位置からの移動

			Sample02
				向きベクトルによる移動

■概要

円運動はシューティングの敵やエフェクトの演出の動きなどで使われている移動処理です。
この移動方法で使用される方法として「中心位置からの移動」「向きベクトルによる移動」があります。
どちらにも三角関数などの計算処理が入りますので苦手な方はそちらを確認した方がいいと思います。

■中心位置からの移動

この移動方法は「中心座標から角度、半径の長さによって割り出された位置を
描画座標に加算して新しい描画座標」にします。

	gmpg_0208

●メリット
	・三角関数だけで済む
		この方法は三角関数のsinとcosの計算結果を使用して座標を割り出します。
		もう一つの方法はベクトルの考えを理解していた方がわかりやすいため
		どちらかといえばこちらの方法の方が簡単です。

	・円の動きをそのままに移動させれる
		円の動きをさせつつ上下左右に移動させたいと考えた時に
		中心座標を移動させるだけでいいので簡単に円の動きを意識せずに
		移動させることができます。

	・描画を続けてもずれない
		この後説明する「向きベクトルによる移動」は長時間同じ位置で円運動させた場合
		描画位置がずれる可能性がありますが、こちらの方法ではずれることはありません。

●デメリット
	・専用のメンバが増える
		構造体などで管理する際に中心座標を追加する必要があります。
		円の動きを実装するうえで必要な情報はいくつかありますが、
		中心座標以外の情報はゲーム上で動くオブジェクトにも必要とされるので
		無駄になることはありませんが、中心座標だけは異質なメンバとなるので、
		共通の構造体で考えている場合、ほかで使わないメンバが存在することになります。

●プログラム
	・用意が必要な情報
		必要な情報は「描画座標」「中心座標」「角度」「半径の長さ」が必要です。
		サンプル(Sample01)では以下のような形で用意しています。

		struct DrawObject
		{
			float m_PosX;		// 描画座標X
			float m_PosY;		// 描画座標Y
			float m_Radius;		// 半径(描画用)
			float m_CenterX;	// 中心座標X
			float m_CenterY;	// 中心座標Y
			float m_Angle;		// 角度
			float m_Length;		// 半径の長さ
		};

	・計算方法
		三角関数を使用して計算を行い、その結果を中心座標に加算します。
		計算結果を反映後、角度を更新します。

		// 中心座標に角度と長さを使用した円の位置を加算する
		// 度数法の角度を弧度法に変換
		float radius = enemy.m_Angle * 3.14f / 180.0f;
		
		// 三角関数を使用し、円の位置を割り出す。
		float add_x = cos(radius) * enemy.m_Length;
		float add_y = sin(radius) * enemy.m_Length;
		
		// 結果ででた位置を中心位置に加算し、それを描画位置とする
		enemy.m_PosX = enemy.m_CenterX + add_x;
		enemy.m_PosY = enemy.m_CenterY + add_y;

		// 角度更新
		enemy.m_Angle += 10.0f;


■向きベクトルによる移動

向きベクトルの移動は「オブジェクトがどの方向を向いているかというベクトルを
利用して円の動きをさせる方法」です。
毎フレーム少しずつオブジェクトの向きを変更していくことで、円の動きを実現しますが
こちらはあくまで、円に近い動きができるだけですので、いくつか問題があります。
3Dアクションゲームのキャラクターの旋回の動きなどはこの方法が使用されていることが多いです。

	gmpg_0209

●メリット
	・専用となるメンバが少ない
		この方法は「中心位置からの移動」と比較して、専用のメンバの宣言を
		少なくすることができます。
		特に3Dではこの処理で必要とされるメンバはすべて必須ですので、
		円運動をしないオブジェクトの邪魔になることはありません。

	・柔軟に作りやすい
		直進してきてから突然円を描く動きを行うなどの実装が
		「中心位置からの移動」と比較して簡単にできます。

●デメリット
	・ベクトルの知識がいる
		この方法を理解するには三角関数の知識の他にベクトルの知識がないと
		わかりづらくなっています。

	・誤差が出る
		同じ位置で円運動をさせていたら少しずつ計算誤差が生じてきて
		長時間処理を行っていると描画位置がずれる可能性があります。

	・円運動にならない
		毎フレームで変更する角度が大きすぎると円運動にならないことがあります。
		例えば毎フレーム90度角度変更をすると円ではなく四角に動きます。

●プログラム
	・用意が必要な情報
		必要な情報は「描画座標」「角度」「速度」が必要です。
		サンプル(Sample02)では以下のような形で用意しています。

		struct DrawObject
		{
			float m_PosX;		// 描画座標X
			float m_PosY;		// 描画座標Y
			float m_Radius;		// 半径(描画用)
			float m_Angle;		// 向きの角度
			float m_Speed;		// 速度
		};

	・計算方法
		三角関数を使用して計算を行い、その結果を描画座標に加算します。
		計算結果を反映後、角度を更新します。

		// 角度から移動用のベクトルを求めて描画座標に加算する
		// 度数法の角度を弧度法に変換
		float radius = enemy.m_Angle * 3.14f / 180.0f;
		
		// 三角関数を使用し、円の位置を割り出す。
		float add_x = cos(radius) * enemy.m_Length;
		float add_y = sin(radius) * enemy.m_Length;
		
		// 結果ででた位置を中心位置に加算し、それを描画位置とする
		enemy.m_PosX = enemy.m_CenterX + add_x;
		enemy.m_PosY = enemy.m_CenterY + add_y;

		// 向きを変える
		enemy.m_Angle += 10.0f;