敵の衝突判定について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
yaegasi

敵の衝突判定について

#1

投稿記事 by yaegasi » 7年前

http://dixq.net/g/26.html
こちらの改造版なんですが
敵同士との衝突してマスがだぶらないようにしたいのですが
どうしてもうまくいきません。ダブルやつがいます
どうすればいいでしょうか

コード:

 
#include "DxLib.h"
 
typedef struct{
        int x,y,img,muki,walking_flag;
}ch_t;    ch_t ch;
 
typedef struct{
        int x,y,life,counter,img,walkimg,faceimg,muki,kasoumuki,speed,walking_flag,flag,msgflag,hanninflag,tenmetuflag,zoukaryou;
        char msg[120];
}enemy_t;//敵の初期位置xyは32で割り切れる数でなければならない。でないと壁抜けしたり向きがおかしくなる
    //32の倍数 32,64,96,128,160,192,224,256,288,320,352,384,416,448,480,512,544,576,608,640,672
//waikimgは敵の歩く画像をloaddivgraphでenemygazou[128]に4×4個を128個読み込んでるので4×4の塊の左上の最初の数。図に書くとわかりやすい
//0→1番目のキャラの塊の最初の画像,4→2番目,8→3番目,12→4番目,64→5番目,68→6番目,72→7番目,76→8番目
enemy_t enemy[50] = {
		{ 320,160,3,7,2,0,1,1,0,2,1,1,0,0,0,0,"大事なものは体に身につけるようにしよう。"},
		{ 288,128,4,7,2,4,1,1,0,2,1,1,0,0,0,0,"あなた井の中の蛙ね"},
		{ 256,96,5,7,2,8,2,2,0,2,1,1,0,0,0,0,"なに?ーー。やべえな。"},
		{ 224,224,6,7,2,12,3,2,0,2,1,1,0,0,0,0,"ちっぱお"},
		{ 630,96,3,7,2,64,4,2,0,2,1,1,0,0,0,0,"大久保"},
		{ 662,96,7,3,2,68,5,0,0,2,1,1,0,0,0,0,"ダンクーダ"},
		{ 288,160,4,3,2,72,6,3,0,2,1,1,0,0,0,0,"レンジで5分"},
		{ 288,192,5,3,2,76,7,0,0,2,1,1,0,0,0,0,"おちっこ漏れちゃうー"},
		{ 320,224,7,3,2,0,7,2,0,2,1 ,1,0,0,0,0,"知ってるかい?一番右のやつ盗撮が趣味なんだって"},
		{ 320,256,7,3,2,4,1,2,0,2,1 ,1,0,0,0,0,"この中に殺人鬼がいるらしい"},
		{ 320,288,3,8,2,8,2,2,0,2,1 ,1,0,0,0,0,"どうしようお金すられたわ。犯人捜して頂戴"},
		{ 320,320,3,9,2,12,3,2,0,2,1 ,1,0,0,0,0,"この中。"},
		{ 352,224,3,10,2,64,4,2,0,2,1,1,0,0,0,0,"さ"},
		{ 352,256,3,7,2,68,5,2,0,2,0 ,1,0,0,0,0,""},
		{ 352,288,3,7,2,72,6,2,0,2,0 ,1,0,0,0,0,"ああああああーーーさっき株が暴落して1億吹っ飛んだーー会社の金なのにどうしよう。ねえ誰か1億ちょうだい?"},
		{ 352,320,3,7,2,76,2,1,0,2,0 ,1,0,0,0,0,"こんなに人と肩ぶつかりまくるわ"},
		{ 352,352,3,7,2,0,7,2,0,2,0 ,1,0,0,0,0,"さっきどさくさに紛れて痴漢した奴がいるわ"},
		{ 352,384,7,3,2,4,0,3,0,2,0,1,0,0,0,0,"おっす。"},
		{ 352,416,7,3,2,8,2,2,0,3,0 ,1,0,1,0,0,"僕だ"},
		{ 384,132,3,7,2,12,2,0,0,2,1 ,1,0,0,0,0,"うん"},
		{ 384,224,3,7,2,64,0,0,0,2,1 ,1,0,0,0,0,"はやく来てくれーーーーー"},
		{ 384,256,3,7,2,68,0,0,0,2,1 ,1,0,0,0,0,"めがね落とした。"},
		{ 384,288,3,7,2,72,0,0,0,2,1 ,1,0,0,0,0,"なに?痴漢を探してるって?そいつなら知ってるぞ。確か口癖が「らんらんるー」だったかな"},
		{ 384,320,3,7,2,78,0,0,0,2,1 ,1,0,0,0,0,"つぼみ"},
		{ 416,256,7,3,2,4,1,2,0,2,1 ,1,0,0,0,0,"この中に殺人鬼がいるらしい"},
		{ 416,288,3,8,2,8,2,2,0,2,1 ,1,0,0,0,0,"どうしようお金すられたわ。犯人捜して頂戴"},
		{ 416,320,3,9,2,12,3,2,0,2,1 ,1,0,0,0,0,"この中に。早く探して寝取らないと先を越されちゃう"},
		{ 448,224,3,10,2,64,4,2,0,2,1,1,0,0,0,0,"さっき"},
		{ 448,256,3,7,2,68,5,2,0,2,0 ,1,0,0,0,0,""},
		{ 448,288,3,7,2,72,6,2,0,2,0 ,1,0,0,0,0,"ああああああーーーさっき株が暴落して1億吹っ飛んだーー会社の金なのにどうしよう。ねえ誰か1億ちょうだい?"},
		{ 448,320,3,7,2,76,2,1,0,2,0 ,1,0,0,0,0,"こんなに人と肩ぶつかりまくるわ。"},
		{ 448,352,3,7,2,0,7,2,0,2,0 ,1,0,0,0,0,"さっきどさくさに紛れて痴漢した奴がいるわ"},
		{ 448,384,7,3,2,4,0,3,0,2,0,1,0,0,0,0,"おっす。オラ悟空"},
		{ 448,416,7,3,2,8,2,2,0,3,0 ,1,0,1,0,0,"僕はね、"},
		{ 480,132,3,7,2,12,2,0,0,2,1 ,1,0,0,0,0,""},
		{ 480,224,3,7,2,64,0,0,0,2,1 ,1,0,0,0,0,"はやく来てくれーーーーー"},
		{ 480,256,3,7,2,68,0,0,0,2,1 ,1,0,0,0,0,"めがね落とした。ねがめねがめ"},
		{ 480,288,3,7,2,72,0,0,0,2,1 ,1,0,0,0,0,"「らんらんるー」"},
		{ 480,320,3,7,2,78,0,0,0,2,1 ,1,0,0,0,0,"つぼみ"},};


int hantei[15][34] = {
        { 1,1,1,1,1,1,1,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 },
        { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,1,1,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,1,1,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0 },
        { 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 },
        { 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 }, 
};
 
