ifまみれの移動制御をなんとかしたい

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

ifまみれの移動制御をなんとかしたい

#1

投稿記事 by イマダニ » 6年前

今回はif文だらけで汚らしいコードをどうにかしたく、質問しに来ました。

そのコードは以下の質問で

クォーターの当たり判定とスクロール
http://dixq.net/forum/viewtopic.php?t=12822

質問に回答してくれたソフト屋さんにif文だらけで汚いと言われたもので、
以下がそのコードになります。

コード:

		if( checkkey(KEY_INPUT_LEFT)>0 && checkkey(KEY_INPUT_UP)>0  ){//押されたキーによって
			p.muki=5;	//向きを指定。これは左上
			p.walkflag=true;//歩きフラグをたてる
		}else if( checkkey(KEY_INPUT_LEFT)>0 && checkkey(KEY_INPUT_DOWN)>0 ){
			p.muki=6;	//左下
			p.walkflag=true;
		}else if( checkkey(KEY_INPUT_RIGHT)>0 && checkkey(KEY_INPUT_UP)>0 ){
			p.muki=7;	//右上
			p.walkflag=true;
		}else if( checkkey(KEY_INPUT_RIGHT)>0 && checkkey(KEY_INPUT_DOWN)>0 ){
			p.muki=8;	//右下
			p.walkflag=true;
		
		}else if( checkkey(KEY_INPUT_LEFT)>0 ){
			p.muki=1;   //左向きで
			p.walkflag=true;  //フラグが建つよ
		}else if( checkkey(KEY_INPUT_RIGHT)>0 ){
			p.muki=2;	//右
			p.walkflag=true;
		}else if( checkkey(KEY_INPUT_UP)>0 ){
			p.muki=3;	//右
			p.walkflag=true;
		}else if( checkkey(KEY_INPUT_DOWN)>0 ){
			p.muki=4;
			p.walkflag=true;
		
		}else{			//それ以外
			p.walkflag=false;  //フラグ建ってないよ
		}

		//歩きフラグの分岐
		if(p.walkflag==true){//フラグがたってる時
			if(p.muki==1){	//左へ
				p.x-=4;		//走る
				p.y+=4;     /*クォータの座標に変えたため、X座標だけ変動しても斜めに移動するため
							  y座標も変えた*/
				p.img=10+(p.cnt/5)%8;
			}if(p.muki==2){	//右へ
				p.x+=4;     //走る
				p.y-=4;
				p.img=19+(p.cnt/5)%8;//それのアニメーション
			}if(p.muki==3){ //上へ
				p.y-=6;
				p.x-=6;
				p.img=28+(p.cnt/5)%8;
			}if(p.muki==4){ //下へ
				p.y+=6;
				p.x+=6;
				p.img=1+(p.cnt/5)%8;
			}
			
			if(p.muki==5){	//左上
				p.x-=6;
				p.img=37+(p.cnt/5)%8;
			}if(p.muki==6){	//左下
				p.y+=6;
				p.img=55+(p.cnt/5)%8;
			}if(p.muki==7){	//右上
				p.y-=6;
				p.img=46+(p.cnt/5)%8;
			}if(p.muki==8){
				p.x+=6;
				p.img=64+(p.cnt/5)%8;
			}

		}if(p.walkflag==false){//フラグが建ってない時
			//それぞれの向きの立っている絵にする
			if(p.muki==1) p.img=9;
			if(p.muki==2) p.img=18;
			if(p.muki==3) p.img=27;
			if(p.muki==4) p.img=0;
			if(p.muki==5) p.img=36;
			if(p.muki==6) p.img=54;
			if(p.muki==7) p.img=45;
			if(p.muki==8) p.img=63;
		}
クォーターなので八方向です。汚いですねとっても……
そこで上記の質問でソフト屋さんが配列を使えばきれいにできるとのヒントをくれたので
それをもとに自分なりきれいにしてみました。

ソフト屋さん、せっかくアドバイスくれたのに遅くなってすいません!

以下がそのコードになります。

コード:

		//キー入力配列
		p.muki[0]=CheckKey(KEY_INPUT_LEFT); p.muki[1]=CheckKey(KEY_INPUT_RIGHT);
		p.muki[2]=CheckKey(KEY_INPUT_DOWN); p.muki[3]=CheckKey(KEY_INPUT_UP);

		for(int i=0; i<4; i++){
			if(p.muki[i]>0){
				switch(i){
					case 0://左へ
						p.x-=p.speed;//走る
						p.y+=p.speed;

						p.img=10+(p.cnt/5)%8;//それのアニメーション
						break;
					case 1://右へ
						p.x+=p.speed;
						p.y-=p.speed;

						p.img=19+(p.cnt/5)%8;
						break;
					case 2://下へ
						p.x+=p.speed;
						p.y+=p.speed;

						p.img=1+(p.cnt/5)%8;
						break;
					case 3://上へ
						p.x-=p.speed;
						p.y-=p.speed;

						p.img=28+(p.cnt/5)%8;
						break;
				}
			}
		}
移動の部分だけ抜き取るとこんな感じです。
どうでしょうか?我ながらなかなか綺麗になったと思うのですが……
まだ歩きフラグなど入れてないため移動をやめると走ってる途中の画像で止まりますが、ベースはこんな感じでいいかなーと。

