DXライブラリの初歩的な質問です

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

DXライブラリの初歩的な質問です

#1

投稿記事 by ba-yu » 8年前

Dxライブラリ初心者です

習うより慣れろだと思い
現在、ゲームプログラミングの館の
24. 行けない所を作る。~2D~
のサンプルを参考に
画面上をランダムに動くキャラクターを追加したのですが
敵とプレイヤーを同じ座標に存在させない処理が作れません。

またキャラクターの現在いる座標を壁と同じく白く描画するようにしたのですが、画像が左上から描画されるからなのか、キャラクターの座標と画像の動きに統一性がなく
移動先が上か左ならキャラクターの座標(白い壁)の移動のあとについていくようにキャラクターの画像が動き、
移動先が下か右ならキャラクターの画像にキャラクターの座標(白い壁)がついていく形になってしまいます(たぶん分かりづらくてすいません)
これをどちらかの形に統一できないでしょうか

知恵を貸していただければ嬉しいです。

コード:

 

#include "DxLib.h"
 
typedef struct{
        int x,y,img,muki,walking_flag;
}ch_t;


int hantei[15][20] = {
        { 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,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,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1 },
        { 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,1,1,1,0,0,0,1,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,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,1 },
        { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },
};

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 Genzaiti(int x,int y){//敵とプレイヤーの現在の座標を記録する
	hantei[y/32][x/32]=2;
          return hantei[y/32][x/32];
}

 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        
        int image[16],Egazou,i,j;
        char Key[256];
        ch_t ch,ENEMY;
 
    if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理
 
        ch.x    =320;
        ch.y    =160;
        ch.walking_flag=0;
        ch.muki=3;

		ENEMY.x    =192;
        ENEMY.y    =192;
        ENEMY.muki=3;

 
        SetDrawScreen( DX_SCREEN_BACK ) ;                                                 //描画先を裏画面に設定
        LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存
		Egazou=LoadGraph( "x.png" ); //敵の画像

    while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
            //↑メッセージ処理        ↑画面をクリア         ↑キーボード入力状態取得       ↑ESCが押されると終了
 
		/*白い壁を描画*/
                for(i=0;i<15;i++)
                        for(j=0;j<20;j++)			
							if(hantei[i][j]!=0){
                                        DrawBox(j*32,i*32,(j+1)*32,(i+1)*32,GetColor(255,255,255),TRUE);
							if(hantei[i][j]==2)
										hantei[i][j]=0;//現時点でプレイヤーも敵もいない座標の数字を0に戻す
							}

		
		Genzaiti(ENEMY.x,ENEMY.y);
                               

        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)!=0)//行き先が0でないなら
                    ch.walking_flag=0;
        }


        if(ch.walking_flag==1){        //歩くフラグが立っていたら
            if     (ch.muki==0)        //上向きならch.y座標を減らす
                    ch.y--;
            else if(ch.muki==1)        //左向きならch.x座標を減らす
                    ch.x--;
            else if(ch.muki==2)        //下向きならch.y座標を増やす
                    ch.y++;
            else if(ch.muki==3)        //右向きならch.x座標を増やす
                    ch.x++;
        }

		Genzaiti(ch.x,ch.y);

	    if(ENEMY.x%32==0 && ENEMY.y%32==0){ //敵の座標が32で割り切れたら
			do{
			ENEMY.muki=GetRand(3);
			}while((IsAbleToGo(ENEMY.x,ENEMY.y,ENEMY.muki)!=0));//行き先が0でないなら
		}

		
		    if     (ENEMY.muki==0)        //o.mukiが0ならch.y座標を減らす
                    ENEMY.y--;
            else if(ENEMY.muki==1)        //o.mukiが1ならch.x座標を減らす
                    ENEMY.x--;
            else if(ENEMY.muki==2)        //o.mukiが2ならch.y座標を増やす
                    ENEMY.y++;
            else if(ENEMY.muki==3)        //o.mukiが3ならch.x座標を増やす
                    ENEMY.x++;

	
        ch.img=image[(ch.x%32+ch.y%32)/8 + ch.muki*4];   //プレイヤーの画像をセット
        DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//プレイヤーの画像を描画
		DrawGraph( ENEMY.x , ENEMY.y , Egazou , TRUE ) ;//敵の画像を描画
 
        ScreenFlip();//裏画面を表画面に反映
    }
 
    DxLib_End();
    return 0;
}


