撃った弾の軌道を変更したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
tonari
記事: 28
登録日時: 6年前

撃った弾の軌道を変更したい

#1

投稿記事 by tonari » 6年前

撃った弾がボールに当たると特定の角度に軌道を変えるという処理を行いたいのですが。
うまくいきません。ボールに弾が当たっていないのに勝手に角度が変わってしまったり,ちゃんと当たった後に変わったりします
どうすればボールに当たった時だけ弾の軌道を変更することができますか?おそらくvoid HitCheck()の中の角度を変える部分が間違っていると思うのですが・・・

コード:

#define _USE_MATH_DEFINES
#include "DxLib.h"
#include <math.h>
#define SCREEN_WIDIH 1000
#define SCREEN_HEIGHT 900
#define SHOTS_MAX 5

//キーの実装
int key[256];
int gpUpdatekey()
{
	char tmpkey[256];               //現在のキーの入力状態を格納
	GetHitKeyStateAll(tmpkey);      //すべてのキーの入力状態を得る
	for (int i = 0; i < 256; ++i)
	{
		if (tmpkey[i] != 0)
		{
			++key[i];
		}
		else
		{
			key[i] = 0;
		}
	}
	return 0;
}
struct Obj
{
	int     x;
	int     y;
	int     w;
	int     h;
	int		direction;	//向き、1でプラス方向
	double  now_x;		//反射する直前の座標を格納
	double  now_y;
	double	degree;		//弾の反射角度を格納
	double	radian = M_PI / 180.0f * degree;
	bool	flag;
	int		speed;
	int		color;
};

Obj me;
Obj shot[SHOTS_MAX];
Obj Enemy;
Obj Eshot[SHOTS_MAX];
Obj mirror_ball;
int RED = GetColor(255, 0, 0);
int White = GetColor(255, 255, 255);
int Blue = GetColor(0, 0, 255);
int Green = GetColor(0, 255, 0);
int SkyBlue = GetColor(0, 255, 255);

