上と左右の当たり判定がおかしいです。

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

上と左右の当たり判定がおかしいです。

#1

投稿記事 by keito940 » 8年前

このスレと合わせて読んで、お答えください。)
現在アクションゲームの当たり判定に悪戦苦闘している人です。どうやら別なところでやれということに気づきこれを立てました。
今起こっている症状:下の当たり判定は完成しているが、上に当たると下に大きく押し出されてしまう。
左右の当たり判定は左に衝突すると、右に大きく押し出してしまう。また右に衝突して左に行こうとすると、何故か倍速で右に行ってしまう。
問題のコードをあげますので自分でデバッグできる方はそれをご覧ください。

コード:

//衝突判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY, float Size) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;
	float blx, brx, bby, bty;
	blx = (float)((int)afX / Size)*Size;
	brx = (float)((int)afX / Size + 1)*Size;
	bty = (float)((int)afY / Size)*Size;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(X, afY - 1.0F) == 1 && *MoveY > 0.0F) {
		//移動量を補正する
		*MoveY = bty - Y - 1.0F;
		//上の壁に当たったと判定する
		return 3;
	}
	if (MapChipParam(X, afY + 1.0F) == 1 && *MoveY < 0.0F) {
		//移動量を補正する
		*MoveY = bby - Y - 1.0F;
		//下の壁に当たったと判定する
		return 4;
	}
	//右の当たり判定
	if (MapChipParam(afX - 1.0F ,Y) == 1 && *MoveX > 0.0F) {
		printf("右に当たりました。");
		//移動量を補正する
		*MoveX = blx - X + 1.0F;
		//右の壁に当たったと判定する
		return 1;
	}
	//左の当たり判定
	if (MapChipParam(afX + 1.0F, Y) == 1 && *MoveX < 0.0F) {
		printf("左に当たりました。");
		//移動量を補正する
		*MoveX = brx - X + 1.0F;
		//左の壁に当たったと判定する
		return 2;
	}
	return 0;
}
//当たり判定チェック
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop,float *G,char *Jump,float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F; 
	//上下の当たり判定チェック、上に衝突したら落下させ、下に衝突したら着地させる。
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F;
		//問題ないのなら移動させる
		*Y += MoveY;
	}
	//左右の当たり判定チェック
	{
		//左下
		MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy, Size);
		//右上
		MapHitCheck(*X + hsize, *Y + hsize, &MoveX, &Dummy, Size);
		//左上
		MapHitCheck(*X - hsize, *Y - hsize, &MoveX, &Dummy, Size);
		//右上
		MapHitCheck(*X + hsize, *Y - hsize, &MoveX, &Dummy, Size);
		//問題ないのなら移動させる
		*X += MoveX;
	}
	//着地判定
	{
		if (MapChipParam(*X - hsize, *Y + hsize + 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
			*Jump = TRUE;
		}
		else {
			*Drop = 0.0F;
			*G = 0.0F;
			*Jump = FALSE;
		}
	}
	return 0;
}

keito940
記事: 105
登録日時: 8年前

Re: 上と左右の当たり判定がおかしいです。

#2

投稿記事 by keito940 » 8年前

部分的なソースコードだけでしたね。ごめんなさい。ソースコード全体を上げたいと思います。ちなみに左右の当たり判定がおかしい原因は、左下と左上と当たり判定が同時に出ていることにあるようです。この不具合をどうやって解消するのか教えてください。(原因が特定できるよう、少し変えてあります。)

コード:

//衝突のテストプログラム
//アクションゲームのテストシステムを作る前に、
//めり込み防止のアルゴリズムを初心者なりに作らざるをえない。
//Create 2017/02/10
#include "DxLib.h"

#define SCREEN_WIDTH (320)		//画面の横幅
#define SCREEN_HEIGHT (240)		//画面の縦幅
#define CHIP_SIZE (16)			//チップのサイズ
#define MAP_WIDTH (SCREEN_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (SCREEN_HEIGHT/CHIP_SIZE)
HANDLE Stdout;

char MapData[MAP_HEIGHT][MAP_WIDTH]
{
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,

	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,1, 1,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,

	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

float PlayerX, PlayerY;
float SaveX, SaveY;
float MoveX, MoveY;
float DropPower, Grav;
char JumpFlag, Dir;

int Input, EdgeInput;
int FreamStartTime;
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY, float Size);
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop, float *G, char *Jump, float Size);
int MapChipParam(float X, float Y);