ソフト屋さんのもう一つのヒントの構造体配列はいまいち扱い方が思いつかなかったのでそれはまだ実装できておりません。
できればcheckkeyの配列化、構造体配列を使うをやってから質問したかったんですが、ごめんなさいわからんかったです……

よろしければ感想とアドバイスください。
いらぬ誤解を招かないよう、一応、コードの全体はっておきますね。

コード:

#include"DxLib.h"
#include"Key.h"//新c言語と同じupdateとcheckkeyが書かれてる
#include <math.h>//ルート使おうかなと思いインクルード

//画面の大きさ
#define SCREEN_WIDTH 640;
#define SCREEN_HEIGHT 480;
//チップの枚数
#define CHIP_NUMBER_X 10
#define CHIP_NUMBER_Y 8

#define MAP_PARTS_HSIZEX 32 /*マップパーツの横サイズ(半分)*/
#define MAP_PARTS_HSIZEY 16 /*マップパーツの縦サイズ(半分)*/

#define VTOP_PARTS_SIZEX 64 /*仮想トップビューのマップパーツの横サイズ*/
#define VTOP_PARTS_SIZEY 64 /*仮想トップビューのマップパーツの縦サイズ*/
#define CHAR_PARTS_SIZEX 64
#define CHAR_PARTS_SIZEY 48

#define MAP_VIEW_OFFSET 32


//プレイヤー構造体
typedef struct{
	bool walkflag,jumpflag;//歩きフラグ
	int img,cnt,jcnt,muki[8];//画像、カウンタ、向き
	double x,y,speed,naname,oldx,oldy;//座標
}PLAY;

//マップデータ
int MapData[ CHIP_NUMBER_Y ][ CHIP_NUMBER_X ] =
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);

	/*AllocConsole();
    freopen("CONOUT$", "w", stdout); //標準出力をコンソールにする
	//  printf( "これでprintfが使えます\n" );   //←お試し用*/

	//構造体宣言
	PLAY p;

	//画像変数
	int player[81];
	int map;
	
	//画像の読み込み
	map    = LoadGraph("img/mapchip01.bmp");
	LoadDivGraph("img/player1.png",81,9,9,64,64,player);
	
	//構造体要素の初期化
	memset(&p,0,sizeof(PLAY));
	
	//プレイヤー座標の初期化
	p.x=160;
	p.y=160;

	p.speed=4.0;//移動スピード
	p.naname=sqrt(2.0);//とりあえず斜め移動の速度制御のために用意。まだ使ってない。

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && updatekey()==0 ){

		//プレイヤー移動アニメーションのためのカウント
		p.cnt++;

		//座標を記録
		p.oldx=p.x;
		p.oldy=p.y;

		//キー入力配列
		p.muki[0]=CheckKey(KEY_INPUT_LEFT); p.muki[1]=CheckKey(KEY_INPUT_RIGHT);
		p.muki[2]=CheckKey(KEY_INPUT_DOWN); p.muki[3]=CheckKey(KEY_INPUT_UP);

		for(int i=0; i<4; i++){
			if(p.muki[i]>0){
				switch(i){
					case 0://左へ
						p.x-=p.speed;//走る
						p.y+=p.speed;

						p.img=10+(p.cnt/5)%8;//それのアニメーション
						break;
					case 1://右へ
						p.x+=p.speed;
						p.y-=p.speed;

						p.img=19+(p.cnt/5)%8;
						break;
					case 2://下へ
						p.x+=p.speed;
						p.y+=p.speed;

						p.img=1+(p.cnt/5)%8;
						break;
					case 3://上へ
						p.x-=p.speed;
						p.y-=p.speed;

						p.img=28+(p.cnt/5)%8;
						break;
				}
			}
		}

		//いけない所だったら
		if( MapData[(int)p.y/64][(int)p.x/64]==0 ){
				p.x=p.oldx; //移動前の座標を代入
				p.y=p.oldy;
		}

		//マップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				if(MapData[y][x]==1){
					DrawGraph(MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX*(x-y), MAP_PARTS_HSIZEY*(x+y), map,TRUE);
				}
			}
		}
		//プレイヤー描画
		DrawGraph((MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX)+(p.x-p.y)*MAP_PARTS_HSIZEX/VTOP_PARTS_SIZEX - CHAR_PARTS_SIZEX/2
				  ,(p.x+p.y)*MAP_PARTS_HSIZEY/VTOP_PARTS_SIZEY - CHAR_PARTS_SIZEY
				  ,player[p.img],TRUE);
	}

	DxLib_End();

	return 0;
}

コード:

key.cpp

#include "DxLib.h"

int num[256];

int updatekey(){
	char Buf[256];
	GetHitKeyStateAll(Buf);
	for(int i=0;i<256;i++){
		if(Buf[i] !=0){
			num[i]++;
		}else{
			num[i]=0;
		}
	}
	return 0;
}

int CheckKey(int KeyCode){
	return num[KeyCode];
}

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

Re: ifまみれの移動制御をなんとかしたい

#2

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