//自機初期化
void Block_Ini()
{
	me.x = 0;
	me.y = SCREEN_HEIGHT;
	me.w = 50;
	me.h = 50;
	me.flag = true;
	me.color = RED;
	me.speed = 5;
}
//弾の初期化
void Shot_Ini()
{
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		shot[s].x = me.x + (me.w / 2);
		shot[s].y = me.y;
		shot[s].speed = 10;
		shot[s].color = White;
		shot[s].flag = false;
	}
}
//敵初期化
void Enemy_Ini()
{
	Enemy.x = SCREEN_WIDIH / 2;
	Enemy.y = SCREEN_HEIGHT / 10;
	Enemy.w = 50;
	Enemy.h = 50;
	Enemy.direction = 1;
	Enemy.flag = true;
	Enemy.color = Blue;
	Enemy.speed = 3;
}
//敵の弾の初期化
void EnemyShot_Ini()
{
	for (int e_s = 0; e_s < SHOTS_MAX; ++e_s)
	{
		Eshot[e_s].x = Enemy.x + (Enemy.w / 2);
		Eshot[e_s].y = Enemy.y;
		Eshot[e_s].speed = 10;
		Eshot[e_s].color = Green;
		Eshot[e_s].flag = false;
	}
}
//弾が当たると特定の角度に軌道を変えるミラーボールの初期化
void MirrorBall_Ini()
{
			mirror_ball.x = (SCREEN_WIDIH / 2);
			mirror_ball.y = (SCREEN_HEIGHT / 2);
			mirror_ball.color = SkyBlue;
}
//自機更新
void Block_Update()
{
	if (me.flag == true)
	{
		if (key[KEY_INPUT_RIGHT] > 0 && me.x + me.w <= SCREEN_WIDIH)
		{
			me.x += me.speed;
		}
		if (key[KEY_INPUT_LEFT] > 0 && me.x >= 0)
		{
			me.x -= me.speed;
		}
		for (int s = 0; s < SHOTS_MAX; ++s)
		{
			if (key[KEY_INPUT_Z] == 1 && shot[s].flag == false)
			{
				shot[s].flag = true;
				shot[s].x = me.x + (me.w / 2);
				shot[s].y = me.y;
				break;
			}
		}
	}
}
//弾の更新
void Shot_Update()
{
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		if (shot[s].flag == true)
		{
			shot[s].y -= shot[s].speed;
		}
		if (shot[s].y <= 0 && shot[s].flag == true)
		{
			shot[s].flag = false;
		}
	}
}
//敵の動き
void Enemy_Update()
{
	if (Enemy.flag == true)
	{
		if (Enemy.x + Enemy.w >= SCREEN_WIDIH)
		{
			Enemy.direction = -1;
		}
		if (Enemy.x <= 0)
		{
			Enemy.direction = 1;
		}
		for (int e_s = 0; e_s < SHOTS_MAX; ++e_s)
		{
			if (key[KEY_INPUT_X] == 1 && Eshot[e_s].flag == false)
			{
				Eshot[e_s].flag = true;
				Eshot[e_s].x = Enemy.x + (Enemy.w / 2);
				Eshot[e_s].y = Enemy.y;
				break;
			}
		}
	}
	Enemy.x += Enemy.speed * Enemy.direction;
}
//敵の弾の更新
void Eshot_Update()
{
	for (int e_s = 0; e_s < SHOTS_MAX; ++e_s)
	{
		if (Eshot[e_s].flag == true)
		{
			Eshot[e_s].y += Eshot[e_s].speed;
		}
		if (Eshot[e_s].y >= SCREEN_HEIGHT && Eshot[e_s].flag == true)
		{
			Eshot[e_s].flag = false;
		}
	}
}
//弾のあたり判定
{
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		//自機の弾と敵
		if (Enemy.flag == true && shot[s].flag == true)
		{
			if (shot[s].y <= Enemy.y && shot[s].y <= Enemy.y + Enemy.h && shot[s].x <= Enemy.x + Enemy.w && shot[s].x >= Enemy.x)
			{
				Enemy.flag = false;
				shot[s].flag = false;
			}
		}
		//敵の弾と自機
		if (me.flag == true && Eshot[s].flag == true)
		{
			if (Eshot[s].y <= me.y && Eshot[s].y >= me.y - me.h && Eshot[s].x <= me.x + me.w && Eshot[s].x >= me.x)
			{
				me.flag = false;
				Eshot[s].flag = false;
			}
		}
	}
	//ミラーボールと弾の判定
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		if (shot[s].y <= mirror_ball.y && shot[s].y <= mirror_ball.y && shot[s].x <= mirror_ball.x && shot[s].x >= mirror_ball.x)
		{
			shot[s].direction = 1;
			shot[s].radian = 45;
		}
		shot[s].x += (double)shot[s].speed * cos(shot[s].radian) * shot[s].direction;
	}
}
//描画
void Obj_Draw()
{
	//弾
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		if (shot[s].flag == true)
		{
			DrawCircle(shot[s].x, shot[s].y, 2, shot[s].color, true);
		}
		if (Eshot[s].flag == true)
		{
			DrawCircle(Eshot[s].x, Eshot[s].y, 2, Eshot[s].color, true);
		}
	}
	//ミラーボール
		DrawCircle(mirror_ball.x, mirror_ball.y, 20, mirror_ball.color, true);
	//自機
	if (me.flag == true)
	{
		DrawBox(me.x, me.y - me.h, me.x + me.w, me.y, me.color, true);
	}
	//敵
	if (Enemy.flag == true)
	{
		DrawBox(Enemy.x, Enemy.y - Enemy.h, Enemy.x + Enemy.w, Enemy.y, Enemy.color, true);
	}
}

//エントリーポイント
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	ChangeWindowMode(1), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);   //ウィンドウモード変更と初期化と裏画面設定
																		//ウインドウサイズ(1000*900)
	SetGraphMode(SCREEN_WIDIH, SCREEN_HEIGHT, 32);
	//初期化処理
	MirrorBall_Ini();
	Block_Ini();
	Shot_Ini();
	Enemy_Ini();
	EnemyShot_Ini();
	
	// while(裏画面を表画面に反映、メッセージ処理、画面クリア、キーの更新)
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdatekey() == 0)
	{
		//ここにゲームの処理を描く------------------------------------------------

		Block_Update();
		Shot_Update();
		Enemy_Update();
		Eshot_Update();
		HitCheck();
		Obj_Draw();

		//----------------------------------------------------------------------
	}
	DxLib_End();                            // DXライブラリ終了処理
	return 0;
}

 

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 撃った弾の軌道を変更したい

#2

投稿記事 by みけCAT » 6年前

きちんと読んでいませんが、とりあえず当たり判定をまともにすれば改善するかもしれません。
196行目、205行目、215行目で、それぞれ似ているけど違う式が書かれていますね。
205行目の式はx, yともにある座標がある有限の範囲内かを求める式になっていますが、
196行目と215行目ではyのチェックする範囲が無限になっており、215行目のxでは範囲の幅が0 (=一致するかの判定) となっています。
これらの196行目と215行目の式は当たり判定として不自然でしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

tonari
記事: 28
登録日時: 6年前

Re: 撃った弾の軌道を変更したい

#3

投稿記事 by tonari » 6年前

返信ありがとうございます。
とりあえずボールとのあたり判定の部分を以下のように変更したのですが、
今度は配列に格納されている弾の情報が、反射するとそれ以降ずっと45度になってしまします、
反射して弾がfalseになったらまた通常通り上方向に撃てるようにしたいのですがどうすればよいでしょうか?