int MapChipParam(float X, float Y) {
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;

	return MapData[y][x];
}
//衝突判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY, float Size) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;
	float blx, brx, bby, bty;
	blx = (float)((int)afX / Size)*Size;
	brx = (float)((int)afX / Size + 1)*Size;
	bty = (float)((int)afY / Size)*Size;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(X, afY - 1.0F) == 1 && *MoveY > 0.0F) {
		printf("\n下に当たりました。");
		//移動量を補正する
		*MoveY = bty - Y - 1.0F;
		//上の壁に当たったと判定する
		return 3;
	}
	if (MapChipParam(X, afY + 1.0F) == 1 && *MoveY < 0.0F) {
		printf("\n上に当たりました。");
		//移動量を補正する
		*MoveY = bby - Y + 1.0F;
		//下の壁に当たったと判定する
		return 4;
	}
	//右の当たり判定
	if (MapChipParam(afX - 1.0F ,Y) == 1 && *MoveX > 0.0F) {
		printf("\n右に当たりました。");
		//移動量を補正する
		*MoveX = blx - X + 1.0F;
		//右の壁に当たったと判定する
		return 1;
	}
	//左の当たり判定
	if (MapChipParam(afX + 1.0F, Y) == 1 && *MoveX < 0.0F) {
		printf("\n左に当たりました。");
		//移動量を補正する
		*MoveX = brx - X + 1.0F;
		//左の壁に当たったと判定する
		return 2;
	}
	return 0;
}
//当たり判定チェック
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop,float *G,char *Jump,float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F; 
	//上下の当たり判定チェック、上に衝突したら落下させ、下に衝突したら着地させる。
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F,printf("\n上下::左下");
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F,printf("\n上下::右下");
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F,printf("\n上下::左上");
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F,printf("\n上下::右上");
		//問題ないのなら移動させる
		*Y += MoveY;
	}
	//左右の当たり判定チェック
	{
		//左下
		if(MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy, Size))printf("\n左右::左下");
		//右上
		if(MapHitCheck(*X + hsize, *Y + hsize, &MoveX, &Dummy, Size))printf("\n左右::右下");
		//左上
		if(MapHitCheck(*X - hsize, *Y - hsize, &MoveX, &Dummy, Size))printf("\n左右::左上");
		//右上
		if(MapHitCheck(*X + hsize, *Y - hsize, &MoveX, &Dummy, Size))printf("\n左右::右上");
		//問題ないのなら移動させる
		*X += MoveX;
	}
	//着地判定
	{
		if (MapChipParam(*X - hsize, *Y + hsize + 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
			*Jump = TRUE;
		}
		else {
			*Drop = 0.0F;
			*G = 0.0F;
			*Jump = FALSE;
		}
	}
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE),SetGraphMode(320,240,32),printf("初期化しています…"); 
	if (DxLib_Init() == -1) { return -1; }
	PlayerX = 160.0F, PlayerY = 214.0F, MoveX = 0.0F, MoveY = 0.0F;
	JumpFlag = FALSE, DropPower = 0.0F, Grav = 0.5F, Dir = TRUE;
	Input = 0, EdgeInput = 0, FreamStartTime = GetNowCount();
	return 0;
}
int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始\n");
	printf("\nPlayerX=%d,PlayerY=%d,Grav=%8.1f,DropPower=%8.1f", (int)PlayerX, (int)PlayerY, Grav,DropPower);
	printf("MoveX=%8.1f,MoveY=%8.1f,Jump=%d", MoveX, MoveY,JumpFlag);
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	//移動処理
	{
		MoveX = 0.0F;
		MoveY = 0.0F;
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			Dir = TRUE;
			MoveX += 5.0F;
		}
		if ((Input&PAD_INPUT_LEFT) != 0) {
			Dir = FALSE;
			MoveX -= 5.0F;
		}
		if (JumpFlag == FALSE && (EdgeInput&PAD_INPUT_1) != 0) {
			Grav = 0.5F;
			DropPower = -9.5F;
			JumpFlag = TRUE;
		}
		//落下処理
		DropPower += Grav;
		MoveY = DropPower;
		//移動量に基づいて移動する。
		CharMove(&PlayerX, &PlayerY, MoveX, MoveY, &DropPower, &Grav, &JumpFlag, CHIP_SIZE);
		/*//移動処理
		int i = MoveChar(&PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, &JumpFlag, CHIP_SIZE);
		//どういうわけか、常に上に衝突している。僕の考えでは、iが0なら、移動できるとしたいのだが…
		//ようやく、原因が見えてきたぞ。
		printf("\n現在衝突している場所(3:上、4:下、1:左、2:右)=%d", i);
		if (i != 0) {
			PlayerX = SaveX;
			PlayerY = SaveY;
		}*/
	}
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i*CHIP_SIZE + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout); Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
	init();
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		main();
	}
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}

