ページ 11

ボンバーマン風ゲームの当たり判定について

Posted: 2010年12月31日(金) 15:53
by ぐれーと
僕はDXライブラリでボンバーマン風のゲームを作っています。
いまのところ「24. 行けない所を作る。~2D~」のように、 配列でマップを作ってブロックとの当たり判定をしています。
そして、ブロックとの当たり判定は大体作り終わったのですが、致命的な問題を抱えています。
キャラクターのスピードを設定しているのですが、そのスピードが1や2なら大丈夫なのですが、
3や5になるとブロックとブロックの間にキャラクターが入れなくなる所が発生してしまいました。
どうやったらちゃんとブロックの間に入れるでしょうか?
(キャラクターがスムーズにブロックの間に入れるように、壁にあたると滑るように動くプログラムも組んでいます)

コード:

 
#include "DxLib.h"
 
int Key[256];
 
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
	char GetHitKeyStateAll_Key[256];
	GetHitKeyStateAll( GetHitKeyStateAll_Key );
	for(int i=0;i<256;i++){
		if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
		else                            GetHitKeyStateAll_InputKey[i]=0;
	}
	return 0;
}

typedef struct{
	int x , y , gazou , muki , speed;
}ch_t;


int map[15][20] = { // 0が床 1がブロック
	{9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9},
	{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,0},
	{0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
	{0,1,0,1,0,1,1,1,0,0,0,1,0,1,0,1,0,1,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0},
	{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
};

int atarihantei(int *x , int *y , int muki , int speed){//当たり判定
	
	int x1 , x2 , y1 , y2;
	
	x1 = *x/32;    //キャラの左端の座標のマップ上の位置
	y1 = *y/32;    //キャラの上端の座標のマップ上の位置
	x2 =(*x+31)/32;//キャラの右端の座標のマップ上の位置 
	y2 =(*y+31)/32;//キャラの下端の座標のマップ上の位置
	
	if(map[y1][x1]==1 && muki == 4){//左判定(下移動)
		*x = x2*32;
		y2 =(*y+31-9)/32;
		if(map[y2][x1] ==0)
			*y +=speed; 
	}
	if(map[y2][x1]==1 && muki == 4){//左判定(上移動)
		*x = x2*32;
		y1 =(*y+9)/32;
		if(map[y1][x1] ==0)
			*y -=speed;
	}
	
	if(map[y1][x2]==1 && muki == 3){//右判定(下移動)
		*x = x1*32;
		y2 =(*y+31-9)/32;
		if(map[y2][x2]==0)
			*y +=speed;
	}
	if(map[y2][x2]==1 && muki == 3){//右判定(上移動)
		*x = x1*32;
		y1 =(*y+9)/32;
		if(map[y1][x2]==0)
			*y -=speed;
	}
	
	if(map[y1][x1]==1 && muki == 1){//上判定(右移動)
		*y = y2*32;
		x2 =(*x+31-9)/32;
		if(map[y1][x2]==0)
			*x +=speed;
	}
	if(map[y1][x2]==1 && muki == 1){//上判定(左移動)
		*y = y2*32;
		x1 =(*x+9)/32;
		if(map[y1][x1]==0)
			*x -=speed;
	}
	
	if(map[y2][x1]==1 && muki == 2){//下判定(右移動)
		*y = y1*32;
		x2 =(*x+31-9)/32;
		if(map[y2][x2]==0)
			*x +=speed;
	}
	if(map[y2][x2]==1 && muki == 2){//下判定(左移動)
		*y = y1*32;
		x1 =(*x+9)/32;
		if(map[y2][x1]==0)
			*x -=speed;
	}
	
	DrawFormatString(300, 0,GetColor(255,255,255),"x1:%d y1:%d",x1,y1);
	DrawFormatString(300,15,GetColor(255,255,255),"x2:%d y2:%d",x2,y2);
	                                          
	return 0;
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	ChangeWindowMode(TRUE);//ウィンドウモード
	if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
	
	ch_t ch;
	
	
	ch.x    = 320;
	ch.y    = 240;
	ch.muki = 0;
	ch.speed= 2;
	
	ch.gazou = LoadGraph("char1.png");
	
	int i , j , k = 0, 
	    siro , haiiro , b1gazou , y1gazou ;
	
	siro   = GetColor(255,255,255);
	haiiro = GetColor(130,130,130);
	b1gazou= LoadGraph("block1.png");
	y1gazou= LoadGraph("yuka1.png");
	
	
	while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
		//↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
		
		if(Key[KEY_INPUT_UP] >= 1){//上が押されたら
			ch.y -= ch.speed;
			ch.muki = 1;
		}
		if(Key[KEY_INPUT_DOWN] >= 1 && Key[KEY_INPUT_UP]==0){//上が押されず下が押されたら
			ch.y += ch.speed;
			ch.muki = 2;
		}
		if(Key[KEY_INPUT_RIGHT] >= 1&& Key[KEY_INPUT_UP]==0 
		&& Key[KEY_INPUT_DOWN]  == 0){//上下が押されず右が押されたら
			ch.x += ch.speed;
			ch.muki = 3;
		}
		if(Key[KEY_INPUT_LEFT] >= 1 && Key[KEY_INPUT_UP]==0 
		&& Key[KEY_INPUT_DOWN] == 0 && Key[KEY_INPUT_RIGHT]==0){//上下右が押されず左が押されたら
			ch.x -= ch.speed;
			ch.muki = 4;
		}
		
		atarihantei(&ch.x , &ch.y , ch.muki , ch.speed );
		
		
		for(i=0;i<20;i++)
			for(j=0;j<15;j++){
				if(map[j][i] == 1)
					DrawGraph(i*32,j*32,b1gazou,FALSE);
				if(map[j][i] == 0)
					DrawGraph(i*32,j*32,y1gazou,FALSE);
			}
		
		DrawGraph(ch.x , ch.y , ch.gazou , TRUE);
		
		DrawFormatString(0,0,siro,"x座標:%d y座標:%d",ch.x , ch.y );
		DrawFormatString(180,0,siro,"向き:%d",ch.muki);
		DrawFormatString(0,40,siro,"%d",k);
		ScreenFlip();
	}
	DxLib_End();
	return 0;
}

Re: ボンバーマン風ゲームの当たり判定について

Posted: 2010年12月31日(金) 16:16
by a5ua
滑る処理のときは、speedを1にするというのはどうでしょうか?

Re: ボンバーマン風ゲームの当たり判定について

Posted: 2010年12月31日(金) 18:22
by ぐれーと
それもやってみたのですが、いきなり遅くなって変な動きになってしまうんですよね。
本当のボンバーマンも遅くなりませんし。

Re: ボンバーマン風ゲームの当たり判定について

Posted: 2010年12月31日(金) 19:26
by kimuchi
言ってみるだけですが、
3や5が32の約数ではないから。というのはどうでしょう?

追伸:
此方で動かしたところspeedが4、8、16で正常に動作しました。
滑る動作の所をspeedの値で加減しているようなので、3や5では公倍数以外の場所で
ズレが生じて行ったり来たりの状態になるようです。

関係ないですが、Keyの判定分岐はelseを使えばコンパクトになると思います。

Re: ボンバーマン風ゲームの当たり判定について

Posted: 2011年1月01日(土) 00:55
by a5ua
滑る処理の補正座標を、次のブロックの位置までに制限すればいいのではないでしょうか?
合ってるかわかりませんが、以下のような感じです。

コード:

*y = min(*y + speed, y2 * 32); // 最大でも隣のブロックまでしか移動しない

Re: ボンバーマン風ゲームの当たり判定について

Posted: 2011年1月01日(土) 12:20
by ぐれーと
minってどういう意味でしたっけ?

Re: ボンバーマン風ゲームの当たり判定について

Posted: 2011年1月01日(土) 19:47
by 匿名希望の774さん
ぐれーと さんが書きました:minってどういう意味でしたっけ?
それぐらい自分で調べなさい

Re: ボンバーマン風ゲームの当たり判定について

Posted: 2011年1月01日(土) 20:50
by ぐれーと
minの意味自分で調べました。何でもかんでも質問してすいませんm(_ _)m

教えてもらった方法で解決しました。a5uaさんありがとうございます。
kimuchi さんもご指摘ありがとうございます。とんだバカなプログラム組んでましたね。
今後とも宜しくお願いします。