コード:

if (shot[s].y <= mirror_ball.y + mirror_ball.r && shot[s].y >= mirror_ball.y - mirror_ball.r 
 && shot[s].x >= mirror_ball.x - mirror_ball.r && shot[s].x <= mirror_ball.x + mirror_ball.r)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 撃った弾の軌道を変更したい

#4

投稿記事 by みけCAT » 6年前

これまでと同様に、発射する時に全てのパラメータを初期化(設定)するといいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

tonari
記事: 28
登録日時: 6年前

Re: 撃った弾の軌道を変更したい

#5

投稿記事 by tonari » 6年前

悩んだ末にこのようになりました、
まだ改善しなければならないところがありますがひとまず解決しました。
ありがとうございます。

コード:

#define _USE_MATH_DEFINES
#include "DxLib.h"
#include <math.h>
#define SCREEN_WIDIH 1000
#define SCREEN_HEIGHT 900
#define SHOTS_MAX 10

//キーの実装
int key[256];
int gpUpdatekey()
{
	char tmpkey[256];               //現在のキーの入力状態を格納
	GetHitKeyStateAll(tmpkey);      //すべてのキーの入力状態を得る
	for (int i = 0; i < 256; ++i)
	{
		if (tmpkey[i] != 0)
		{
			++key[i];
		}
		else
		{
			key[i] = 0;
		}
	}
	return 0;
}
struct Obj
{
	int     x;
	int     y;
	int     w;
	int     h;
	int		r;
	int		direction;	//向き、1でプラス方向
	double  now_x;		//反射する直前の座標を格納
	double  now_y;
	double	degree;		//弾の反射角度を格納
	double	radian = M_PI / 180.0f * degree;
	bool	flag;
	int		speed;
	int		color;
};

Obj me;
Obj shot[SHOTS_MAX];
Obj Enemy;
Obj Eshot[SHOTS_MAX];
Obj mirror_ball;
int RED = GetColor(255, 0, 0);
int White = GetColor(255, 255, 255);
int Blue = GetColor(0, 0, 255);
int Green = GetColor(0, 255, 0);
int SkyBlue = GetColor(0, 255, 255);

