プログラマーの卵の日記

備忘録になってます!小難しそうなことから超簡単なことまでやってます!!

【C++】思い通りに物体を動かしたい【2D】

※私はテスト用にDxLibを使ってやってますので一応main関数内のコードもついでに書いてますがそんなに気にしなくていいです。

構成


No.1 適当な上下移動ってこれだ
No.2 斜めって早くね
No.3 角度で移動したい
No.4 重力っぽくつけてホッピングさせたい







      No.1 適当な上下移動ってこれだ


 例えば、移動においてこんなプログラムだった場合


void Move(int& t_x, int& t_y, const int t_speed, const int t_sizeX, const int t_sizeY)
{
	if (CheckHitKey(KEY_INPUT_LEFT) > 0)
	{
		t_x -= t_speed;
		if (t_x <= 0)
		{
			t_x = 0;
		}
	}
	if (CheckHitKey(KEY_INPUT_RIGHT) > 0)
	{
		t_x += t_speed;
		if (t_x >= winWidth - t_sizeX)
		{
			t_x = winWidth - t_sizeX;
		}
	}
	if (CheckHitKey(KEY_INPUT_UP) > 0)
	{
		t_y -= t_speed;
		if (t_y <= 0)
		{
			t_y = 0;
		}
	}
	if (CheckHitKey(KEY_INPUT_DOWN) > 0)
	{
		t_y += t_speed;
		if (t_y >= winHeight - t_sizeY)
		{
			t_y = winHeight - t_sizeY;
		}
	}
}

 


// DxLibのmain関数内の一部
	int x = 0;
	int y = 0;

	// メインループ
	while (!ScreenFlip() && !ProcessMessage() && !ClearDrawScreen() && !CheckHitKey(KEY_INPUT_ESCAPE))
	{
		Move(x, y, 5, 20, 20);
		DrawBox(x, y, x + 20, y + 20, GetColor(255, 0, 0), true);
	}

f:id:yutateno:20191121230441g:plain







      No.2 斜めって早くね


 上記のコードだった場合、縦横は大丈夫かもしれないが、斜め移動では縦横の速度よりも早くなってしまう。
では、正確な速度は何かというと、ピタゴラスの定理で分かります。今回の場合で言うと一方向の速度 x √2になります。
なので、それを考慮したコードに書き換えます。
また、今回はintのままでやりたいですし√2ぐらいならひとよひとよにひとみごろの語呂から適当にやります。


const float m_root2 = 1.4142f;

void Move(int& t_x, int& t_y, const int t_speed, const int t_sizeX, const int t_sizeY)
{
	bool left	 = CheckHitKey(KEY_INPUT_LEFT)	 > 0 ? true : false;
	bool right	 = CheckHitKey(KEY_INPUT_RIGHT)	 > 0 ? true : false;
	bool up		 = CheckHitKey(KEY_INPUT_UP)	 > 0 ? true : false;
	bool down	 = CheckHitKey(KEY_INPUT_DOWN)	 > 0 ? true : false;


	if (left)
	{
		if (up || down)
		{
			t_x -= static_cast<int>(t_speed / m_root2);
		}
		else
		{
			t_x -= t_speed;
		}
		if (t_x <= 0)
		{
			t_x = 0;
		}
	}
	if (right)
	{
		if (up || down)
		{
			t_x += static_cast<int>(t_speed / m_root2);
		}
		else
		{
			t_x += t_speed;
		}
		if (t_x >= winWidth - t_sizeX)
		{
			t_x = winWidth - t_sizeX;
		}
	}
	if (up)
	{
		if (left || right)
		{
			t_y -= static_cast<int>(t_speed / m_root2);
		}
		else
		{
			t_y -= t_speed;
		}
		if (t_y <= 0)
		{
			t_y = 0;
		}
	}
	if (down)
	{
		if (left || right)
		{
			t_y += static_cast<int>(t_speed / m_root2);
		}
		else
		{
			t_y += t_speed;
		}
		if (t_y >= winHeight - t_sizeY)
		{
			t_y = winHeight - t_sizeY;
		}
	}
}

 


// DxLibのmain関数の一部
	int x = 0;
	int y = 0;

	// メインループ
	while (!ScreenFlip() && !ProcessMessage() && !ClearDrawScreen() && !CheckHitKey(KEY_INPUT_ESCAPE))
	{
		Move(x, y, 5, 20, 20);
		DrawBox(x, y, x + 20, y + 20, GetColor(255, 0, 0), true);
	}

 

 もっと正確にするなら全部の型をfloatにし、移動速度も方向によって変えるならそのたびにピタゴラスの定理(V²=Vx²+Vy²)から計算する必要があります。