アバター
ぱにしん
記事: 58
登録日時: 8年前
住所: 滋賀

Re: DXライブラリの初歩的な質問です

#2

投稿記事 by ぱにしん » 8年前

24章と言うと旧ゲームプログラミングの館の内容ですね。

とりあえず移動の直前にプレイヤーもしくは敵の座標を記録する方法を取っていますが、中々不便そうです・・・

それよりも24章のIsAbletoGo関数の引数にEnemy、ch両方の座標を取ってあげて、行き先に何かがいるならエラーを返すって処理を追加すれば当たり判定については出来る筈です。
足下の地面を変化させる処理ですが、コレは単純にキャラの画像と同じ座標にDrawBoxで箱を描画すれば良いのではないでしょうか

追記
ちょっと回答として情報が少ないように思えて来たので・・・

コード:


int IsAbleToGo(int x1,int y1,int muki,int x2,int y2){//進めるかを判定する
        
        if(muki==0)//上向きなら
                if(hantei[y/32-1][x/32]==1 || (x1==x2      && y1-32==y2) )//進めるか判定
                        return 1;//エラー
        if(muki==1)//左向きなら
                if(hantei[y/32][x/32-1]==1 || (x1-32==x2   && y1 == y2) )
                        return 1;
        if(muki==2)//下向きなら
                if(hantei[y/32+1][x/32]==1 || (x1==x2      && y+32 == y2))
                        return 1;
        if(muki==3)//右向きなら
                if(hantei[y/32][x/32+1]==1 || (x1+32 == x2 && y==y2))
                        return 1;
        return 0;//正常
}

第1、第2引数に動かすキャラの座標、第4、第5引数に動かすときに判定するキャラの座標を入れてください。
この方法だと一体一の判定しかできませんが・・・

ba-yu

Re: DXライブラリの初歩的な質問です

#3

投稿記事 by ba-yu » 8年前

返信ありがとうございます。

書き方が悪く誤解を生んでしまいました、申し訳ありません。
キャラクターの当たり判定自体は最初に書き込んだプログラムでも実現できています。
移動する白い壁(つまりキャラクター本体の座標)がある場所には移動できないように作ってあります。
ただ、二つのキャラが同時に同じ座標に移動しようとした場合にキャラクターが重なってしまうという問題があるんです。
足元の地面の白い壁の動き方を統一したいのも、左と上への移動の場合キーを押した瞬間に白い壁が移動するのに対して、右と下の場合キーを押してしばらくしないと白い壁が移動しないことが当たり判定の問題と関係があるのではないかと考えたからなんです。
なので
>>コレは単純にキャラの画像と同じ座標にDrawBoxで箱を描画すれば良いのではないでしょうか
この解決方法ではキャラクターの本体の位置を無視して白い壁を描画することとなってしまうので使うことができません。

ba-yu

Re: DXライブラリの初歩的な質問です

#4

投稿記事 by ba-yu » 8年前

画像を抜いて実行してみても、右と下に移動しようとした場合、キーを押したタイミングと足元の地面の白い壁の動きにはズレが生じていますね。左手系というものの仕様なのでしょうか?

だんごさん
記事: 273
登録日時: 8年前

Re: DXライブラリの初歩的な質問です

#5

投稿記事 by だんごさん » 8年前

>>コレは単純にキャラの画像と同じ座標にDrawBoxで箱を描画すれば良いのではないでしょうか
この解決方法ではキャラクターの本体の位置を無視して白い壁を描画することとなってしまうので使うことができません
上記の解答では、↓じゃダメってことですよね?

コード:

/*白い壁を描画*/
		Genzaiti(ch.x,ch.y);
		Genzaiti(ENEMY.x,ENEMY.y);
                for(i=0;i<15;i++)
                        for(j=0;j<20;j++)           
                            if(hantei[i][j]!=0){
                                        DrawBox(j*32,i*32,(j+1)*32,(i+1)*32,GetColor(255,255,255),TRUE);
				/*****変更点*****/		DrawBox(ch.x,ch.y,ch.x+32,ch.y+32,GetColor(255,255,255),TRUE);
				/*****変更点*****/		DrawBox(ENEMY.x,ENEMY.y,ENEMY.x+32,ENEMY.y+32,GetColor(255,255,255),TRUE);
										}
 Dango San

だんごさん
記事: 273
登録日時: 8年前

Re: DXライブラリの初歩的な質問です

#6

投稿記事 by だんごさん » 8年前

色々改造してみました・・・。
以下のソースは改造したてのものを張り付けてますので汚いですが、
要するに、移動する前の座標をint型(N,Z)に(x,y)という順で入れてます。
それでDrawBoxで描きます。
書いたまま消えなかったらおかしいので、フラグが立っていなければ
現在の座標を与えて、元に戻す、という感じです。

無理矢理見せかけてますが、ソース的に問題なければうれしいです。

コード:

#include "DxLib.h"
 
typedef struct{
        int x,y,img,muki,walking_flag;
}ch_t;
 
 
int hantei[15][20] = {
        { 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,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,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1 },
        { 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,1,1,1,0,0,0,1,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1 },
        { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,1,1,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,1 },
        { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },
};
 
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 Genzaiti(int x,int y){//敵とプレイヤーの現在の座標を記録する
    hantei[y/32][x/32]=2;
          return hantei[y/32][x/32];
}
 
 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
 
        int /*image[16],Egazou,*/i,j,N,Z;
        char Key[256];
        ch_t ch,ENEMY;
 
    if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理
 
        ch.x    =320;
        ch.y    =160;
        ch.walking_flag=0;
        ch.muki=3;
 
        ENEMY.x    =192;
        ENEMY.y    =192;
        ENEMY.muki=3;

  		

	ch.img=LoadGraph("****.png");
        SetDrawScreen( DX_SCREEN_BACK ) ;                                                 //描画先を裏画面に設定
        //LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存
        //Egazou=LoadGraph( "x.png" ); //敵の画像

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

	
	
                for(i=0;i<15;i++)
                        for(j=0;j<20;j++)           
                            if(hantei[i][j]!=0){	
								 if(hantei[i][j]==2)hantei[i][j]=0;//現時点でプレイヤーも敵もいない座標の数字を0に戻す
                                        DrawBox(j*32,i*32,(j+1)*32,(i+1)*32,GetColor(255,255,255),TRUE);
										DrawBox(N,Z,N+32,Z+32,GetColor(255,255,255),TRUE);
										DrawBox(ch.x,ch.y,ch.x+32,ch.y+32,GetColor(255,0,0),TRUE);

							}
       	Genzaiti(ENEMY.x,ENEMY.y);
     
 
        if(ENEMY.x%32==0 && ENEMY.y%32==0){ //敵の座標が32で割り切れたら
            do{
            ENEMY.muki=GetRand(3);
            }while((IsAbleToGo(ENEMY.x,ENEMY.y,ENEMY.muki)!=0));//行き先が0でないなら
        }
 
        
            if     (ENEMY.muki==0)        //o.mukiが0ならch.y座標を減らす
                    ENEMY.y--;
            else if(ENEMY.muki==1)        //o.mukiが1ならch.x座標を減らす
                    ENEMY.x--;
            else if(ENEMY.muki==2)        //o.mukiが2ならch.y座標を増やす
                    ENEMY.y++;
            else if(ENEMY.muki==3)        //o.mukiが3ならch.x座標を増やす
                    ENEMY.x++;
   
                         
 
        if(ch.x%32==0 && ch.y%32==0){         //座標が32で割り切れたら入力可能
            ch.walking_flag=1;         //歩くフラグを立てる。
			if     ( Key[ KEY_INPUT_UP   ]  == 1 ){  //上ボタンが押されたら
				ch.muki=0;
				N= ch.x;
				Z= ch.y;
			} //上向きフラグを立てる
			else if( Key[ KEY_INPUT_LEFT ]  == 1 ){ //左ボタンが押されたら
				ch.muki=1;        
			    N= ch.x;
				Z= ch.y;
			}//左向きフラグを立てる
			else if( Key[ KEY_INPUT_DOWN ]  == 1 ){ //下ボタンが押されたら
				ch.muki=2;
			    N= ch.x;
			    Z= ch.y;
            }//下向きフラグを立てる
     		else if( Key[ KEY_INPUT_RIGHT]  == 1 ){//右ボタンが押されたら
				ch.muki=3;
				N= ch.x;
				Z= ch.y;
			}//右向きフラグを立てる
            else                                    //何のボタンも押されてなかったら
                    ch.walking_flag=0; //歩かないフラグを立てる
            if(ch.walking_flag==1)    //もし歩くなら
                if(IsAbleToGo(ch.x,ch.y,ch.muki)!=0)//行き先が0でないなら
                    ch.walking_flag=0;
        }
      
 
        if(ch.walking_flag==1){        //歩くフラグが立っていたら
            if     (ch.muki==0)        //上向きならch.y座標を減らす
                    ch.y--;
            else if(ch.muki==1)        //左向きならch.x座標を減らす
                    ch.x--;
            else if(ch.muki==2)        //下向きならch.y座標を増やす
                    ch.y++;
            else if(ch.muki==3)        //右向きならch.x座標を増やす
                    ch.x++;
        }
		if(ch.walking_flag==0){
			N = ch.x;
			Z = ch.y;
		}
   

           //プレイヤーの画像をセット
        DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//プレイヤーの画像を描画
        //DrawGraph( ENEMY.x , ENEMY.y , Egazou , TRUE ) ;//敵の画像を描画
 
                            
        ScreenFlip();//裏画面を表画面に反映
    }
 
    DxLib_End();
    return 0;
}
あ、敵の方はやってないです。プレイヤーのだけ・・・。
 Dango San

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