//自機初期化
void Block_Ini()
{
	me.x = 0;
	me.y = SCREEN_HEIGHT;
	me.w = 50;
	me.h = 50;
	me.flag = true;
	me.color = RED;
	me.speed = 5;
}
//弾の初期化
void Shot_Ini()
{
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		shot[s].x = me.x + (me.w / 2);
		shot[s].y = me.y;
		shot[s].r = 2;
		shot[s].speed = 10;
		shot[s].color = White;
		shot[s].flag = false;
	}
}
//敵初期化
void Enemy_Ini()
{
	Enemy.x = SCREEN_WIDIH / 2;
	Enemy.y = SCREEN_HEIGHT / 10;
	Enemy.w = 50;
	Enemy.h = 50;
	Enemy.direction = 1;
	Enemy.flag = true;
	Enemy.color = Blue;
	Enemy.speed = 3;
}
//敵の弾の初期化
void EnemyShot_Ini()
{
	for (int e_s = 0; e_s < SHOTS_MAX; ++e_s)
	{
		Eshot[e_s].x = Enemy.x + (Enemy.w / 2);
		Eshot[e_s].y = Enemy.y;
		shot[e_s].r = 2;
		Eshot[e_s].speed = 10;
		Eshot[e_s].color = Green;
		Eshot[e_s].flag = false;
	}
}
//弾が当たると特定の角度に軌道を変えるミラーボールの初期化
void MirrorBall_Ini()
{
			mirror_ball.x = (SCREEN_WIDIH / 2);
			mirror_ball.y = (SCREEN_HEIGHT / 2);
			mirror_ball.r = 20;
			mirror_ball.color = SkyBlue;
}
//自機更新
void Block_Update()
{
	if (me.flag == true)
	{
		if (key[KEY_INPUT_RIGHT] > 0 && me.x + me.w <= SCREEN_WIDIH)
		{
			me.x += me.speed;
		}
		if (key[KEY_INPUT_LEFT] > 0 && me.x >= 0)
		{
			me.x -= me.speed;
		}
		for (int s = 0; s < SHOTS_MAX; ++s)
		{
			if (key[KEY_INPUT_Z] == 1 && shot[s].flag == false)
			{
				//弾の再設定
				shot[s].flag = true;
				shot[s].x = me.x + (me.w / 2);
				shot[s].y = me.y;
				break;
			}
		}
	}
}
//弾の更新
void Shot_Update()
{
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		if (shot[s].flag == true)
		{
			shot[s].y -= shot[s].speed;
		}
		if (shot[s].y <= 0 && shot[s].flag == true)
		{
			shot[s].flag = false;
		}
	}
}
//敵の動き
void Enemy_Update()
{
	if (Enemy.flag == true)
	{
		if (Enemy.x + Enemy.w >= SCREEN_WIDIH)
		{
			Enemy.direction = -1;
		}
		if (Enemy.x <= 0)
		{
			Enemy.direction = 1;
		}
		for (int e_s = 0; e_s < SHOTS_MAX; ++e_s)
		{
			if (key[KEY_INPUT_X] == 1 && Eshot[e_s].flag == false)
			{
				//弾の再設定
				Eshot[e_s].flag = true;
				Eshot[e_s].x = Enemy.x + (Enemy.w / 2);
				Eshot[e_s].y = Enemy.y;
				break;
			}
		}
	}
	Enemy.x += Enemy.speed * Enemy.direction;
}
//敵の弾の更新
void Eshot_Update()
{
	for (int e_s = 0; e_s < SHOTS_MAX; ++e_s)
	{
		if (Eshot[e_s].flag == true)
		{
			Eshot[e_s].y += Eshot[e_s].speed;
		}
		if (Eshot[e_s].y >= SCREEN_HEIGHT && Eshot[e_s].flag == true)
		{
			Eshot[e_s].flag = false;
		}
	}
}
//弾のあたり判定
void HitCheck()
{
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		//自機の弾と敵
		if (Enemy.flag == true && shot[s].flag == true)
		{
			if (shot[s].y <= Enemy.y && shot[s].y <= Enemy.y + Enemy.h 
			 && shot[s].x <= Enemy.x + Enemy.w && shot[s].x >= Enemy.x)
			{
				Enemy.flag = false;
				shot[s].flag = false;
			}
		}
		//敵の弾と自機
		if (me.flag == true && Eshot[s].flag == true)
		{
			if (Eshot[s].y <= me.y && Eshot[s].y >= me.y - me.h 
			 && Eshot[s].x <= me.x + me.w && Eshot[s].x >= me.x)
			{
				me.flag = false;
				Eshot[s].flag = false;
			}
		}
	}
	//ミラーボールと弾の判定
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		if (shot[s].y <= mirror_ball.y + mirror_ball.r && shot[s].y >= mirror_ball.y - mirror_ball.r 
		 && shot[s].x >= mirror_ball.x - mirror_ball.r && shot[s].x <= mirror_ball.x + mirror_ball.r)
		{
			shot[s].direction = 1;
			shot[s].degree = 45;
		}	
		else if(shot[s].flag == false)
		{
			shot[s].degree = 90;
		}
		shot[s].x += shot[s].speed * cos(shot[s].radian) * shot[s].direction;
		shot[s].radian = M_PI / 180.0f * shot[s].degree;		//角度の更新
	}
}
//描画
void Obj_Draw()
{
	//弾
	for (int s = 0; s < SHOTS_MAX; ++s)
	{
		if (shot[s].flag == true)
		{
			DrawCircle(shot[s].x, shot[s].y, shot[s].r, shot[s].color, true);
		}
		if (Eshot[s].flag == true)
		{
			DrawCircle(Eshot[s].x, Eshot[s].y, shot[s].r, Eshot[s].color, true);
		}
	}
	//ミラーボール
		DrawCircle(mirror_ball.x, mirror_ball.y, mirror_ball.r, mirror_ball.color, true);
	//自機
	if (me.flag == true)
	{
		DrawBox(me.x, me.y - me.h, me.x + me.w, me.y, me.color, true);
	}
	//敵
	if (Enemy.flag == true)
	{
		DrawBox(Enemy.x, Enemy.y - Enemy.h, Enemy.x + Enemy.w, Enemy.y, Enemy.color, true);
	}
}

//エントリーポイント
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	ChangeWindowMode(1), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);   //ウィンドウモード変更と初期化と裏画面設定
																		//ウインドウサイズ(1000*900)
	SetGraphMode(SCREEN_WIDIH, SCREEN_HEIGHT, 32);
	//初期化処理
	MirrorBall_Ini();
	Block_Ini();
	Shot_Ini();
	Enemy_Ini();
	EnemyShot_Ini();
	
	// while(裏画面を表画面に反映、メッセージ処理、画面クリア、キーの更新)
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdatekey() == 0)
	{
		//ここにゲームの処理を描く------------------------------------------------

		Block_Update();
		Shot_Update();
		Enemy_Update();
		Eshot_Update();
		HitCheck();
		Obj_Draw();

		//----------------------------------------------------------------------
	}
	DxLib_End();                            // DXライブラリ終了処理
	return 0;
}


返信

“C言語何でも質問掲示板” へ戻る