f:id:yutateno:20191121230818g:plain






      No.3 角度で移動したい


 これまでは速度と向きによって制御していたが、今回は速度と角度で動くようにしてみる。


#define _USE_MATH_DEFINES
#include <cmath>

void CharaInit(float& t_x, float& t_y)
{
	t_x = 310.0f;
	t_y = 230.0f;
}

void Move(float& t_x, float& t_y, float& t_moveX, float& t_moveY, float& t_speed, float& t_angle, const int t_size)
{
	t_x += t_moveX;
	t_y += t_moveY;
	if (t_x < -t_size || t_x > winWidth || t_y < -t_size || t_y > winHeight)
	{
		CharaInit(t_x, t_y);
	}


	bool flag = false;

	if (CheckHitKey(KEY_INPUT_UP) > 0)
	{
		flag = true;
		t_angle += (2.0f * M_PI) / 10.0f;
		if (t_angle > (2.0f * M_PI))
		{
			t_angle -= 2.0f * M_PI;
		}
	}
	if (CheckHitKey(KEY_INPUT_DOWN) > 0)
	{
		flag = true;
		t_angle -= (2.0f * M_PI) / 10.0f;
		if (t_angle < -(2.0f * M_PI))
		{
			t_angle += 2.0f * M_PI;
		}
	}
	if (CheckHitKey(KEY_INPUT_LEFT) > 0)
	{
		flag = true;
		t_speed -= 0.5f;
	}
	if (CheckHitKey(KEY_INPUT_RIGHT) > 0)
	{
		flag = true;
		t_speed += 0.5f;
	}

	if (flag)
	{
		t_moveX = t_speed * std::cosf(t_angle);
		t_moveY = t_speed * std::sinf(t_angle);
	}
}

 


// DxLibのmain関数の一部
	float x = 310.0f;
	float y = 230.0f;
	float angle = M_PI / 6.0f;
	float speed = 5.0f;
	float moveX = speed * std::cosf(angle);
	float moveY = speed * std::sinf(angle);

	// メインループ
	while (!ScreenFlip() && !ProcessMessage() && !ClearDrawScreen() && !CheckHitKey(KEY_INPUT_ESCAPE))
	{
		Move(x, y, moveX, moveY, speed, angle, 20);
		DrawBox(x, y, x + 20, y + 20, GetColor(255, 0, 0), true);
	}


コードを見ればすぐ分かると思いますが、上下のキー操作により36度(一周の1/10)ずつ移動するようになっており、左右のキーにより速度を操作しています。
そののちにキー操作があれば、移動する数値を加算するようにしています。その計算について説明すると長くなるので端折りますが、
簡単に言えば、比例関係にあるxとyの比例係数を三角関数よりcosとsinをそれぞれに割り当てたものです。

f:id:yutateno:20191121232101g:plain






      No.4 重力っぽくつけてホッピングさせたい


 これまでは物体といっても平面に物体を置いた状態で扱っているようなものでした。
それで今回は側面を意識したものとして、物体に重力を与えてみることにしたのをやってみます。今回は物理っぽい式を使ってやります。


void Move(float& t_x, float& t_y, float& t_gravity, float& t_nowFrame, const float t_moveX, const float t_moveY, const float t_size)
{
	t_x += t_moveX;
	t_y = ((1.0f / 2.0f) * t_gravity * t_nowFrame * t_nowFrame + t_moveY * t_nowFrame) + (winHeight - t_size);
	t_nowFrame++;

	if ((t_y > winHeight - t_size))
	{
		t_nowFrame = 0;
		t_gravity += 0.1f;
	}
	if (t_x > winWidth)
	{
		t_x = 0.0f;
	}
}

 


// DxLibのmain関数の一部
	float x = 0.0f;
	float y = 480.0f;
	float gravity = 0.4f;
	float time = 0;
	float vx = 2.0f;
	float vy = -20.0f;

	// メインループ
	while (!ScreenFlip() && !ProcessMessage() && !ClearDrawScreen() && !CheckHitKey(KEY_INPUT_ESCAPE))
	{
		Move(x, y, gravity, time, vx, vy, 20);
		DrawBox(x, y, x + 20, y + 20, GetColor(255, 0, 0), true);
	}


コードを見れば分かると思いますが、物理でよく見るx=1/2at²+v₀tってやつを使ってます。それをそれに開始時の位置を加算する感じで後ろにwinHeight - t_sizeを付けています。
あと重力も9.8じゃねぇのかよって思われそうですが、ゲームって大体はそんなもんだと思います。特に2Dは。

f:id:yutateno:20191121232458g:plain