このコードだと、わざわざfor文で回す必要が無いように思えます。
[PHP] forとifの使い方覚えました!-ウンコード・マニアをifではなくswitchにした、という感じですね。

コード:

// CheckKey略

const int dx[4]={-1,1,1,-1};
const int dy[4]={1,-1,1,-1};
const int imgid[4]={10,19,1,28};

for(int i=0; i<4; i++){
    if(p.muki[i]>0){
        p.x+=dx[i]*p.speed;
        p.y+=dy[i]*p.speed;
        p.img=imgid[i]+(p.cnt/5)%8;
    }
}
のようにしないと、for文を使う効果は薄いと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: ifまみれの移動制御をなんとかしたい

#3

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

事前にCheckKeyを4個書く手間も省けますね。

コード:

const int keyid[4]={KEY_INPUT_LEFT,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_UP};
const int dx[4]={-1,1,1,-1};
const int dy[4]={1,-1,1,-1};
const int imgid[4]={10,19,1,28};
 
for(int i=0; i<4; i++){
    if((p.muki[i]=CheckKey(keyid[i]))>0){
        p.x+=dx[i]*p.speed;
        p.y+=dy[i]*p.speed;
        p.img=imgid[i]+(p.cnt/5)%8;
    }
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
usao
記事: 1574
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#4

投稿記事 by usao » 6年前

左と下が同時に押されたら
p.yが通常の2倍だけ変化しそうですが,それで動作としてはOKなのですか?
(ifで書いてた時と動作が違いそう?)

イマダニ
記事: 145
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#5

投稿記事 by イマダニ » 6年前

>>みけCATさん
アドバイスありがとうございます!
これは確かにウンコードですね……
こんなの書いてドヤガオしていた自分が恥ずかしいです
早速、書きなおしました。特に問題なく動きました。

コード:

#include"DxLib.h"
#include"Key.h"
#include <math.h>

//画面の大きさ
#define SCREEN_WIDTH 640;
#define SCREEN_HEIGHT 480;
//チップの枚数
#define CHIP_NUMBER_X 10
#define CHIP_NUMBER_Y 8

#define MAP_PARTS_HSIZEX 32 /*マップパーツの横サイズ(半分)*/
#define MAP_PARTS_HSIZEY 16 /*マップパーツの縦サイズ(半分)*/

#define VTOP_PARTS_SIZEX 64 /*仮想トップビューのマップパーツの横サイズ*/
#define VTOP_PARTS_SIZEY 64 /*仮想トップビューのマップパーツの縦サイズ*/
#define CHAR_PARTS_SIZEX 64
#define CHAR_PARTS_SIZEY 48

#define MAP_VIEW_OFFSET 32


//プレイヤー構造体
typedef struct{
	bool walkflag,jumpflag;//歩きフラグ
	int img,cnt,jcnt,muki[4];//画像、カウンタ、向き
	double x,y,speed,naname,oldx,oldy;//座標
}PLAY;

//マップデータ
int MapData[ CHIP_NUMBER_Y ][ CHIP_NUMBER_X ] =
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);

	AllocConsole();
    freopen("CONOUT$", "w", stdout); //標準出力をコンソールにする
	//  printf( "これでprintfが使えます\n" );   //←お試し用

	//構造体宣言
	PLAY p;

	//画像変数
	int player[81];
	int map;
	
	//画像の読み込み
	map    = LoadGraph("img/mapchip01.bmp");
	LoadDivGraph("img/player1.png",81,9,9,64,64,player);
	
	//構造体要素の初期化
	memset(&p,0,sizeof(PLAY));
	
	//プレイヤー座標の初期化
	p.x=160;
	p.y=160;

	p.speed=4.0;

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && updatekey()==0 ){

		//プレイヤー移動アニメーションのためのカウント
		p.cnt++;

		//座標を記録
		p.oldx=p.x;
		p.oldy=p.y;
	
		const int keyid[4]={KEY_INPUT_LEFT,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_UP};
		const int dx[4]={-1,1,1,-1};//左、右、下、上
		const int dy[4]={1,-1,1,-1};//左、右、下、上
		const int imgid[4]={10,19,1,28};

		for(int i=0; i<4; i++){
			if((p.muki[i]=CheckKey(keyid[i]))>0){
				p.x+=dx[i]*p.speed;
				p.y+=dy[i]*p.speed;
				p.img=imgid[i]+(p.cnt/5)%8;
			}
		}

		printf("%d",p.x);

		//いけない所だったら
		if( MapData[(int)p.y/64][(int)p.x/64]==0 ){
				p.x=p.oldx; //移動前の座標を代入
				p.y=p.oldy;
		}

		//マップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				if(MapData[y][x]==1){
					DrawGraph(MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX*(x-y), MAP_PARTS_HSIZEY*(x+y), map,TRUE);
				}
			}
		}
		//プレイヤー描画
		DrawGraph((MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX)+(p.x-p.y)*MAP_PARTS_HSIZEX/VTOP_PARTS_SIZEX - CHAR_PARTS_SIZEX/2
				  ,(p.x+p.y)*MAP_PARTS_HSIZEY/VTOP_PARTS_SIZEY - CHAR_PARTS_SIZEY
				  ,player[p.img],TRUE);
	}

	DxLib_End();

	return 0;
}
>>usaoさん
そこが悩みどころです。
上下移動より左右移動が速く、斜め移動はそれよりもさらに速いと