Re: DXライブラリの初歩的な質問です

#7

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

全部をマップ座標系(32で割った座標系)で処理するのは無理があります。
キャラクタは32で割らない座標系で独自に当たり判定すべきでしょう。
そうすればマップを書き換える必要もなくなります。

>画像を抜いて実行してみても、右と下に移動しようとした場合、キーを押したタイミングと足元の地面の白い壁の動きにはズレが生じていますね。左手系というものの仕様なのでしょうか?

それは単に計算の仕方の問題ですが、上に書いた通り独自に処理すれば解決します。
右手、左手系は3D空間における座標系の話だけだったはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

Re: DXライブラリの初歩的な質問です

#8

投稿記事 by ISLe » 8年前

x/32とかy/32は端数を切り捨てるので左上に寄ってしまうわけです。
右に移動しているときは(x+(32-1))/32、下に移動しているときは(y+(32-1))/32とすると移動先のマップ座標を得ることができます。
#座標が常に正の数であることが前提です。

最初の投稿に書かれたコードで、Genzaiti関数を以下のように変更して、呼び出し側にも引数を追加してください。

コード:

// 敵とプレイヤーの現在の座標を記録する
int Genzaiti(int x, int y, int muki)
{
	switch (muki) {
	case 0: // 上向き
	case 1: // 左向き
		hantei[y/32][x/32]=2;
		break;
	case 2: // 下向き
	case 3: // 右向き
		hantei[(y+(32-1))/32][(x+(32-1))/32]=2;
		break;
	}
	return hantei[y/32][x/32];
}

ba-yu

Re: DXライブラリの初歩的な質問です

#9

投稿記事 by ba-yu » 8年前

皆さん、ありがとうございました。
無事解決しました。
>>だんごさん
すいません、これでもダメみたいです
>>ソフト屋さん
マップ座標系で作ったほうがすんなりいくだろうというのは理解しています。
ですが、昔のマップ座標系のゲームでも当たり判定はできていたのだから、どうにかそれを再現してみたいと思ったもので。
>>ISLeさん
ありがとうございました、想像通りに動くようになりました。
DXライブラリの仕様云々以前にプログラムそのものへの理解たりていませんでした。

閉鎖

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