int IsAbleToGo(int x,int y,int muki){//進めるかを判定する

	if(muki==0){//上向きなら
                if(hantei[y/32-1][x/32]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;if(y/32-1==ch.y/32&&x/32==ch.x/32)return 2;}
        if(muki==1){//左向きなら
                if(hantei[y/32][x/32-1]==1)
                        return 1;if(y/32==ch.y/32&&x/32-1==ch.x/32)return 2;}
        if(muki==2){//下向きなら
                if(hantei[y/32+1][x/32]==1)
                        return 1;if(y/32+1==ch.y/32&&x/32==ch.x/32)return 2;}
        if(muki==3){//右向きなら
                if(hantei[y/32][x/32+1]==1)
                        return 1;if(y/32==ch.y/32&&x/32+1==ch.x/32)return 2;}
        return 0;//正常
}

int Chcolision(int x,int y,int muki){
       	int kiriageX = (int)(x + 0.9);int kiriageY = (int)(y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする.マス移動中は少数になるため切り上げて次のマスに行ったことにする
        int kiriageChX = (int)(ch.x + 0.9);int kiriagechY = (int)(ch.y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする
 
	if(muki==0)//上向きなら
               if(kiriageY/32==kiriagechY/32-1&&kiriageX/32==kiriageChX/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
        if(muki==1)//左向きなら
               if(kiriageY/32==kiriagechY/32&&kiriageX/32==kiriageChX/32-1)
                        return 1;
        if(muki==2)//下向きなら
                if(kiriageY/32==kiriagechY/32+1&&kiriageX/32==kiriageChX/32)
                        return 1;
        if(muki==3)//右向きなら
               if(kiriageY/32==kiriagechY/32&&kiriageX/32==kiriageChX/32+1)
                        return 1;
        return 0;//正常
}
int Enecolision(int x,int y,int muki){
       
	int kiriageX = (int)(x + 0.9);int kiriageY = (int)(y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う
	int kiriageChX = (int)(ch.x + 0.9);int kiriagechY = (int)(ch.y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする
 
      if(muki==0)//上向きなら
               if(kiriageY/32-1==kiriagechY/32&&kiriageX/32==kiriageChX/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
        if(muki==1)//左向きなら
               if(kiriageY/32==kiriagechY/32&&kiriageX/32-1==kiriageChX/32)
                        return 1;
        if(muki==2)//下向きなら
                if(kiriageY/32+1==kiriagechY/32&&kiriageX/32==kiriageChX/32)
                        return 1;
        if(muki==3)//右向きなら
               if(kiriageY/32==kiriagechY/32&&kiriageX/32+1==kiriageChX/32)
                        return 1;
        return 0;//正常
}
//敵同士の衝突判定 xyが実際動かすやつで、x2y2が先にいるか調べるやつ
int EnetoEnecolision(int x,int y,int x2,int y2,int muki){
       
	int kiriageX = (int)(x + 0.9);int kiriageY = (int)(y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う
	int kiriageX2 = (int)(x2 + 0.9);int kiriageY2 = (int)(y2 + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする
 
      if(muki==0)//上向きなら
               if(kiriageY/32-1==kiriageY2/32&&kiriageX/32==kiriageX2/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
        if(muki==1)//左向きなら
               if(kiriageY/32==kiriageY2/32&&kiriageX/32-1==kiriageX2/32)
                        return 1;
        if(muki==2)//下向きなら
                if(kiriageY/32+1==kiriageY2/32&&kiriageX/32==kiriageX2/32)
                        return 1;
        if(muki==3)//右向きなら
               if(kiriageY/32==kiriageY2/32&&kiriageX/32+1==kiriageX2/32)
                        return 1;
        return 0;//正常
}
//敵同士の衝突判定 敵Aと敵Bの行く予定のマスがダブってるか調べる
int preEnetoEnecolision(int x,int y,int x2,int y2,int muki,int muki2){
 

      if(muki==0){//上向きなら 基本調べるほうに+1とかつける
               if(muki2==1)if(y/32-1==y2/32&&x/32+1==x2/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
               if(muki2==2)if(y/32-2==y2/32&&x/32==x2/32)
				       return 1;
			   if(muki2==3)if(y/32-1==y2/32&&x/32-1==x2/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;}
	  if(muki==1){//左向きなら
               if(muki2==0)if(y/32+1==y2/32&&x/32-1==x2/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
               if(muki2==2)if(y/32-1==y2/32&&x/32-1==x2/32)
				       return 1;
			   if(muki2==3)if(y/32==y2/32&&x/32-2==x2/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;}
        if(muki==2){//下向きなら
               if(muki2==0)if(y/32+2==y2/32&&x/32==x2/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
               if(muki2==1)if(y/32+1==y2/32&&x/32+1==x2/32)
				       return 1;
			   if(muki2==3)if(y/32+1==y2/32&&x/32-1==x2/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;}
        if(muki==3){//右向きなら
               if(muki2==0)if(y/32+1==y2/32&&x/32+1==x2/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
               if(muki2==1)if(y/32==y2/32&&x/32+2==x2/32)
				       return 1;
			   if(muki2==2)if(y/32-1==y2/32&&x/32+1==x2/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;}
        return 0;//正常
}
int Chdistance(int x,int y,int x2,int y2){

if((y-y2)*(y-y2)+(x-x2)*(x-x2)<32*32)
          return 1;

        return 0;//正常
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        
    int image[16],i,j=0;
    char Key[256];
int attacknumber,tenmetumode=0,attackmode=0,tenmetucounter=0,zoukaryou=0,enezoukaryou=0,turn=1;
 int random[3],state=0;
 int msgnumber,walktmp=0;
 
    if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理
    int msgmode=0;char tmpmsg[80]="";
    ch.x    =320;
    ch.y    =160;
    ch.walking_flag=0;
    ch.muki=3;
 int scrmapX=32,scrmapY=32;
    SetDrawScreen( DX_SCREEN_BACK ) ;                                                 //描画先を裏画面に設定
    LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存

    while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
            //↑メッセージ処理        ↑画面をクリア         ↑キーボード入力状態取得       ↑ESCが押されると終了
 
                
		
		if(ch.x%32==0 && ch.y%32==0){         //座標が32で割り切れたら入力可能
            ch.walking_flag=1;         //歩くフラグを立てる。
            if     ( Key[ KEY_INPUT_UP   ]  == 1 )  //上ボタンが押されたら
                    ch.muki=0;         //上向きフラグを立てる
            else if( Key[ KEY_INPUT_LEFT ]  == 1 )  //左ボタンが押されたら
                    ch.muki=1;         //左向きフラグを立てる
            else if( Key[ KEY_INPUT_DOWN ]  == 1 )  //下ボタンが押されたら
                    ch.muki=2;         //下向きフラグを立てる
            else if( Key[ KEY_INPUT_RIGHT]  == 1 )  //右ボタンが押されたら
                    ch.muki=3;         //右向きフラグを立てる
            else                                    //何のボタンも押されてなかったら
                    ch.walking_flag=0; //歩かないフラグを立てる
            if(ch.walking_flag==1)    //もし歩くなら
                if(IsAbleToGo(ch.x,ch.y,ch.muki)==1)//行き先が歩けないなら
                    ch.walking_flag=0;                  //歩かないフラグを立てる。
        }

		for(int i = 0 ; i < 50 ; i ++ )
		{ if(Chcolision(enemy[i].x,enemy[i].y,ch.muki)==1)//行き先が歩けないなら(このマップは0が壁で1が通路であるから注意)
           if(ch.x%32==0 && ch.y%32==0)ch.walking_flag=0;
		}
 
       if(ch.walking_flag==1){        //歩くフラグが立っていたら
            if     (ch.muki==0){       //上向きならch.y座標を減らす
                    ch.y -=4;scrmapY +=4;zoukaryou +=4;}
            else if(ch.muki==1){        //左向きならch.x座標を減らす
                    ch.x -=4;scrmapX +=4;zoukaryou +=4;}
            else if(ch.muki==2){       //下向きならch.y座標を増やす
                    ch.y +=4;scrmapY -=4;zoukaryou +=4;}
            else if(ch.muki==3){         //右向きならch.x座標を増やす
                    ch.x +=4;scrmapX -=4;zoukaryou +=4;}
        }


if(zoukaryou==32 ){
	turn=0;
zoukaryou=0;}
for(int i = 0 ; i < 50 ; i ++ )
if(enemy[i].x%32==0 && enemy[i].y%32==0 )if(enemy[i].zoukaryou==32){turn=1;enemy[i].zoukaryou=0;}




		//敵同士の衝突判定。敵同士の仮想グリップ上の座標で一歩先に敵いるか調べる。xyが32で割り切れる座標で一瞬だけ評価するからけっこうザル
	for(int i = 0 ; i < 50 ; i ++ )
for(int j = 0 ; j < 50 ; j ++ )if(turn==0)if(enemy[i].flag==1)
if(enemy[i].x%32==0 && enemy[i].y%32==0 )//↓行き先に主人公orカベor敵があれば
if(IsAbleToGo(enemy[i].x,enemy[i].y,enemy[i].muki)==2||IsAbleToGo(enemy[i].x,enemy[i].y,enemy[i].muki)==1||EnetoEnecolision(enemy[i].x,enemy[i].y,enemy[j].x,enemy[j].y,enemy[i].muki)==1||preEnetoEnecolision(enemy[i].x,enemy[i].y,enemy[j].x,enemy[j].y,enemy[i].muki,enemy[j].muki)==1)
        for(int r=0;r<=3;r++)//行き先が壁もしくは主人公がいない方向探す
			if(IsAbleToGo(enemy[i].x,enemy[i].y,r)==0)
				if(EnetoEnecolision(enemy[i].x,enemy[i].y,enemy[j].x,enemy[j].y,r)==0)
						if(preEnetoEnecolision(enemy[i].x,enemy[i].y,enemy[j].x,enemy[j].y,r,enemy[j].muki)==0){random[r]=r;enemy[i].muki= GetRand(random[r]);}

//敵Aと敵Bの行く予定のマスがダブったら		



for(int i = 0 ; i < 50 ; i ++ )
		{if(turn==0)if(enemy[i].flag==1)
	   	if( enemy[i].walking_flag==1) 
                 if(enemy[i].muki==0){ 
                  enemy[i].y -=4;enemy[i].zoukaryou +=4;}
	        else if(enemy[i].muki==1){        //左向きならch.x座標を減らす
                    enemy[i].x -=4;enemy[i].zoukaryou +=4;}
            else if(enemy[i].muki==2){        //下向きならch.y座標を増やす
                    enemy[i].y +=4;enemy[i].zoukaryou +=4;}
            else if(enemy[i].muki==3){        //右向きならch.x座標を増やす
                    enemy[i].x +=4;enemy[i].zoukaryou +=4;}
}


        ch.img=image[(ch.x%32+ch.y%32)/8 + ch.muki*4];            //画像をセット
 		
		for(int i = 0 ; i < 50 ; i ++ )
		{
        enemy[i].img=image[(enemy[i].x%32+enemy[i].y%32)/8 + enemy[i].muki*4];            //画像をセット
 	}
   

		for(int i = 0 ; i < 50 ; i ++ )
		{ if(Chcolision(enemy[i].x,enemy[i].y,ch.muki)==1)//行き先が歩けないなら(このマップは0が壁で1が通路であるから注意)
           if(ch.x%32==0 && ch.y%32==0)ch.walking_flag=0;
		}

 		for( i = 0 ; i < 50 ; i ++ ){  //メッセージ処理   
     if(Chcolision(enemy[i].x,enemy[i].y,ch.muki)==1)
		if( Key[ KEY_INPUT_RETURN    ]  == 1)enemy[i].msgflag=1;msgmode=1;
}  
   if(msgmode==1){
 		for( i = 0 ; i < 50 ; i ++ ){  //メッセージ処理   
   if(enemy[i].msgflag==1)                // 配列の終端-2以下で、今回コピーするiまでの配列要素のi番目が\0じゃなくカウンターが5の倍数なら
                if(j<=80-2 && enemy[i].msg[j]!='\0'){
                        j+=2;                    // 全角文字なので配列要素2つずつカウントアップ
                        strncpy(tmpmsg,enemy[i].msg,j);// iバイトまでの配列要素をdisp配列にコピー
                        tmpmsg[j]='\0';            // 終端記号を代入
  }
	DrawFormatString(10,20,GetColor(255,25,255),"%s",tmpmsg);//disp配列の文字データを表示

}
 }               /*白い壁を描画*/
                for(i=0;i<15;i++)
                        for(j=0;j<34;j++)
                                if(hantei[i][j]==1)
                                        DrawBox(j*32+scrmapX,i*32+scrmapY,(j-1)*32+scrmapX,(i-1)*32+scrmapY,GetColor(255,255,255),TRUE);
 
        DrawGraph( 320 , 160 , ch.img , TRUE ) ;//画像を描画
 		for( i = 0 ; i < 50 ; i ++ ){  //なぜか一個ずれてたんで-32   
			DrawGraph( enemy[i].x-32 + scrmapX, enemy[i].y-32 + scrmapY   , enemy[i].img , TRUE ) ;
}  
		DrawFormatString( 0, 80, GetColor(0,0,255), "ch.x%d",ch.x);
		DrawFormatString( 0, 100, GetColor(0,0,255), "ch.y%d",ch.y); 

        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}
 

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 敵の衝突判定について

#2

投稿記事 by softya(ソフト屋) » 7年前

すごくソースコードがごちゃごちゃしてますね。バグを誘発する原因なので、まず整理しましょう。
1.インデントを綺麗に揃える。
2.同じような処理が出てきたら関数化する
3./32の様な定番処理も関数化するとか関数の最初で/32した値を作っておく。
4.mainの処理が多いので関数に分ける。Player処理、表示処理、敵処理を分けてみましょう。
こうすると大分整理されると思います。
そうするとバグが調べやすくなりますので、まず整理をお願いします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2648
登録日時: 9年前
連絡を取る:

Re: 敵の衝突判定について

#3

投稿記事 by ISLe » 7年前

DXライブラリの初歩的な質問です • C言語交流フォーラム ~ mixC++ ~
この記事と同じ問題があるのでは。

それでも同じマスに同時に入れてしまう問題は残ると思います。
マップにキャラの存在フラグを持たせればずっとシンプルになりますが。

yaegasi

Re: 敵の衝突判定について

#4

投稿記事 by yaegasi » 7年前

>マップにキャラの存在フラグを持たせれば
どんなコードになるのでしょうか
簡単な例があると助かります

ISLe
記事: 2648
登録日時: 9年前
連絡を取る:

Re: 敵の衝突判定について

#5

投稿記事 by ISLe » 7年前

yaegasi さんが書きました:>マップにキャラの存在フラグを持たせれば
どんなコードになるのでしょうか
簡単な例があると助かります
hantei配列のキャラが居る位置の上位バイトにデータを書き込んで障害物と同じように判定するのですが。
判定方法自体は簡単ですが、複数のキャラが存在しないと例として成立しないので、サンプルコード全体としては簡単にできません。

↑の説明で分からないようであれば改造は難しいと思うので、こちらで質問に書かれたコードを改造したものを投稿したいと思います。
時間が掛かりますのでしばらくお待ちください。

yaegasi

Re: 敵の衝突判定について

#6

投稿記事 by yaegasi » 7年前

こういう感じでしょうか
うまくいきました↓
しかし実座標で判定した場合と配列で判定した場合
とで結果が違うのはなぜなんでしょう・・・・

コード:

#include "DxLib.h"
 
typedef struct{
        int x,y,img,muki,walking_flag;
}ch_t;    ch_t ch;
 
typedef struct{
        int x,y,life,counter,img,walkimg,faceimg,muki,kasoumuki,speed,walking_flag,flag,msgflag,hanninflag,tenmetuflag,zoukaryou;
        char msg[120];
}enemy_t;//敵の初期位置xyは32で割り切れる数でなければならない。でないと壁抜けしたり向きがおかしくなる
    //32の倍数 32,64,96,128,160,192,224,256,288,320,352,384,416,448,480,512,544,576,608,640,672
//waikimgは敵の歩く画像をloaddivgraphでenemygazou[128]に4×4個を128個読み込んでるので4×4の塊の左上の最初の数。図に書くとわかりやすい
//0→1番目のキャラの塊の最初の画像,4→2番目,8→3番目,12→4番目,64→5番目,68→6番目,72→7番目,76→8番目
enemy_t enemy[50] = {
        { 320,160,3,7,2,0,1,1,0,2,1,1,0,0,0,0,"大事なものは体に身につけるようにしよう。"},
        { 288,128,4,7,2,4,1,1,0,2,1,1,0,0,0,0,"あなた井の中の蛙ね"},
        { 256,96,5,7,2,8,2,2,0,2,1,1,0,0,0,0,"なに?ーー。やべえな。"},
        { 224,224,6,7,2,12,3,2,0,2,1,1,0,0,0,0,"ちっぱお"},
        { 630,96,3,7,2,64,4,2,0,2,1,1,0,0,0,0,"大久保"},
        { 662,96,7,3,2,68,5,0,0,2,1,1,0,0,0,0,"ダンクーダ"},
        { 288,160,4,3,2,72,6,3,0,2,1,1,0,0,0,0,"レンジで5分"},
        { 288,192,5,3,2,76,7,0,0,2,1,1,0,0,0,0,"おちっこ漏れちゃうー"},
        { 320,224,7,3,2,0,7,2,0,2,1 ,1,0,0,0,0,"知ってるかい?一番右のやつ盗撮が趣味なんだって"},
        { 320,256,7,3,2,4,1,2,0,2,1 ,1,0,0,0,0,"この中に殺人鬼がいるらしい"},
        { 320,288,3,8,2,8,2,2,0,2,1 ,1,0,0,0,0,"どうしようお金すられたわ。犯人捜して頂戴"},
        { 320,320,3,9,2,12,3,2,0,2,1 ,1,0,0,0,0,"この中。"},
        { 352,224,3,10,2,64,4,2,0,2,1,1,0,0,0,0,"さ"},
        { 352,256,3,7,2,68,5,2,0,2,1 ,1,0,0,0,0,""},
        { 352,288,3,7,2,72,6,2,0,2,1 ,1,0,0,0,0,"ああああああーーーさっき株が暴落して1億吹っ飛んだーー会社の金なのにどうしよう。ねえ誰か1億ちょうだい?"},
        { 352,320,3,7,2,76,2,1,0,2,1 ,1,0,0,0,0,"こんなに人と肩ぶつかりまくるわ"},
        { 352,352,3,7,2,0,7,2,0,2,1 ,1,0,0,0,0,"さっきどさくさに紛れて痴漢した奴がいるわ"},
        { 352,384,7,3,2,4,0,3,0,2,1,1,0,0,0,0,"おっす。"},
        { 352,416,7,3,2,8,2,2,0,3,1 ,1,0,1,0,0,"僕だ"},
        { 384,128,3,7,2,12,2,0,0,2,1 ,1,0,0,0,0,"うん"},
        { 384,224,3,7,2,64,0,0,0,2,1 ,1,0,0,0,0,"はやく来てくれーーーーー"},
        { 384,256,3,7,2,68,0,0,0,2,1 ,1,0,0,0,0,"めがね落とした。"},
        { 384,288,3,7,2,72,0,0,0,2,1 ,1,0,0,0,0,"なに?痴漢を探してるって?そいつなら知ってるぞ。確か口癖が「らんらんるー」だったかな"},
        { 384,320,3,7,2,78,0,0,0,2,1 ,1,0,0,0,0,"つぼみ"},
        { 416,256,7,3,2,4,1,2,0,2,1 ,1,0,0,0,0,"この中に殺人鬼がいるらしい"},
        { 416,288,3,8,2,8,2,2,0,2,1 ,1,0,0,0,0,"どうしようお金すられたわ。犯人捜して頂戴"},
        { 416,320,3,9,2,12,3,2,0,2,1 ,1,0,0,0,0,"この中に。早く探して寝取らないと先を越されちゃう"},
        { 448,224,3,10,2,64,4,2,0,2,1,1,0,0,0,0,"さっき"},
        { 448,256,3,7,2,68,5,2,0,2,1 ,1,0,0,0,0,""},
        { 448,288,3,7,2,72,6,2,0,2,1 ,1,0,0,0,0,"ああああああーーーさっき株が暴落して1億吹っ飛んだーー会社の金なのにどうしよう。ねえ誰か1億ちょうだい?"},
        { 448,320,3,7,2,76,2,1,0,2,1 ,1,0,0,0,0,"こんなに人と肩ぶつかりまくるわ。"},
        { 448,352,3,7,2,0,7,2,0,2,1 ,1,0,0,0,0,"さっきどさくさに紛れて痴漢した奴がいるわ"},
        { 448,384,7,3,2,4,0,3,0,2,1,1,0,0,0,0,"おっす。オラ悟空"},
        { 448,416,7,3,2,8,2,2,0,3,1 ,1,0,1,0,0,"僕はね、"},
        { 480,128,3,7,2,12,2,0,0,2,1 ,1,0,0,0,0,""},
        { 480,224,3,7,2,64,0,0,0,2,1 ,1,0,0,0,0,"はやく来てくれーーーーー"},
        { 480,256,3,7,2,68,0,0,0,2,1 ,1,0,0,0,0,"めがね落とした。ねがめねがめ"},
        { 480,288,3,7,2,72,0,0,0,2,1 ,1,0,0,0,0,"「らんらんるー」"},
        { 480,320,3,7,2,78,0,0,0,2,1 ,1,0,0,0,0,"つぼみ"},};
 
 
int hantei[15][34] = {
        { 1,1,1,1,1,1,1,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 },
        { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,1,1,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0 },
        { 1,1,1,1,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,1,1,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0 },
        { 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 },
        { 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 }, 
};
 int enemyhantei[15][34] = {
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
};
int IsAbleToGo(int x,int y,int muki){//進めるかを判定する
 
    if(muki==0){//上向きなら
                if(hantei[y/32-1][x/32]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;if(y/32-1==ch.y/32&&x/32==ch.x/32)return 2;}
        if(muki==1){//左向きなら
                if(hantei[y/32][x/32-1]==1)
                        return 1;if(y/32==ch.y/32&&x/32-1==ch.x/32)return 2;}
        if(muki==2){//下向きなら
                if(hantei[y/32+1][x/32]==1)
                        return 1;if(y/32+1==ch.y/32&&x/32==ch.x/32)return 2;}
        if(muki==3){//右向きなら
                if(hantei[y/32][x/32+1]==1)
                        return 1;if(y/32==ch.y/32&&x/32+1==ch.x/32)return 2;}
        return 0;//正常
}
 
int Chcolision(int x,int y,int muki){
        int kiriageX = (int)(x + 0.9);int kiriageY = (int)(y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする.マス移動中は少数になるため切り上げて次のマスに行ったことにする
        int kiriageChX = (int)(ch.x + 0.9);int kiriagechY = (int)(ch.y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする
 
    if(muki==0)//上向きなら
               if(kiriageY/32==kiriagechY/32-1&&kiriageX/32==kiriageChX/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
        if(muki==1)//左向きなら
               if(kiriageY/32==kiriagechY/32&&kiriageX/32==kiriageChX/32-1)
                        return 1;
        if(muki==2)//下向きなら
                if(kiriageY/32==kiriagechY/32+1&&kiriageX/32==kiriageChX/32)
                        return 1;
        if(muki==3)//右向きなら
               if(kiriageY/32==kiriagechY/32&&kiriageX/32==kiriageChX/32+1)
                        return 1;
        return 0;//正常
}
int Enecolision(int x,int y,int muki){
       
    int kiriageX = (int)(x + 0.9);int kiriageY = (int)(y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う
    int kiriageChX = (int)(ch.x + 0.9);int kiriagechY = (int)(ch.y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする
 
      if(muki==0)//上向きなら
               if(kiriageY/32-1==kiriagechY/32&&kiriageX/32==kiriageChX/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
        if(muki==1)//左向きなら
               if(kiriageY/32==kiriagechY/32&&kiriageX/32-1==kiriageChX/32)
                        return 1;
        if(muki==2)//下向きなら
                if(kiriageY/32+1==kiriagechY/32&&kiriageX/32==kiriageChX/32)
                        return 1;
        if(muki==3)//右向きなら
               if(kiriageY/32==kiriagechY/32&&kiriageX/32+1==kiriageChX/32)
                        return 1;
        return 0;//正常
}
//敵同士の衝突判定 xyが実際動かすやつで、x2y2が先にいるか調べるやつ
int EnetoEnecolision(int x,int y,int x2,int y2,int muki){
 

      if(muki==0)//上向きなら
               if(enemyhantei[y/32-1][x/32]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
        if(muki==1)//左向きなら
               if(enemyhantei[y/32][x/32-1]==1)
                        return 1;
        if(muki==2)//下向きなら
               if(enemyhantei[y/32+1][x/32]==1)
                        return 1;
        if(muki==3)//右向きなら
               if(enemyhantei[y/32][x/32+1]==1)

                        return 1;
        return 0;//正常
}
//敵同士の衝突判定 敵Aと敵Bの行く予定のマスがダブってるか調べる
int preEnetoEnecolision(int x,int y,int x2,int y2,int muki,int muki2){
 

      if(muki==0){//上向きなら 基本調べるほうに+1とかつける
               if(muki2==1)if(enemyhantei[y/32-1][x/32+1]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
               if(muki2==2)if(enemyhantei[y/32-2][x/32]==1)
				       return 1;
			   if(muki2==3)if(enemyhantei[y/32-1][x/32-1]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1; }
	  if(muki==1){//左向きなら
               if(muki2==0)if(enemyhantei[y/32+1][x/32-1]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
               if(muki2==2)if(enemyhantei[y/32-1][x/32-1]==1)
				       return 1;
			   if(muki2==3)if(enemyhantei[y/32-2][x/32]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;}
        if(muki==2){//下向きなら
               if(muki2==0)if(enemyhantei[y/32+2][x/32]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
               if(muki2==1)if(enemyhantei[y/32+1][x/32+1]==1)
				       return 1;
			   if(muki2==3)if(enemyhantei[y/32+1][x/32-1]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;}
        if(muki==3){//右向きなら
              if(muki2==0&&enemyhantei[y/32+1][x/32+1]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1;
              if(muki2==1&&enemyhantei[y/32][x/32+2]==1)
				       return 1;
			   if(muki2==2&&enemyhantei[y/32-1][x/32+1]==1)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
                        return 1; }
					return 0;
       
}
int Chdistance(int x,int y,int x2,int y2){
 
if((y-y2)*(y-y2)+(x-x2)*(x-x2)<32*32)
          return 1;
 
        return 0;//正常
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        
    int image[16],i,j=0;
    char Key[256];
int attacknumber,tenmetumode=0,attackmode=0,tenmetucounter=0,zoukaryou=0,enezoukaryou=0,turn=1;
 int random[3],state=0;
 int msgnumber,walktmp=0;
 
    if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理
    int msgmode=0;char tmpmsg[80]="";
    ch.x    =320;
    ch.y    =160;
    ch.walking_flag=0;
    ch.muki=3;
 int scrmapX=32,scrmapY=32;
    SetDrawScreen( DX_SCREEN_BACK ) ;                                                 //描画先を裏画面に設定
    LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存
 for(int i = 0 ; i < 50 ; i ++ )
enemyhantei[enemy[i].y/32][enemy[i].x/32]=1;
    while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
            //↑メッセージ処理        ↑画面をクリア         ↑キーボード入力状態取得       ↑ESCが押されると終了
 
                
        
        if(ch.x%32==0 && ch.y%32==0){         //座標が32で割り切れたら入力可能
            ch.walking_flag=1;         //歩くフラグを立てる。
            if     ( Key[ KEY_INPUT_UP   ]  == 1 )  //上ボタンが押されたら
                    ch.muki=0;         //上向きフラグを立てる
            else if( Key[ KEY_INPUT_LEFT ]  == 1 )  //左ボタンが押されたら
                    ch.muki=1;         //左向きフラグを立てる
            else if( Key[ KEY_INPUT_DOWN ]  == 1 )  //下ボタンが押されたら
                    ch.muki=2;         //下向きフラグを立てる
            else if( Key[ KEY_INPUT_RIGHT]  == 1 )  //右ボタンが押されたら
                    ch.muki=3;         //右向きフラグを立てる
            else                                    //何のボタンも押されてなかったら
                    ch.walking_flag=0; //歩かないフラグを立てる
            if(ch.walking_flag==1)    //もし歩くなら
                if(IsAbleToGo(ch.x,ch.y,ch.muki)==1)//行き先が歩けないなら
                    ch.walking_flag=0;                  //歩かないフラグを立てる。
        }
 
        for(int i = 0 ; i < 50 ; i ++ )
        { if(Chcolision(enemy[i].x,enemy[i].y,ch.muki)==1)//行き先が歩けないなら(このマップは0が壁で1が通路であるから注意)
           if(ch.x%32==0 && ch.y%32==0)ch.walking_flag=0;
        }
 
       if(ch.walking_flag==1){        //歩くフラグが立っていたら
            if     (ch.muki==0){       //上向きならch.y座標を減らす
                    ch.y -=4;scrmapY +=4;zoukaryou +=4;}
            else if(ch.muki==1){        //左向きならch.x座標を減らす
                    ch.x -=4;scrmapX +=4;zoukaryou +=4;}
            else if(ch.muki==2){       //下向きならch.y座標を増やす
                    ch.y +=4;scrmapY -=4;zoukaryou +=4;}
            else if(ch.muki==3){         //右向きならch.x座標を増やす
                    ch.x +=4;scrmapX -=4;zoukaryou +=4;}
        }
 
 

if(zoukaryou!=0 ){
    turn=0;
zoukaryou=0;}
for(int i = 0 ; i < 50 ; i ++ )
if(enemy[i].zoukaryou==32){turn=1;enemy[i].zoukaryou=0;
if(enemy[i].muki==0){enemyhantei[enemy[i].y/32+1][enemy[i].x/32]=0;enemyhantei[enemy[i].y/32][enemy[i].x/32]=1;}
if(enemy[i].muki==1){enemyhantei[enemy[i].y/32][enemy[i].x/32+1]=0;enemyhantei[enemy[i].y/32][enemy[i].x/32]=1;}
if(enemy[i].muki==2){enemyhantei[enemy[i].y/32-1][enemy[i].x/32]=0;enemyhantei[enemy[i].y/32][enemy[i].x/32]=1;}
if(enemy[i].muki==3){enemyhantei[enemy[i].y/32][enemy[i].x/32-1]=0;enemyhantei[enemy[i].y/32][enemy[i].x/32]=1;}
}

 
 
        //敵同士の衝突判定。敵同士の仮想グリップ上の座標で一歩先に敵いるか調べる。xyが32で割り切れる座標で一瞬だけ評価するからけっこうザル
    for(int i = 0 ; i < 50 ; i ++ )
for(int j = 0 ; j < 50 ; j ++ )if(turn==0)if(enemy[i].flag==1)
if(enemy[i].x%32==0 && enemy[i].y%32==0 )//↓行き先に主人公orカベor敵があれば
if(IsAbleToGo(enemy[i].x,enemy[i].y,enemy[i].muki)==2||IsAbleToGo(enemy[i].x,enemy[i].y,enemy[i].muki)==1||EnetoEnecolision(enemy[i].x,enemy[i].y,enemy[j].x,enemy[j].y,enemy[i].muki)==1||preEnetoEnecolision(enemy[i].x,enemy[i].y,enemy[j].x,enemy[j].y,enemy[i].muki,enemy[j].muki)==1)
        for(int r=0;r<=3;r++)//行き先が壁もしくは主人公がいない方向探す
            if(IsAbleToGo(enemy[i].x,enemy[i].y,r)==0)
                if(EnetoEnecolision(enemy[i].x,enemy[i].y,enemy[j].x,enemy[j].y,r)==0)
                        if(preEnetoEnecolision(enemy[i].x,enemy[i].y,enemy[j].x,enemy[j].y,r,enemy[j].muki)==0){random[r]=r;enemy[i].muki= GetRand(random[r]);}
 
//敵Aと敵Bの行く予定のマスがダブったら     
 
 
 
for(int i = 0 ; i < 50 ; i ++ )
        {if(turn==0)if(enemy[i].flag==1)
        if( enemy[i].walking_flag==1) 
                 if(enemy[i].muki==0){ 
                  enemy[i].y -=4;enemy[i].zoukaryou +=4;}
            else if(enemy[i].muki==1){        //左向きならch.x座標を減らす
                    enemy[i].x -=4;enemy[i].zoukaryou +=4;}
            else if(enemy[i].muki==2){        //下向きならch.y座標を増やす
                    enemy[i].y +=4;enemy[i].zoukaryou +=4;}
            else if(enemy[i].muki==3){        //右向きならch.x座標を増やす
                    enemy[i].x +=4;enemy[i].zoukaryou +=4;}
}
 
 
        ch.img=image[(ch.x%32+ch.y%32)/8 + ch.muki*4];            //画像をセット
        
        for(int i = 0 ; i < 50 ; i ++ )
        {
        enemy[i].img=image[(enemy[i].x%32+enemy[i].y%32)/8 + enemy[i].muki*4];            //画像をセット
    }
   
 
        for(int i = 0 ; i < 50 ; i ++ )
        { if(Chcolision(enemy[i].x,enemy[i].y,ch.muki)==1)//行き先が歩けないなら(このマップは0が壁で1が通路であるから注意)
           if(ch.x%32==0 && ch.y%32==0)ch.walking_flag=0;
        }
 
        for( i = 0 ; i < 50 ; i ++ ){  //メッセージ処理   
     if(Chcolision(enemy[i].x,enemy[i].y,ch.muki)==1)
        if( Key[ KEY_INPUT_RETURN    ]  == 1)enemy[i].msgflag=1;msgmode=1;
}  
   if(msgmode==1){
        for( i = 0 ; i < 50 ; i ++ ){  //メッセージ処理   
   if(enemy[i].msgflag==1)                // 配列の終端-2以下で、今回コピーするiまでの配列要素のi番目が\0じゃなくカウンターが5の倍数なら
                if(j<=80-2 && enemy[i].msg[j]!='\0'){
                        j+=2;                    // 全角文字なので配列要素2つずつカウントアップ
                        strncpy(tmpmsg,enemy[i].msg,j);// iバイトまでの配列要素をdisp配列にコピー
                        tmpmsg[j]='\0';            // 終端記号を代入
  }
    DrawFormatString(10,20,GetColor(255,25,255),"%s",tmpmsg);//disp配列の文字データを表示
 
}
 }               /*白い壁を描画*/
                for(i=0;i<15;i++)
                        for(j=0;j<34;j++)
                                if(hantei[i][j]==1)
                                        DrawBox(j*32+scrmapX,i*32+scrmapY,(j-1)*32+scrmapX,(i-1)*32+scrmapY,GetColor(255,255,255),TRUE);
 
        DrawGraph( 320 , 160 , ch.img , TRUE ) ;//画像を描画
        for( i = 0 ; i < 50 ; i ++ ){  //なぜか一個ずれてたんで-32   
            DrawGraph( enemy[i].x-32 + scrmapX, enemy[i].y-32 + scrmapY   , enemy[i].img , TRUE ) ;
}  
        DrawFormatString( 0, 80, GetColor(0,0,255), "ch.x%d",ch.x);
        DrawFormatString( 0, 100, GetColor(0,0,255), "ch.y%d",ch.y); 
 
        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}


ISLe
記事: 2648
登録日時: 9年前
連絡を取る:

Re: 敵の衝突判定について

#7

投稿記事 by ISLe » 7年前

せっかく書いたのでこちらで改造したコードもあげておきます。
#エラーチェックが甘いです。

改造は移動周りだけに抑えました。
やりたいことは想像できるのですが、謎の多いコードなので仕様レベルで整理することをお勧めします。

ピクセル座標とブロック座標でズレるのは、テーブルにブロック単位ではない座標が混じっているからかと。
こちらのコードは正規化しないとバグります。

コード:

#include "DxLib.h"

typedef struct {
	int x,y,img,muki,walking_flag;
} ch_t;
ch_t ch;

typedef struct {
	int x,y,life,counter,img,walkimg,faceimg,muki,kasoumuki,speed,walking_flag,flag,msgflag,hanninflag,tenmetuflag,zoukaryou;
	char msg[120];
} enemy_t; //敵の初期位置xyは32で割り切れる数でなければならない。でないと壁抜けしたり向きがおかしくなる
//32の倍数 32,64,96,128,160,192,224,256,288,320,352,384,416,448,480,512,544,576,608,640,672
//waikimgは敵の歩く画像をloaddivgraphでenemygazou[128]に4×4個を128個読み込んでるので4×4の塊の左上の最初の数。図に書くとわかりやすい
//0→1番目のキャラの塊の最初の画像,4→2番目,8→3番目,12→4番目,64→5番目,68→6番目,72→7番目,76→8番目
enemy_t enemy[50] = {
	{ 320,160,3,7,2,0,1,1,0,2,1,1,0,0,0,0,"大事なものは体に身につけるようにしよう。"},
	{ 288,128,4,7,2,4,1,1,0,2,1,1,0,0,0,0,"あなた井の中の蛙ね"},
	{ 256,96,5,7,2,8,2,2,0,2,1,1,0,0,0,0,"なに?ーー。やべえな。"},
	{ 224,224,6,7,2,12,3,2,0,2,1,1,0,0,0,0,"ちっぱお"},
	{ 630,96,3,7,2,64,4,2,0,2,1,1,0,0,0,0,"大久保"},
	{ 662,96,7,3,2,68,5,0,0,2,1,1,0,0,0,0,"ダンクーダ"},
	{ 288,160,4,3,2,72,6,3,0,2,1,1,0,0,0,0,"レンジで5分"},
	{ 288,192,5,3,2,76,7,0,0,2,1,1,0,0,0,0,"おちっこ漏れちゃうー"},
	{ 320,224,7,3,2,0,7,2,0,2,1 ,1,0,0,0,0,"知ってるかい?一番右のやつ盗撮が趣味なんだって"},
	{ 320,256,7,3,2,4,1,2,0,2,1 ,1,0,0,0,0,"この中に殺人鬼がいるらしい"},
	{ 320,288,3,8,2,8,2,2,0,2,1 ,1,0,0,0,0,"どうしようお金すられたわ。犯人捜して頂戴"},
	{ 320,320,3,9,2,12,3,2,0,2,1 ,1,0,0,0,0,"この中。"},
	{ 352,224,3,10,2,64,4,2,0,2,1,1,0,0,0,0,"さ"},
	{ 352,256,3,7,2,68,5,2,0,2,0 ,1,0,0,0,0,""},
	{ 352,288,3,7,2,72,6,2,0,2,0 ,1,0,0,0,0,"ああああああーーーさっき株が暴落して1億吹っ飛んだーー会社の金なのにどうしよう。ねえ誰か1億ちょうだい?"},
	{ 352,320,3,7,2,76,2,1,0,2,0 ,1,0,0,0,0,"こんなに人と肩ぶつかりまくるわ"},
	{ 352,352,3,7,2,0,7,2,0,2,0 ,1,0,0,0,0,"さっきどさくさに紛れて痴漢した奴がいるわ"},
	{ 352,384,7,3,2,4,0,3,0,2,0,1,0,0,0,0,"おっす。"},
	{ 352,416,7,3,2,8,2,2,0,3,0 ,1,0,1,0,0,"僕だ"},
	{ 384,132,3,7,2,12,2,0,0,2,1 ,1,0,0,0,0,"うん"},
	{ 384,224,3,7,2,64,0,0,0,2,1 ,1,0,0,0,0,"はやく来てくれーーーーー"},
	{ 384,256,3,7,2,68,0,0,0,2,1 ,1,0,0,0,0,"めがね落とした。"},
	{ 384,288,3,7,2,72,0,0,0,2,1 ,1,0,0,0,0,"なに?痴漢を探してるって?そいつなら知ってるぞ。確か口癖が「らんらんるー」だったかな"},
	{ 384,320,3,7,2,78,0,0,0,2,1 ,1,0,0,0,0,"つぼみ"},
	{ 416,256,7,3,2,4,1,2,0,2,1 ,1,0,0,0,0,"この中に殺人鬼がいるらしい"},
	{ 416,288,3,8,2,8,2,2,0,2,1 ,1,0,0,0,0,"どうしようお金すられたわ。犯人捜して頂戴"},
	{ 416,320,3,9,2,12,3,2,0,2,1 ,1,0,0,0,0,"この中に。早く探して寝取らないと先を越されちゃう"},
	{ 448,224,3,10,2,64,4,2,0,2,1,1,0,0,0,0,"さっき"},
	{ 448,256,3,7,2,68,5,2,0,2,0 ,1,0,0,0,0,""},
	{ 448,288,3,7,2,72,6,2,0,2,0 ,1,0,0,0,0,"ああああああーーーさっき株が暴落して1億吹っ飛んだーー会社の金なのにどうしよう。ねえ誰か1億ちょうだい?"},
	{ 448,320,3,7,2,76,2,1,0,2,0 ,1,0,0,0,0,"こんなに人と肩ぶつかりまくるわ。"},
	{ 448,352,3,7,2,0,7,2,0,2,0 ,1,0,0,0,0,"さっきどさくさに紛れて痴漢した奴がいるわ"},
	{ 448,384,7,3,2,4,0,3,0,2,0,1,0,0,0,0,"おっす。オラ悟空"},
	{ 448,416,7,3,2,8,2,2,0,3,0 ,1,0,1,0,0,"僕はね、"},
	{ 480,132,3,7,2,12,2,0,0,2,1 ,1,0,0,0,0,""},
	{ 480,224,3,7,2,64,0,0,0,2,1 ,1,0,0,0,0,"はやく来てくれーーーーー"},
	{ 480,256,3,7,2,68,0,0,0,2,1 ,1,0,0,0,0,"めがね落とした。ねがめねがめ"},
	{ 480,288,3,7,2,72,0,0,0,2,1 ,1,0,0,0,0,"「らんらんるー」"},
	{ 480,320,3,7,2,78,0,0,0,2,1 ,1,0,0,0,0,"つぼみ"},
};

int hantei[15][34] = {
	{ 1,1,1,1,1,1,1,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 },
	{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0 },
	{ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0 },
	{ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0 },
	{ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,1,1,1,0,0,0 },
	{ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0 },
	{ 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0 },
	{ 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 },
	{ 1,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0 },
	{ 1,1,1,1,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,1,1 },
	{ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1 },
	{ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,1,1,1,1 },
	{ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0 },
	{ 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 },
	{ 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 },
};
/*
 * ブロック単位で現在位置のインデックスを求める
 */
int GetCurPosIndex(int x,int y,int dir) {
	switch (dir) {
	case 0: // 上向き
	case 1: // 左向き
		return (y/32)*34+(x/32);
	case 2: // 下向き
	case 3: // 右向き
		return ((y+32-1)/32)*34+((x+32-1)/32);
	}
	return -1; // 向きエラー
}
/*
 * キャラクターの存在位置にフラグを付ける
 */
void MarkCurPos(int x,int y,int dir) {
	int idx = GetCurPosIndex(x, y, dir);
	hantei[0][idx] |= (1 << 16);
}
/*
 * キャラクターの存在位置のフラグを外す
 */
void UnmarkCurPos(int x,int y,int dir) {
	int idx = GetCurPosIndex(x, y, dir);
	hantei[0][idx] &= ~(1 << 16);
}

int IsAbleToGo(int x,int y,int muki) { //進めるかを判定する

	if(muki==0) { //上向きなら
		if(hantei[y/32-1][x/32]!=0)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
			return 1;
	}
	if(muki==1) { //左向きなら
		if(hantei[y/32][x/32-1]!=0)
			return 1;
	}
	if(muki==2) { //下向きなら
		if(hantei[y/32+1][x/32]!=0)
			return 1;
	}
	if(muki==3) { //右向きなら
		if(hantei[y/32][x/32+1]!=0)
			return 1;
	}
	return 0;//正常
}

int Chcolision(int x,int y,int muki) {
	int kiriageX = (int)(x + 0.9);
	int kiriageY = (int)(y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする.マス移動中は少数になるため切り上げて次のマスに行ったことにする
	int kiriageChX = (int)(ch.x + 0.9);
	int kiriagechY = (int)(ch.y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする

	if(muki==0)//上向きなら
		if(kiriageY/32==kiriagechY/32-1&&kiriageX/32==kiriageChX/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
			return 1;
	if(muki==1)//左向きなら
		if(kiriageY/32==kiriagechY/32&&kiriageX/32==kiriageChX/32-1)
			return 1;
	if(muki==2)//下向きなら
		if(kiriageY/32==kiriagechY/32+1&&kiriageX/32==kiriageChX/32)
			return 1;
	if(muki==3)//右向きなら
		if(kiriageY/32==kiriagechY/32&&kiriageX/32==kiriageChX/32+1)
			return 1;
	return 0;//正常
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ) {

	int image[16],i,j=0;
	char Key[256];
	int attacknumber,tenmetumode=0,attackmode=0,tenmetucounter=0,enezoukaryou=0,turn;
	int random[3],state=0;
	int msgnumber,walktmp=0;

	if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理
	int msgmode=0;
	char tmpmsg[80]="";
	ch.x    =320;
	ch.y    =160;
	ch.walking_flag=0;
	ch.muki=3;
	int scrmapX=32,scrmapY=32;
	SetDrawScreen( DX_SCREEN_BACK ) ;                                                 //描画先を裏画面に設定
	LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存

	/*
	 * 事前にキャラクターの存在位置をマーク
	 */
	MarkCurPos(ch.x, ch.y, ch.muki);
	for (i=0; i<50; i++) {
		if (enemy[i].flag == 1) {
			{
				// ついでに敵の座標を正規化
				enemy[i].x = enemy[i].x / 32 * 32;
				enemy[i].y = enemy[i].y / 32 * 32;
			}
			MarkCurPos(enemy[i].x, enemy[i].y, enemy[i].muki);
		}
	}

	while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]) {
		//↑メッセージ処理        ↑画面をクリア         ↑キーボード入力状態取得       ↑ESCが押されると終了

		turn = 0;
		if(ch.x%32==0 && ch.y%32==0) {        //座標が32で割り切れたら入力可能

			if (ch.walking_flag) turn=1; // 歩いていた主人公が止まったら敵のターン

			ch.walking_flag=1;         //歩くフラグを立てる。
			if     ( Key[ KEY_INPUT_UP   ]  == 1 )  //上ボタンが押されたら
				ch.muki=0;         //上向きフラグを立てる
			else if( Key[ KEY_INPUT_LEFT ]  == 1 )  //左ボタンが押されたら
				ch.muki=1;         //左向きフラグを立てる
			else if( Key[ KEY_INPUT_DOWN ]  == 1 )  //下ボタンが押されたら
				ch.muki=2;         //下向きフラグを立てる
			else if( Key[ KEY_INPUT_RIGHT]  == 1 )  //右ボタンが押されたら
				ch.muki=3;         //右向きフラグを立てる
			else                                    //何のボタンも押されてなかったら
				ch.walking_flag=0; //歩かないフラグを立てる
			if(ch.walking_flag==1)    //もし歩くなら
				if(IsAbleToGo(ch.x,ch.y,ch.muki)==1)//行き先が歩けないなら
					ch.walking_flag=0;                  //歩かないフラグを立てる。
		}
		if(ch.walking_flag==1) {       //歩くフラグが立っていたら
			UnmarkCurPos(ch.x, ch.y, ch.muki);
			if     (ch.muki==0) {      //上向きならch.y座標を減らす
				ch.y -=4;
				scrmapY +=4;
			}
			else if(ch.muki==1) {       //左向きならch.x座標を減らす
				ch.x -=4;
				scrmapX +=4;
			}
			else if(ch.muki==2) {      //下向きならch.y座標を増やす
				ch.y +=4;
				scrmapY -=4;
			}
			else if(ch.muki==3) {        //右向きならch.x座標を増やす
				ch.x +=4;
				scrmapX -=4;
			}
			MarkCurPos(ch.x, ch.y, ch.muki);
		}

		/*
		 * 敵の移動
		 */
		for( i = 0 ; i < 50 ; i ++ ) {
			if(enemy[i].flag==1) {

				if(enemy[i].x%32==0 && enemy[i].y%32==0 ) {
					enemy[i].walking_flag = 0; // ブロック単位で停止
					if (turn) {
						// ターンが来ると停止している敵が動き出す
						enemy[i].walking_flag = 1;
						if(IsAbleToGo(enemy[i].x,enemy[i].y,enemy[i].muki)==1) {
							enemy[i].walking_flag = 0;
							int r, rc = 0;
							for(r=0; r<4; r++) { // 空いている方向を探す
								if(IsAbleToGo(enemy[i].x,enemy[i].y,r)==0) {
									random[rc] = r;
									rc ++;
								}
							}
							if (rc > 0) { // 空いている方向がある
								rc = GetRand(rc - 1); // ランダムに選択
								enemy[i].muki= random[rc];
								enemy[i].walking_flag = 1;
							}
						}
					}
				}

				if( enemy[i].walking_flag==1) {
					UnmarkCurPos(enemy[i].x, enemy[i].y, enemy[i].muki);
					if(enemy[i].muki==0) {
						enemy[i].y -=4;
					}
					else if(enemy[i].muki==1) {       //左向きならch.x座標を減らす
						enemy[i].x -=4;
					}
					else if(enemy[i].muki==2) {       //下向きならch.y座標を増やす
						enemy[i].y +=4;
					}
					else if(enemy[i].muki==3) {       //右向きならch.x座標を増やす
						enemy[i].x +=4;
					}
					MarkCurPos(enemy[i].x, enemy[i].y, enemy[i].muki);
				}
			}
		}

		ch.img=image[(ch.x%32+ch.y%32)/8 + ch.muki*4];            //画像をセット

		for( i = 0 ; i < 50 ; i ++ )
		{
			enemy[i].img=image[(enemy[i].x%32+enemy[i].y%32)/8 + enemy[i].muki*4];            //画像をセット
		}

		for( i = 0 ; i < 50 ; i ++ ) { //メッセージ処理
			if(Chcolision(enemy[i].x,enemy[i].y,ch.muki)==1)
				if( Key[ KEY_INPUT_RETURN    ]  == 1)enemy[i].msgflag=1;
			msgmode=1;
		}
		if(msgmode==1) {
			for( i = 0 ; i < 50 ; i ++ ) { //メッセージ処理
				if(enemy[i].msgflag==1)                // 配列の終端-2以下で、今回コピーするiまでの配列要素のi番目が\0じゃなくカウンターが5の倍数なら
					if(j<=80-2 && enemy[i].msg[j]!='\0') {
						j+=2;                    // 全角文字なので配列要素2つずつカウントアップ
						strncpy(tmpmsg,enemy[i].msg,j);// iバイトまでの配列要素をdisp配列にコピー
						tmpmsg[j]='\0';            // 終端記号を代入
					}
				DrawFormatString(10,20,GetColor(255,25,255),"%s",tmpmsg);//disp配列の文字データを表示

			}
		}               /*白い壁を描画*/
		for(i=0; i<15; i++)
			for(j=0; j<34; j++)
				if((hantei[i][j]&0xffff)==1)
					DrawBox(j*32+scrmapX,i*32+scrmapY,(j-1)*32+scrmapX,(i-1)*32+scrmapY,GetColor(255,255,255),TRUE);

		DrawGraph( 320 , 160 , ch.img , TRUE ) ;//画像を描画
		for( i = 0 ; i < 50 ; i ++ ) { //なぜか一個ずれてたんで-32
			DrawGraph( enemy[i].x-32 + scrmapX, enemy[i].y-32 + scrmapY   , enemy[i].img , TRUE ) ;
		}
		DrawFormatString( 0, 80, GetColor(0,0,255), "ch.x%d",ch.x);
		DrawFormatString( 0, 100, GetColor(0,0,255), "ch.y%d",ch.y);

		ScreenFlip();
	}

	DxLib_End();
	return 0;
}

yaegasi

Re: 敵の衝突判定について

#8

投稿記事 by yaegasi » 7年前

ついでに風来のシレン風味にしときました↓

コード:

#include "DxLib.h"
 
typedef struct {
    int x,y,img,muki,walking_flag;
} ch_t;
ch_t ch;
 
typedef struct {
    int x,y,life,counter,img,walkimg,faceimg,muki,kasoumuki,speed,walking_flag,flag,msgflag,hanninflag,tenmetuflag,zoukaryou;
    char msg[120];
} enemy_t; //敵の初期位置xyは32で割り切れる数でなければならない。でないと壁抜けしたり向きがおかしくなる
//32の倍数 32,64,96,128,160,192,224,256,288,320,352,384,416,448,480,512,544,576,608,640,672
//waikimgは敵の歩く画像をloaddivgraphでenemygazou[128]に4×4個を128個読み込んでるので4×4の塊の左上の最初の数。図に書くとわかりやすい
//0→1番目のキャラの塊の最初の画像,4→2番目,8→3番目,12→4番目,64→5番目,68→6番目,72→7番目,76→8番目
enemy_t enemy[50] = {
    { 320,160,3,7,2,0,1,1,0,2,1,1,0,0,0,0,"大事なものは体に身につけるようにしよう。"},
    { 288,128,4,7,2,4,1,1,0,2,1,1,0,0,0,0,"あなた井の中の蛙ね"},
    { 256,96,5,7,2,8,2,2,0,2,1,1,0,0,0,0,"なに?ーー。やべえな。"},
    { 224,224,6,7,2,12,3,2,0,2,1,1,0,0,0,0,"ちっぱお"},
    { 630,96,3,7,2,64,4,2,0,2,1,1,0,0,0,0,"大久保"},
    { 662,96,7,3,2,68,5,0,0,2,1,1,0,0,0,0,"ダンクーダ"},
    { 288,160,4,3,2,72,6,3,0,2,1,1,0,0,0,0,"レンジで5分"},
    { 288,192,5,3,2,76,7,0,0,2,1,1,0,0,0,0,"おちっこ漏れちゃうー"},
    { 320,224,7,3,2,0,7,2,0,2,1 ,1,0,0,0,0,"知ってるかい?一番右のやつ盗撮が趣味なんだって"},
    { 320,256,7,3,2,4,1,2,0,2,1 ,1,0,0,0,0,"この中に殺人鬼がいるらしい"},
    { 320,288,3,8,2,8,2,2,0,2,1 ,1,0,0,0,0,"どうしようお金すられたわ。犯人捜して頂戴"},
    { 320,320,3,9,2,12,3,2,0,2,1 ,1,0,0,0,0,"この中。"},
    { 352,224,3,10,2,64,4,2,0,2,1,1,0,0,0,0,"さ"},
    { 352,256,3,7,2,68,5,2,0,2,0 ,1,0,0,0,0,""},
    { 352,288,3,7,2,72,6,2,0,2,0 ,1,0,0,0,0,"ああああああーーーさっき株が暴落して1億吹っ飛んだーー会社の金なのにどうしよう。ねえ誰か1億ちょうだい?"},
    { 352,320,3,7,2,76,2,1,0,2,0 ,1,0,0,0,0,"こんなに人と肩ぶつかりまくるわ"},
    { 352,352,3,7,2,0,7,2,0,2,0 ,1,0,0,0,0,"さっきどさくさに紛れて痴漢した奴がいるわ"},
    { 352,384,7,3,2,4,0,3,0,2,0,1,0,0,0,0,"おっす。"},
    { 352,416,7,3,2,8,2,2,0,3,0 ,1,0,1,0,0,"僕だ"},
    { 384,132,3,7,2,12,2,0,0,2,1 ,1,0,0,0,0,"うん"},
    { 384,224,3,7,2,64,0,0,0,2,1 ,1,0,0,0,0,"はやく来てくれーーーーー"},
    { 384,256,3,7,2,68,0,0,0,2,1 ,1,0,0,0,0,"めがね落とした。"},
    { 384,288,3,7,2,72,0,0,0,2,1 ,1,0,0,0,0,"なに?痴漢を探してるって?そいつなら知ってるぞ。確か口癖が「らんらんるー」だったかな"},
    { 384,320,3,7,2,78,0,0,0,2,1 ,1,0,0,0,0,"つぼみ"},
    { 416,256,7,3,2,4,1,2,0,2,1 ,1,0,0,0,0,"この中に殺人鬼がいるらしい"},
    { 416,288,3,8,2,8,2,2,0,2,1 ,1,0,0,0,0,"どうしようお金すられたわ。犯人捜して頂戴"},
    { 416,320,3,9,2,12,3,2,0,2,1 ,1,0,0,0,0,"この中に。早く探して寝取らないと先を越されちゃう"},
    { 448,224,3,10,2,64,4,2,0,2,1,1,0,0,0,0,"さっき"},
    { 448,256,3,7,2,68,5,2,0,2,0 ,1,0,0,0,0,""},
    { 448,288,3,7,2,72,6,2,0,2,0 ,1,0,0,0,0,"ああああああーーーさっき株が暴落して1億吹っ飛んだーー会社の金なのにどうしよう。ねえ誰か1億ちょうだい?"},
    { 448,320,3,7,2,76,2,1,0,2,0 ,1,0,0,0,0,"こんなに人と肩ぶつかりまくるわ。"},
    { 448,352,3,7,2,0,7,2,0,2,0 ,1,0,0,0,0,"さっきどさくさに紛れて痴漢した奴がいるわ"},

};
 
int hantei[15][34] = {
    { 1,1,1,1,1,1,1,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 },
    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0 },
    { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0 },
    { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0 },
    { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,1,1,1,0,0,0 },
    { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0 },
    { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0 },
    { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 },
    { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0 },
    { 1,1,1,1,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,1,1 },
    { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1 },
    { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,1,1,1,1 },
    { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0 },
    { 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 },
    { 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 },
};
/*
 * ブロック単位で現在位置のインデックスを求める
 */
int GetCurPosIndex(int x,int y,int dir) {
    switch (dir) {
    case 0: // 上向き
    case 1: // 左向き
        return (y/32)*34+(x/32);
    case 2: // 下向き
    case 3: // 右向き
        return ((y+32-1)/32)*34+((x+32-1)/32);
    }
    return -1; // 向きエラー
}
/*
 * キャラクターの存在位置にフラグを付ける
 */
void MarkCurPos(int x,int y,int dir) {
    int idx = GetCurPosIndex(x, y, dir);
    hantei[0][idx] |= (1 << 16);
}
/*
 * キャラクターの存在位置のフラグを外す
 */
void UnmarkCurPos(int x,int y,int dir) {
    int idx = GetCurPosIndex(x, y, dir);
    hantei[0][idx] &= ~(1 << 16);
}
 
int IsAbleToGo(int x,int y,int muki) { //進めるかを判定する
 
    if(muki==0) { //上向きなら
        if(hantei[y/32-1][x/32]!=0)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
            return 1;
    }
    if(muki==1) { //左向きなら
        if(hantei[y/32][x/32-1]!=0)
            return 1;
    }
    if(muki==2) { //下向きなら
        if(hantei[y/32+1][x/32]!=0)
            return 1;
    }
    if(muki==3) { //右向きなら
        if(hantei[y/32][x/32+1]!=0)
            return 1;
    }
    return 0;//正常
}
 
int Chcolision(int x,int y,int muki) {
    int kiriageX = (int)(x + 0.9);
    int kiriageY = (int)(y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする.マス移動中は少数になるため切り上げて次のマスに行ったことにする
    int kiriageChX = (int)(ch.x + 0.9);
    int kiriagechY = (int)(ch.y + 0.9);//小数点以下第1位で、0.1~0.9に対して繰り上げを行う。敵が次のマスへの移動中そのマスを自キャラいけなくする
 
    if(muki==0)//上向きなら
        if(kiriageY/32==kiriagechY/32-1&&kiriageX/32==kiriageChX/32)//進めるか判定。||より右は敵と自キャラのグリッド上の座標がダブったら
            return 1;
    if(muki==1)//左向きなら
        if(kiriageY/32==kiriagechY/32&&kiriageX/32==kiriageChX/32-1)
            return 1;
    if(muki==2)//下向きなら
        if(kiriageY/32==kiriagechY/32+1&&kiriageX/32==kiriageChX/32)
            return 1;
    if(muki==3)//右向きなら
        if(kiriageY/32==kiriagechY/32&&kiriageX/32==kiriageChX/32+1)
            return 1;
    return 0;//正常
}//敵の周り8マスから最も主人公と距離が近いマス探してその方向を返す
int MostNearDistance(int x,int y){
 int tempmin;
 int min[4];
 min[0]=(ch.y-y-32)*(ch.y-y-32)+(ch.x-x)*(ch.x-x);//敵の居るマスの上
 min[1]=(ch.y-y)*(ch.y-y)+(ch.x-x-32)*(ch.x-x-32);//左
 min[2]=(ch.y-y+32)*(ch.y-y+32)+(ch.x-x)*(ch.x-x);//下
 min[3]=(ch.y-y)*(ch.y-y)+(ch.x-x+32)*(ch.x-x+32);//右 これらの大小調べて一番小さいほうが主人公との最短距離
 
 tempmin=min[0];
 
 for(int i=0;i<=3;i++){
        /* 最大値求める */
        if(min[i]>tempmin)
        tempmin=min[i];
         } 
if(tempmin== min[0])	return 0;	
if(tempmin== min[1])	return 1;			
if(tempmin== min[2])	return 2;	
if(tempmin== min[3])	return 3; 
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ) {
 
    int image[16],i,j=0;
    char Key[256];
    int attacknumber,tenmetumode=0,attackmode=0,tenmetucounter=0,enezoukaryou=0,turn;
    int random[3],state=0;
    int msgnumber,walktmp=0;
 
    if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理
    int msgmode=0;
    char tmpmsg[80]="";
    ch.x    =320;
    ch.y    =160;
    ch.walking_flag=0;
    ch.muki=3;
    int scrmapX=32,scrmapY=32;
    SetDrawScreen( DX_SCREEN_BACK ) ;                                                 //描画先を裏画面に設定
    LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存
 
    /*
     * 事前にキャラクターの存在位置をマーク
     */
    MarkCurPos(ch.x, ch.y, ch.muki);
    for (i=0; i<50; i++) {
        if (enemy[i].flag == 1) {
            {
                // ついでに敵の座標を正規化
                enemy[i].x = enemy[i].x / 32 * 32;
                enemy[i].y = enemy[i].y / 32 * 32;
            }
            MarkCurPos(enemy[i].x, enemy[i].y, enemy[i].muki);
        }
    }
 
    while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]) {
        //↑メッセージ処理        ↑画面をクリア         ↑キーボード入力状態取得       ↑ESCが押されると終了
 
        turn = 0;
        if(ch.x%32==0 && ch.y%32==0) {        //座標が32で割り切れたら入力可能
 
            if (ch.walking_flag) turn=1; // 歩いていた主人公が止まったら敵のターン
 
            ch.walking_flag=1;         //歩くフラグを立てる。
            if     ( Key[ KEY_INPUT_UP   ]  == 1 )  //上ボタンが押されたら
                ch.muki=0;         //上向きフラグを立てる
            else if( Key[ KEY_INPUT_LEFT ]  == 1 )  //左ボタンが押されたら
                ch.muki=1;         //左向きフラグを立てる
            else if( Key[ KEY_INPUT_DOWN ]  == 1 )  //下ボタンが押されたら
                ch.muki=2;         //下向きフラグを立てる
            else if( Key[ KEY_INPUT_RIGHT]  == 1 )  //右ボタンが押されたら
                ch.muki=3;         //右向きフラグを立てる
            else                                    //何のボタンも押されてなかったら
                ch.walking_flag=0; //歩かないフラグを立てる
            if(ch.walking_flag==1)    //もし歩くなら
                if(IsAbleToGo(ch.x,ch.y,ch.muki)==1)//行き先が歩けないなら
                    ch.walking_flag=0;                  //歩かないフラグを立てる。
        }
        if(ch.walking_flag==1) {       //歩くフラグが立っていたら
            UnmarkCurPos(ch.x, ch.y, ch.muki);
            if     (ch.muki==0) {      //上向きならch.y座標を減らす
                ch.y -=4;
                scrmapY +=4;
            }
            else if(ch.muki==1) {       //左向きならch.x座標を減らす
                ch.x -=4;
                scrmapX +=4;
            }
            else if(ch.muki==2) {      //下向きならch.y座標を増やす
                ch.y +=4;
                scrmapY -=4;
            }
            else if(ch.muki==3) {        //右向きならch.x座標を増やす
                ch.x +=4;
                scrmapX -=4;
            }
            MarkCurPos(ch.x, ch.y, ch.muki);
        }
 
        /*
         * 敵の移動
         */
        for( i = 0 ; i < 50 ; i ++ ) {
            if(enemy[i].flag==1) {
 
                if(enemy[i].x%32==0 && enemy[i].y%32==0 ) {
                    enemy[i].walking_flag = 0; // ブロック単位で停止
                    if (turn) {
                        // ターンが来ると停止している敵が動き出す
                        enemy[i].walking_flag = 1;
                        if(IsAbleToGo(enemy[i].x,enemy[i].y,enemy[i].muki)==1) {
                            enemy[i].walking_flag = 0;}
                            int r, rc = 0;
                            for(r=0; r<4; r++) { // 空いている方向を探す
                                if(IsAbleToGo(enemy[i].x,enemy[i].y,r)==0) {
                                    if(r==MostNearDistance(enemy[i].x,enemy[i].y)){random[rc] = r;
                                    rc ++;
                                }}
                            
                            if (rc > 0) { // 空いている方向がある
                                rc = GetRand(rc - 1); // ランダムに選択
                                enemy[i].muki= random[rc];
                                enemy[i].walking_flag = 1;
                            }
                        }
                    }
                }
 
                if( enemy[i].walking_flag==1) {
                    UnmarkCurPos(enemy[i].x, enemy[i].y, enemy[i].muki);
                    if(enemy[i].muki==0) {
                        enemy[i].y -=4;
                    }
                    else if(enemy[i].muki==1) {       //左向きならch.x座標を減らす
                        enemy[i].x -=4;
                    }
                    else if(enemy[i].muki==2) {       //下向きならch.y座標を増やす
                        enemy[i].y +=4;
                    }
                    else if(enemy[i].muki==3) {       //右向きならch.x座標を増やす
                        enemy[i].x +=4;
                    }
                    MarkCurPos(enemy[i].x, enemy[i].y, enemy[i].muki);
                }
            }
        }
 
        ch.img=image[(ch.x%32+ch.y%32)/8 + ch.muki*4];            //画像をセット
 
        for( i = 0 ; i < 50 ; i ++ )
        {
            enemy[i].img=image[(enemy[i].x%32+enemy[i].y%32)/8 + enemy[i].muki*4];            //画像をセット
        }
 
        for( i = 0 ; i < 50 ; i ++ ) { //メッセージ処理
            if(Chcolision(enemy[i].x,enemy[i].y,ch.muki)==1)
                if( Key[ KEY_INPUT_RETURN    ]  == 1)enemy[i].msgflag=1;
            msgmode=1;
        }
        if(msgmode==1) {
            for( i = 0 ; i < 50 ; i ++ ) { //メッセージ処理
                if(enemy[i].msgflag==1)                // 配列の終端-2以下で、今回コピーするiまでの配列要素のi番目が\0じゃなくカウンターが5の倍数なら
                    if(j<=80-2 && enemy[i].msg[j]!='\0') {
                        j+=2;                    // 全角文字なので配列要素2つずつカウントアップ
                        strncpy(tmpmsg,enemy[i].msg,j);// iバイトまでの配列要素をdisp配列にコピー
                        tmpmsg[j]='\0';            // 終端記号を代入
                    }
                DrawFormatString(10,20,GetColor(255,25,255),"%s",tmpmsg);//disp配列の文字データを表示
 
            }
        }               /*白い壁を描画*/
        for(i=0; i<15; i++)
            for(j=0; j<34; j++)
                if((hantei[i][j]&0xffff)==1)
                    DrawBox(j*32+scrmapX,i*32+scrmapY,(j-1)*32+scrmapX,(i-1)*32+scrmapY,GetColor(255,255,255),TRUE);
 
        DrawGraph( 320 , 160 , ch.img , TRUE ) ;//画像を描画
        for( i = 0 ; i < 50 ; i ++ ) { //なぜか一個ずれてたんで-32
            DrawGraph( enemy[i].x-32 + scrmapX, enemy[i].y-32 + scrmapY   , enemy[i].img , TRUE ) ;
        }
        DrawFormatString( 0, 80, GetColor(0,0,255), "ch.x%d",ch.x);
        DrawFormatString( 0, 100, GetColor(0,0,255), "ch.y%d",ch.y);
 
        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}

ISLe
記事: 2648
登録日時: 9年前
連絡を取る:

Re: 敵の衝突判定について

#9

投稿記事 by ISLe » 7年前

yaegasi さんが書きました:ついでに風来のシレン風味にしときました↓
風来のシレンだと、敵の移動は主人公が一マス移動した後じゃなくて、移動し始めるとき(見た目には同時)ですけど。

コードは他の部分ももっとシンプルにできるので挑戦してみてください。

yaegasi

Re: 敵の衝突判定について

#10

投稿記事 by yaegasi » 7年前

すいません。最後なんですが
ここの部分は何を意味してるのでしょうか↓配列の要素にフラグ?を付けるというのが
よく分かりません
あとhanteiの中身に65536という数字があるのですが何か意味がある数字なのでしょうか
int GetCurPosIndex(int x,int y,int dir) {
switch (dir) {
case 0: // 上向き
case 1: // 左向き
return (y/32)*34+(x/32);
case 2: // 下向き
case 3: // 右向き
return ((y+32-1)/32)*34+((x+32-1)/32);
}
return -1; // 向きエラー
}
/*
* キャラクターの存在位置にフラグを付ける
*/
void MarkCurPos(int x,int y,int dir) {
int idx = GetCurPosIndex(x, y, dir);
hantei[0][idx] |= (1 << 16);
}
/*
* キャラクターの存在位置のフラグを外す
*/
void UnmarkCurPos(int x,int y,int dir) {
int idx = GetCurPosIndex(x, y, dir);
hantei[0][idx] &= ~(1 << 16);
}

ISLe
記事: 2648
登録日時: 9年前
連絡を取る:

Re: 敵の衝突判定について

#11

投稿記事 by ISLe » 7年前

GetCurPosIndex関数は先のコメントでリンクしたスレに説明があります。
ブロック単位からズレているときに移動先のブロック座標を求めます。

実際には座標ではなくて、配列のインデックスですが。
ゲームプログラムではマップは一次元配列のほうが何かと都合が良いので一次元配列としてアクセスしています。

MarkCurPos/UnmarkCurPos関数は、GetCurPosIndex関数で求めたインデックスの配列要素にフラグをセット/リセットします。
ビット演算で32ビットある整数値の第16ビットを操作します。
第16ビットが1の整数値は10進数で65536になります。

8ビットで0~255までの256通りを表せるので、ゲームプログラムでは、下位から、第0~7ビットを地形番号、第8~15ビットをイベント番号…というふうに情報をビット単位で詰め込んで使うことがよくあります。

yaegasi

Re: 敵の衝突判定について

#12

投稿記事 by yaegasi » 7年前

ビット演算ですか・・・
苦手な分野ですが解読してみます
一マス先に敵がいる場合は簡単に判定できるんですが
行く予定のマスが重なった場合、もう一個ループ回して
総当りでやるしかないと思ってたんですが(preEnetoEnecolision関数)簡単に判定できるんですね
解決しました。
ありがとうございました。

ISLe
記事: 2648
登録日時: 9年前
連絡を取る:

Re: 敵の衝突判定について

#13

投稿記事 by ISLe » 7年前

yaegasi さんが書きました:行く予定のマスが重なった場合、もう一個ループ回して
総当りでやるしかないと思ってたんですが(preEnetoEnecolision関数)簡単に判定できるんですね
わたしの書いたコードでは、ひとりずつ歩を進めるので、そもそも行く『予定』のマスというものがなく、重なることもありません。
次に行くマスが決まった時点で、そのマスに移動済みとして処理しています。
風来のシレンのように、敵が主人公の後ろをぴったり付いて行くには、移動元を空ける必要がありますし。

閉鎖

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