上下移動<左右移動<斜め移動

こんな感じに速度がバラバラで安定しません。

シューティングなどでは斜め移動の際ルート2分の1をかけることで
速度を安定させていましたが、

今回はクォーターなので、

斜め移動がトップビューなどでの上下左右
上下左右がトップビューなどでの斜め移動

と複雑になっており、速度関連がこんがらがっています。

ifまみれの時はp.x,p.yを増減する数値、上記コードでのspeedを
調整する事で速度を安定させてました。

コード:

        if(p.walkflag==true){//フラグがたってる時
            if(p.muki==1){  //左へ

                p.x-=4;     //走る
                p.y+=4;     /*クォータの座標に変えたため、X座標だけ変動しても斜めに移動するため
                              y座標も変えた*/

                p.img=10+(p.cnt/5)%8;
            }if(p.muki==2){ //右へ

                p.x+=4;     //走る
                p.y-=4;

                p.img=19+(p.cnt/5)%8;//それのアニメーション

            }if(p.muki==3){ //上へ

                p.y-=6;//遅くなるので速度を+2
                p.x-=6;

                p.img=28+(p.cnt/5)%8;
            }if(p.muki==4){ //下へ

                p.y+=6;//遅くなるので速度を+2
                p.x+=6;

                p.img=1+(p.cnt/5)%8;
            }
といっても実際の数値を確認したわけではなく、
ゲーム上で動かしてみて同じくらいだなといった感じの適当な調整です。

アバター
usao
記事: 1574
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#6

投稿記事 by usao » 6年前

>そこが悩みどころです。
あ,私の指摘は,「移動処理をどうすべきか」という方法論についてではなくて
あくまでも
「ifで書いてたときと結果が違うけど大丈夫?」(コードをきれいにする作業→動作が変わったらダメじゃない?)
という点についてです.本件のタイトル的に.

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

Re: ifまみれの移動制御をなんとかしたい

#7

投稿記事 by ISLe » 6年前

最初のコードをテーブルを使って整理するとこんな感じになるかと。

コード:

// 撤回しました
(追記)
提示したコードは致命的な欠陥を含んでいたため撤回します。
最後に編集したユーザー ISLe on 2013年8月31日(土) 06:42 [ 編集 1 回目 ]

かずま

Re: ifまみれの移動制御をなんとかしたい

#8

投稿記事 by かずま » 6年前

ISLe さんが書きました:最初のコードをテーブルを使って整理するとこんな感じになるかと。
自動変数のテーブルを使うなら、static を付けましょう。
でないと、keyinput_muki_table[] は、16個初期化して、使うのは 1個だけ
ですし、table[8][4] は、32個初期化して、使うのは 3個か 1個だけ。
それらの初期化は、ここを通るたび、毎回毎回毎回実行されます。

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

Re: ifまみれの移動制御をなんとかしたい

#9

投稿記事 by ISLe » 6年前

ご指摘ありがとうございます。
かずま さんが書きました:それらの初期化は、ここを通るたび、毎回毎回毎回実行されます。
こちらの表現から非常に非常に非常に致命的であるということが感じ取れましたので該当コードは撤回させていただきました。

イマダニ
記事: 145
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#10

投稿記事 by イマダニ » 6年前

>>usao
すいません勘違いしてました!
半端に変えてしまったせいで違う動作になってますフラグが入ってないし……
usaoさんの言うように動作は同じで、コードを綺麗にしたいです

>>ISleさん
usaoさんの突っ込みで、動作同じで、綺麗にしなきゃと思った所、
それに当たるコードの書き込みありがとうございます!
テーブルという概念を扱ったことのない自分にはかなり新鮮で勉強になりました。
それで昨日コードを書き込み、結果報告と質問しようかなと今来たのですけれど、
来てみたらなんと撤回されておる……
少し残念ですが、質問はやめときますね。

イマダニ
記事: 145
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#11

投稿記事 by イマダニ » 6年前

といってもforでまわしているせいか、最初ぼくが書いたswitch文のウンコードでも
walkflag、歩きフラグを交えるとうまくいかないんですよね。

コード:

		const int keyid[4]	= {KEY_INPUT_LEFT,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_UP};
		const int dx[4]		= {-1,1,1,-1};
		const int dy[4]		= {1,-1,1,-1};
		const int imgid[4]	= {10,19,1,28};
		const int imgid2[4] = {9,18,0,27};//立ってる画像
 
		for(int i=0; i<4; i++){
			if((p.muki[i]=CheckKey(keyid[i]))>0){
				p.walkflag=true;//フラグを立てる
			}else{
				p.walkflag=false;
			}

			if(p.walkflag){//フラグごとの動き
				p.x+=dx[i]*p.speed;
				p.y+=dy[i]*p.speed;
				p.img=imgid[i]+(p.cnt/5)%8;
			}else{
				p.img=imgid2[i];
			}
		}
みけCATさんの奴を同じ動作に近づけようとひとまずフラグを入れたのが上記コードですが
思った通りの動き、

フラグがたってる時、走る画像
たってない時、立ってる画像

という動きをするのが上方向だけなんです。

それ以外の方向は上方向に向いて立ってる画像のまま画面上をキー入力に合わせて動きまわります。
これは僕のswitchでも同じでした。

画像も向きごとに、アニメーションも向きごとに、速度も向きごと、と分けるとなると

ISleさんのテーブルのような形が一番向いているような気がします。
やはりこういった細かい動きをfor文でまとめるのは難しいのでしょうか?

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

Re: ifまみれの移動制御をなんとかしたい

#12

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

イマダニ さんが書きました:思った通りの動き、

フラグがたってる時、走る画像
たってない時、立ってる画像

という動きをするのが上方向だけなんです。
フラグと画像の関係は正常だと予想します。
for文に入る前にp.walkflag=false;と初期化して、forのなかではfalseを代入するのをやめてみてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: ifまみれの移動制御をなんとかしたい

#13

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

この構造だと、フラグを立てるfor文と動くためのfor文を分けるべきだと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

イマダニ
記事: 145
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#14

投稿記事 by イマダニ » 6年前

みけCATさん さんが書きました: for文に入る前にp.walkflag=false;と初期化して、forのなかではfalseを代入するのをやめてみてください。

この構造だと、フラグを立てるfor文と動くためのfor文を分けるべきだと思います。
以下のような形でいいんでしょうか?

コード:

		const int keyid[4]	= {KEY_INPUT_LEFT,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_UP};
		const int dx[4]		= {-1,1,1,-1};//x移動量、これに速度をかける
		const int dy[4]		= {1,-1,1,-1};//y移動量
		const int imgid[4]	= {10,19,1,28};//走ってる画像
		const int imgid2[4] = {9,18,0,27};//立ってる画像
 
		p.walkflag=false;//歩きフラグをfalseに初期化

		/*フラグのためのfor文*/
		for(int i=0; i<4; i++){
			if((p.muki[i]=CheckKey(keyid[i]))>0){//キーが押されてる時に
				p.walkflag=true;//フラグを立てる
			}
		}

		/*移動のためのfor文*/
		for(int i=0;i<4;i++){
			if(p.walkflag){//フラグが建ってる時の動き
				p.x+=dx[i]*p.speed;
				p.y+=dy[i]*p.speed;
				p.img=imgid[i]+(p.cnt/5)%8;//走ってる画像
			}else{//それ以外
				p.img=imgid2[i];//立ってる画像
			}
		}
これを実行した所、

どの方向のキーを押しても、

walkflagがfalseの時は、上を向いて立っている画像

walkflagがtrueの時は、上を向いて走っている画像

移動はしません。

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

Re: ifまみれの移動制御をなんとかしたい

#15

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

下のfor文でp.mukiによって条件分岐してください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

イマダニ
記事: 145
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#16

投稿記事 by イマダニ » 6年前

コード:

		const int keyid[4]	= {KEY_INPUT_LEFT,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_UP};
		const int dx[4]		= {-1,1,1,-1};//x移動量、これに速度をかける
		const int dy[4]		= {1,-1,1,-1};//y移動量
		const int imgid[4]	= {10,19,1,28};//走ってる画像
		const int imgid2[4] = {9,18,0,27};//立ってる画像
 
		p.walkflag=false;//歩きフラグをfalseに初期化

		for(int i=0; i<4; i++){
			if((p.muki[i]=CheckKey(keyid[i]))>0){//キーが押されてる時に
				p.walkflag=true;//フラグを立てる
			}
		}

		for(int i=0;i<4;i++){
			if(p.muki[i]){//向きごとに
				if(p.walkflag){//フラグが建ってる時の動き
					p.x+=dx[i]*p.speed;
					p.y+=dy[i]*p.speed;
					p.img=imgid[i]+(p.cnt/5)%8;//走ってる画像
				}else{//それ以外
					p.img=imgid2[i];//立ってる画像
				}
			}
		}
走るようにはなりました。
ですが、フラグがfalseの時、止まった時に、キャラが立ってる画像にならず、
走ってるアニメーションの途中で止まります。

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

Re: ifまみれの移動制御をなんとかしたい

#17

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

後のfor文の前で、p.imgを止まっている画像で初期化してみてください。
直前の向きで変えたいなら、変数に向きを保存すると良いでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

イマダニ
記事: 145
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#18

投稿記事 by イマダニ » 6年前

コード:

typedef struct{
	bool walkflag,jumpflag;//歩きフラグ
	int img,cnt,jcnt,muki[4];//画像、カウンタ、向き

	int old_muki[4];/*向き保存変数*/

	double x,y,speed,naname,oldx,oldy;//座標
}PLAY;
player構造体に保存変数を作り、

コード:

		const int keyid[4]	= {KEY_INPUT_LEFT,KEY_INPUT_RIGHT,KEY_INPUT_DOWN,KEY_INPUT_UP};
		const int dx[4]		= {-1,1,1,-1};//x移動量、これに速度をかける
		const int dy[4]		= {1,-1,1,-1};//y移動量
		const int imgid[4]	= {10,19,1,28};//走ってる画像
		const int imgid2[4] = {9,18,0,27};//立ってる画像
 
		p.walkflag=false;//歩きフラグをfalseに初期化

		for(int i=0; i<4; i++){
			if((p.muki[i]=CheckKey(keyid[i]))>0){//キーが押されてる時に
				p.walkflag=true;//フラグを立てる
				p.old_muki[i]=p.muki[i];/*向き保存*/
			}
		}

		for(int i=0;i<4;i++){/*立ってる画像を入れる*/
			if(p.old_muki[i])
				p.img=imgid2[i];
		}

		for(int i=0;i<4;i++){
			if(p.muki[i]){
				if(p.walkflag){//フラグが建ってる時の動き
					p.x+=dx[i]*p.speed;
					p.y+=dy[i]*p.speed;
					p.img=imgid[i]+(p.cnt/5)%8;//走ってる画像
				}
			}
		}
移動前にp.imgを立ち画像に初期化した所、

一見正常に動いたと思ったのですが、

上を押すともうどの方向で立ち止まろうと上を向いて立ち止まります。

const int keyid[4] = {KEY_INPUT_LEFT, KEY_INPUT_RIGHT, KEY_INPUT_DOWN, KEY_INPUT_UP};

この配列で、右にある向き要素の方が優先されるようです。

もうKEY_INPUT_RIGHTを一度押してしまえば、LEFTを押してもRIGHTの立ち画像になり。
一度DOWNを押してしまえばLEFT、RIGHTどちらを押しても下向きに立つ。
UPを押したらもうすべて上向きになります。

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

Re: ifまみれの移動制御をなんとかしたい

#19

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

p.mukiが0以下の時にp.old_mukiを更新していないようです。
p.old_mukiの更新をif文の後ろに出してください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

タミア

Re: ifまみれの移動制御をなんとかしたい

#20

投稿記事 by タミア » 6年前

みけCAT さんが書きました:p.mukiが0以下の時にp.old_mukiを更新していないようです。
p.old_mukiの更新をif文の後ろに出してください。

それだとold_mukiを追加する前と同じように移動していないときに正しく画像が表示されないように思います。
何も入力していないときold_mukiもすべて0になるため、画像が変わりません。

>> イマダニさん
muki変数にキーが入力されているかを入れてしまうのは変数名と合わないためよくないかと。
また、muki変数を配列にする必要は無いとおもいます。

mukiでどの方向を向いているかを判断し、
walkflagで移動中か判断させましょう。
walkflagがtrueのときにdxやdyの添字にmukiの値を使って計算させ、
mukiに応じた画像を表示させるようにします。
移動計算の部分をループにする必要もなくなります。

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

Re: ifまみれの移動制御をなんとかしたい

#21

投稿記事 by ISLe » 6年前

イマダニさんに申し訳ない気がするので再投稿します。

コードも若干変化していますが、重要なのはテーブル部分をcodeタグで分離したことです。
内容としては変わりません。
コードを利用する際、すべての責任は利用者側にあります。

コード:

		const int keyinput_muki_table[] = {
			0, // nothing
			1, // L
			2, // R
			0, // L+R
			3, // U
			5, // U+L
			7, // U+R
			3, // U+L+R
			4, // D
			6, // D+L
			8, // D+R
			4, // D+L+R
			0, // D+U
			1, // D+U+L
			2, // D+U+R
			0, // D+U+L+R
		};
		const int player_muki_table[8][3] = {
			// X増分, Y増分, 静止画像添字 ※構造体にすると可読性が上がる
			{ -4,  4,  9 }, // 左
			{  4, -4, 18 }, // 右
			{ -6, -6, 27 }, // 上
			{  6,  6,  0 }, // 下
			{ -6,  0, 36 }, // 左上
			{  0,  6, 54 }, // 左下
			{  0, -6, 45 }, // 右上
			{  6,  0, 63 }, // 右下
		};

コード:

		int keyinput = 0, muki;
		if (checkkey(KEY_INPUT_LEFT) >0) keyinput += 1;
		if (checkkey(KEY_INPUT_RIGHT)>0) keyinput += 2;
		if (checkkey(KEY_INPUT_UP)   >0) keyinput += 4;
		if (checkkey(KEY_INPUT_DOWN) >0) keyinput += 8;
		// 入力状況に応じた新しい向きを得る
		muki = keyinput_muki_table[keyinput];
		// 歩きフラグは新しい向きが有効(0以外)かどうか
		p.walkflag = (muki != 0);
		// 新しい向きに歩くとき現在の向きを更新
		if (p.walkflag) p.muki = muki;

		if (p.walkflag) {
			p.x += player_muki_table[p.muki-1][0];
			p.y += player_muki_table[p.muki-1][1];
			p.img = player_muki_table[p.muki-1][2]+1+(p.cnt/5)%8;
		}
		else {
			p.img = player_muki_table[p.muki-1][2];
        }

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

Re: ifまみれの移動制御をなんとかしたい

#22

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

>> ISLeさん
再投稿してもらって良かったです。

>>かずまさん
今回の指摘は今回の本筋と何も関係がないので、独り言で投稿してもらえると助かります。
あるいは、実行には影響がないなどイマダニさんに分かるように解説してください。
イマダニさんに混乱を与える可能性が高いです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

イマダニ
記事: 145
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#23

投稿記事 by イマダニ » 6年前

ISLeさん さんが書きました:イマダニさんに申し訳ない気がするので再投稿します。
再投稿感謝します!本当にありがとうございます!
どうしてもわからない部分があったので質問させていただきます!

まずは実行結果を報告します。コードは以下のように書き換えました。

コード:

#include"DxLib.h"
#include"Key.h"
#include <math.h>

//画面の大きさ
#define SCREEN_WIDTH 640;
#define SCREEN_HEIGHT 480;
//チップの枚数
#define CHIP_NUMBER_X 10
#define CHIP_NUMBER_Y 8

#define MAP_PARTS_HSIZEX 32 /*マップパーツの横サイズ(半分)*/
#define MAP_PARTS_HSIZEY 16 /*マップパーツの縦サイズ(半分)*/

#define VTOP_PARTS_SIZEX 64 /*仮想トップビューのマップパーツの横サイズ*/
#define VTOP_PARTS_SIZEY 64 /*仮想トップビューのマップパーツの縦サイズ*/
#define CHAR_PARTS_SIZEX 64
#define CHAR_PARTS_SIZEY 48

#define MAP_VIEW_OFFSET 32


//プレイヤー構造体
typedef struct{
	bool walkflag,jumpflag;//歩きフラグ
	int img,cnt,jcnt,muki;//画像、カウンタ、向き
	double x,y,speed,naname,oldx,oldy;//座標
}PLAY;

//マップデータ
int MapData[ CHIP_NUMBER_Y ][ CHIP_NUMBER_X ] =
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);

	AllocConsole();
    freopen("CONOUT$", "w", stdout); //標準出力をコンソールにする
	//  printf( "これでprintfが使えます\n" );   //←お試し用

	//構造体宣言
	PLAY p;

	//画像変数
	int player[81];
	int map;
	
	//画像の読み込み
	map    = LoadGraph("img/mapchip01.bmp");
	LoadDivGraph("img/player1.png",81,9,9,64,64,player);
	
	//構造体要素の初期化
	memset(&p,0,sizeof(PLAY));
	
	//プレイヤー座標の初期化
	p.x=160;
	p.y=160;

	p.speed=4.0;//移動速度

	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && updatekey()==0 ){

		//プレイヤー移動アニメーションのためのカウント
		p.cnt++;

		//座標を記録
		p.oldx=p.x;
		p.oldy=p.y;
		
		/*書き変えたというより
		コピペした部分はここから*/
		const int keyinput_muki_table[] = {
            0, // nothing
            1, // L
            2, // R
            0, // L+R
            3, // U
            5, // U+L
            7, // U+R
            3, // U+L+R
            4, // D
            6, // D+L
            8, // D+R
            4, // D+L+R
            0, // D+U
            1, // D+U+L
            2, // D+U+R
            0, // D+U+L+R
        };
        const int player_muki_table[8][3] = {
            // X増分, Y増分, 静止画像添字 ※構造体にすると可読性が上がる
            { -4,  4,  9 }, // 左
            {  4, -4, 18 }, // 右
            { -6, -6, 27 }, // 上
            {  6,  6,  0 }, // 下
            { -6,  0, 36 }, // 左上
            {  0,  6, 54 }, // 左下
            {  0, -6, 45 }, // 右上
            {  6,  0, 63 }, // 右下
        };

		int keyinput = 0, muki;
        
		if (CheckKey(KEY_INPUT_LEFT) >0) keyinput += 1;
        if (CheckKey(KEY_INPUT_RIGHT)>0) keyinput += 2;
        if (CheckKey(KEY_INPUT_UP)   >0) keyinput += 4;
        if (CheckKey(KEY_INPUT_DOWN) >0) keyinput += 8;
        // 入力状況に応じた新しい向きを得る
        muki = keyinput_muki_table[keyinput];
        // 歩きフラグは新しい向きが有効(0以外)かどうか
        p.walkflag = (muki != 0);
        // 新しい向きに歩くとき現在の向きを更新
        if (p.walkflag) p.muki = muki;
 
        if (p.walkflag) {
            p.x += player_muki_table[p.muki-1][0];
            p.y += player_muki_table[p.muki-1][1];
            p.img = player_muki_table[p.muki-1][2]+1+(p.cnt/5)%8;
        }
        else {
            p.img = player_muki_table[p.muki-1][2];
        } 
		/*ここまでです*/

		printf("%d",p.walkflag);

		//いけない所だったら
		if( MapData[(int)p.y/64][(int)p.x/64]==0 ){
				p.x=p.oldx; //移動前の座標を代入
				p.y=p.oldy;
		}

		//マップ描画
		for(int y=0;y<CHIP_NUMBER_Y;y++){
			for(int x=0;x<CHIP_NUMBER_X;x++){
				if(MapData[y][x]==1){
					DrawGraph(MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX*(x-y), MAP_PARTS_HSIZEY*(x+y), map,TRUE);
				}
			}
		}
		//プレイヤー描画
		DrawGraph((MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX)+(p.x-p.y)*MAP_PARTS_HSIZEX/VTOP_PARTS_SIZEX - CHAR_PARTS_SIZEX/2
				  ,(p.x+p.y)*MAP_PARTS_HSIZEY/VTOP_PARTS_SIZEY - CHAR_PARTS_SIZEY
				  ,player[p.img],TRUE);
	}

	DxLib_End();

	return 0;
}
そして実行すると動作を停止しましたとなり、ゲームが強制終了してしまいました。
ひとまずデバッグしてみると以下の様なエラーメッセージが出ました。