keito940
記事: 105
登録日時: 8年前

Re: 上と左右の当たり判定がおかしいです。

#3

投稿記事 by keito940 » 8年前

え~原因がわかりました。どうやら、キャラのサイズの管理は浮動小数点型ではなく、整数型だったようです。

コード:

//衝突判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY, int Size) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;
	float blx, brx, bby, bty;
	blx = (float)((int)afX / Size)*Size;
	brx = (float)((int)afX / Size + 1)*Size;
	bty = (float)((int)afY / Size)*Size;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(afX, afY) == 1) {
		if (*MoveY > 0.0F) {
			printf("\n下に当たりました。");
			//移動量を補正する
			*MoveY = bty - Y - 1.0F;
			//上の壁に当たったと判定する
			return 3;
		}
		if (*MoveY < 0.0F) {
			printf("\n上に当たりました。");
			//移動量を補正する
			*MoveY = bby - Y + 1.0F;
			//下の壁に当たったと判定する
			return 4;
		}
		//右の当たり判定
		if (*MoveX > 0.0F) {
			printf("\n右に当たりました。");
			//移動量を補正する
			*MoveX = blx - X + 1.0F;
			//右の壁に当たったと判定する
			return 1;
		}
		//左の当たり判定
		if (*MoveX < 0.0F) {
			printf("\n左に当たりました。");
			//移動量を補正する
			*MoveX = brx - X + 1.0F;
			//左の壁に当たったと判定する
			return 2;
		}
		//ここに来たら適当な値を返す
		return 4;
	}
	return 0;
}
//当たり判定チェック
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop,float *G,char *Jump,float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F; 
	//上下の当たり判定チェック、上に衝突したら落下させ、下に衝突したら着地させる。
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize-1.0F, &Dummy, &MoveY,(int)Size) == 3) *Drop = 0.0F,printf("\n上下::左下");
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize-1.0F, &Dummy, &MoveY,(int)Size) == 3) *Drop = 0.0F,printf("\n上下::右下");
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize+1.0F, &Dummy, &MoveY,(int)Size) == 4) *Drop = -1.0F,printf("\n上下::左上");
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize+1.0F, &Dummy, &MoveY,(int)Size) == 4) *Drop = -1.0F,printf("\n上下::右上");
		//問題ないのなら移動させる
		*Y += MoveY;
	}
	//左右の当たり判定チェック
	{
		//左下
		if(MapHitCheck(*X - hsize+1.0F, *Y + hsize, &MoveX, &Dummy, (int)Size))printf("\n左右::左下");
		//右上
		if(MapHitCheck(*X + hsize-1.0F, *Y + hsize, &MoveX, &Dummy, (int)Size))printf("\n左右::右下");
		//左上
		if(MapHitCheck(*X - hsize+1.0F, *Y - hsize, &MoveX, &Dummy, (int)Size))printf("\n左右::左上");
		//右上
		if(MapHitCheck(*X + hsize-1.0F, *Y - hsize, &MoveX, &Dummy, (int)Size))printf("\n左右::右上");
		//問題ないのなら移動させる
		*X += MoveX;
	}
	//着地判定
	{
		if (MapChipParam(*X - hsize, *Y + hsize + 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
			*Jump = TRUE;
		}
		else {
			*Drop = 0.0F;
			*G = 0.0F;
			*Jump = FALSE;
		}
	}
	return 0;
}

cattail
記事: 75
登録日時: 11年前

Re: 上と左右の当たり判定がおかしいです。

#4

投稿記事 by cattail » 8年前

よかったねー!
バグなんてそんなものですよ。
是非、世界をあっと言わせるようなゲームを作って下さいね。
そしてそれを見た人がまた凄いの作ると思いたいですね。
お互いがんばりましょう!

閉鎖

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