game2.exe の 0x0057d5e3 でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x33552c30 を読み込み中にアクセス違反が発生しました。

コードを見てみると、ブレークポイントを置く所に矢印があり、
その矢印は以下の様にp.imgの部分を指していました。

コード:

		//プレイヤー描画
		DrawGraph((MAP_VIEW_OFFSET+MAP_PARTS_HSIZEX)+(p.x-p.y)*MAP_PARTS_HSIZEX/VTOP_PARTS_SIZEX - CHAR_PARTS_SIZEX/2
				  ,(p.x+p.y)*MAP_PARTS_HSIZEY/VTOP_PARTS_SIZEY - CHAR_PARTS_SIZEY
→     			  ,player[p.img],TRUE);
	}
そして、p.imgの中を見てみると

p.img|-858993460

p.imgの中にでたらめな数字が入っていました。
どうやらp.imgにちゃんとテーブル配列の数値が入ってないようです。
ためしに以下の様に0を入れ、実行してみた所、

コード:

        if (p.walkflag) {
            p.x += player_muki_table[p.muki-1][0];
            p.y += player_muki_table[p.muki-1][1];
            p.img = player_muki_table[p.muki-1][2]+1+(p.cnt/5)%8;
        }
        else {
            p.img = 0;
        } 
walkflagが建ってない時は、常に正面の立ち画像になりますが、
それ以外は全て特に問題なく動きました。

つまり、問題はフラグが建ってない時の画像処理のようです。

コード:

        if (p.walkflag) {
            p.x += player_muki_table[p.muki-1][0];
            p.y += player_muki_table[p.muki-1][1];
            p.img = player_muki_table[p.muki-1][2]+1+(p.cnt/5)%8;
        }
        else {
            p.img = player_muki_table[p.muki-1][2]; /*この部分が代入できてないみたい?*/
        } 
と、問題の部分を突きとめたのはいいのですけれど、

正直ぼくにはこれの何がいけないのかがさっぱりわかりませんでした……(´Д` ;)

if部分で全く同じ処理ができてるのになぜelseでできんと?
0代入で通るんだから、フラグ関係に問題はないだろうし、もうなにがおこっとるのかよくわかりません……
アドバイスお願いします。

>>タミアさん
アドバイス感謝です。

>>soft屋さん
いつもフォローありがとうございます。

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

Re: ifまみれの移動制御をなんとかしたい

#24

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

p.walkflagが偽の時はp.mukiに代入が行われず、初期状態ではmemsetがあるのでp.muki==0となるはずです。
この状態でplayer_muki_table[p.muki-1][2]にアクセスしようとすると、
範囲外である[-1][2]にアクセスすることになり、アクセス違反になる可能性があります。
また、keyinput_muki_tableの値の範囲に対し、player_muki_tableの要素の数が足りないようです。
ISLeさんの返答を待つか、自分で補完してみてください。

keyinput_muki_tableの0は歩かないことを表すようですね。
最初(pに対するmemsetの次)にp.mukiを4に初期化(4を代入)してみてください。
4にするのは最初に正面の画像を表示するためです。1以上8以下の整数ならOKです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

イマダニ
記事: 145
登録日時: 7年前

Re: ifまみれの移動制御をなんとかしたい

#25

投稿記事 by イマダニ » 6年前

みけCAT さんが書きました: p.walkflagが偽の時はp.mukiに代入が行われず、初期状態ではmemsetがあるのでp.muki==0となるはずです。
この状態でplayer_muki_table[p.muki-1][2]にアクセスしようとすると、
範囲外である[-1][2]にアクセスすることになり、アクセス違反になる可能性があります。
なるほどそういうことだったんですね。
何度もアドバイスありがとうございます。

コード:

	//構造体要素の初期化
	memset(&p,0,sizeof(PLAY));

	p.muki=4;
みけCATさんの言うようにmemsetの後に、p.mukiを初期化した所、
全てが正常に動きました。

皆さんのアドバイスのおかげで最初のぼくのコードがかなり綺麗になりました。
みけCATさんのforで回す適切なやり方や、ISLeさんのテーブルなど
配列の使い方を色々学べました。やはり配列って大事ですね。

ISLeさんの以下のコメントによると、構造体にすると読みやすいとの事なので

コード:

        const int player_muki_table[8][3] = {
            // X増分, Y増分, 静止画像添字 ※構造体にすると可読性が上がる
            { -4,  4,  9 }, // 左
            {  4, -4, 18 }, // 右
            { -6, -6, 27 }, // 上
            {  6,  6,  0 }, // 下
            { -6,  0, 36 }, // 左上
            {  0,  6, 54 }, // 左下
            {  0, -6, 45 }, // 右上
            {  6,  0, 63 }, // 右下
        };
これからはそちらに挑戦してみたいと思います。
今回はこれで解決とします。

みなさんアドバイスありがとうございました。

閉鎖

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