スネークゲーム、伸ばすところがうまくいかない

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

スネークゲーム、伸ばすところがうまくいかない

#1

投稿記事 by cupa » 2年前

コード:

#include "../DxLib/DxLib.h"

#define FIELD_SIZE		20

#define CHIP_SIZE		20

byte mField[ FIELD_SIZE + 2 ][ FIELD_SIZE + 2 ] = {
	//1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19,20,21,22
	{ 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, 0, 0, 0, 0, 0, 0, 0, 1 },//2
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//3
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//4
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//5
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//6
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//7
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//8
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//9
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//10
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//11
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//12
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//13
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//14
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//15
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//16
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//17
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//18
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//19
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//20
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//21
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },//22
};

enum {
	eScene_Game,
	eScene_Clear,
	eScene_GameOver
}eScene = eScene_Game;

int getMinToMaxRand( int min, int max );
int toChipSize( int n );

void Init();
void OnTimer();
void Update();
void Draw();

int mNowClock, mLastClock;
int mPX[ 200 ], mPY[ 200 ], mPMuki, mPLength, mLastPX, mLastPY;
int mMoveX[ 4 ] = { 0, -1, 0, 1 }, mMoveY[ 4 ] = { -1, 0, 1, 0 };
int mFX, mFY, mFoodFlag;
int mOnKey;

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	ChangeWindowMode( TRUE );
	SetDrawScreen( DX_SCREEN_BACK );
	if ( DxLib_Init() == -1 ) return -1;
	
	Init();
	
	mLastClock = GetNowCount();
	while ( ProcessMessage() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 )
	{
		ClearDrawScreen();
		
		OnTimer();
		Draw();
		
		ScreenFlip();
	}
	
	DxLib_End();
	return 0;
}

int getMinToMaxRand( int min, int max ) {
	int r;
	r = GetRand( max - min ) + min;
	return r;
}

int toChipSize( int n ) {
	int cs, s = CHIP_SIZE;
	cs = n / s;
	return cs;
}

void Init() {
	for ( byte i = 0; i < 200; i++ ) {
		mPX[ i ] = 6, mPY[ i ] = 10;
	}
}

void Update() {
	mField[ mPY[ 0 ] ][ mPX[ 0 ] ] = 0;
	
	if ( mFoodFlag != 1 ) {	//もし食べ物がないのなら
		//mField[ mFY ][ mFX ] = 0;	// ①ここでクリアすると1回目はmFYとmFXは0なので、(0,0)の壁が消える
		mFX = getMinToMaxRand( 1, 19 );
		mFY = getMinToMaxRand( 1, 19 );
		mField[ mFY ][ mFX ] = 3;
		mFoodFlag = 1;
	}
	
	if ( mFX == mPX[ 0 ] && mFY == mPY[ 0 ] ) {
		mField[ mFY ][ mFX ] = 0;	// ①当たり判定があったらクリアする
		mPLength++;
		mFoodFlag = 0;
	}

	if ( CheckHitKey( KEY_INPUT_UP		) == 1 ) mOnKey = 0;
	if ( CheckHitKey( KEY_INPUT_LEFT	) == 1 ) mOnKey = 1;
	if ( CheckHitKey( KEY_INPUT_DOWN	) == 1 ) mOnKey = 2;
	if ( CheckHitKey( KEY_INPUT_RIGHT	) == 1 ) mOnKey = 3;

/* ②
	if ( 1 < mPX && toChipSize( FIELD_SIZE - CHIP_SIZE ) < mPX ) {
		mPX += mMoveX[ mOnKey ];
	} else if ( 1 < mPY && toChipSize( FIELD_SIZE - CHIP_SIZE ) < mPY ) {
		mPY += mMoveY[ mOnKey ];
	}
*/

	for ( byte i = 0; i < mPLength; i++ ) {
		mField[ mPY[ i ] + i ][ mPX[ i ] ] = 0;
		mField[ mPY[ i ] ][ mPX[ i ] + i ] = 0;
		mField[ mPY[ i ] - i ][ mPX[ i ] ] = 0;
		mField[ mPY[ i ] ][ mPX[ i ] - i ] = 0;
		switch ( mOnKey ) {
			case 0: if ( mPY[ 0 ] > 0          	&& mField[ mPY[ 0 ] - 1 ][ mPX[ 0 ] ] != 1 ) { mPY[ i ]--; }	break;
			case 2: if ( mPY[ 0 ] < FIELD_SIZE	&& mField[ mPY[ 0 ] + 1 ][ mPX[ 0 ] ] != 1 ) { mPY[ i ]++; }	break;
			case 1: if ( mPX[ 0 ] > 0 			&& mField[ mPY[ 0 ] ][ mPX[ 0 ] - 1 ] != 1 ) { mPX[ i ]--; }	break;
			case 3: if ( mPX[ 0 ] < FIELD_SIZE	&& mField[ mPY[ 0 ] ][ mPX[ 0 ] + 1 ] != 1 ) { mPX[ i ]++; }	break;
		}
		mField[ mPY[ i ] + i ][ mPX[ i ] ] = 2;
		mField[ mPY[ i ] ][ mPX[ i ] + i ] = 2;
		mField[ mPY[ i ] - i ][ mPX[ i ] ] = 2;
		mField[ mPY[ i ] ][ mPX[ i ] - i ] = 2;
		
		mField[ mPY[ i ] ][ mPX[ i ] ] = 2;
	}
}

void OnTimer() {
	mNowClock = GetNowCount();
	if ( mNowClock >= mLastClock + 200 ) {
		mLastClock = mNowClock;
		Update();
	}
}

void Draw() {
	for ( byte y = 0; y < FIELD_SIZE + 2; y++ ) {
		for ( byte x = 0; x < FIELD_SIZE + 2; x++ ) {
			int chip = mField[ y ][ x ];
			char* chipTex[ 4 ] = { " ", "#", "●", "◯" };
			DrawString( x * CHIP_SIZE, y * CHIP_SIZE, chipTex[ chip ], GetColor( 255, 255, 255 ) );
		}
	}
	
	DrawFormatString( 500, 10, GetColor( 255, 255, 255 ), "長さ:%d", mPLength );
}

問題の部分だけ

コード:

for ( byte i = 0; i < mPLength; i++ ) {
		mField[ mPY[ i ] + i ][ mPX[ i ] ] = 0;
		mField[ mPY[ i ] ][ mPX[ i ] + i ] = 0;
		mField[ mPY[ i ] - i ][ mPX[ i ] ] = 0;
		mField[ mPY[ i ] ][ mPX[ i ] - i ] = 0;
		switch ( mOnKey ) {
			case 0: if ( mPY[ 0 ] > 0          	&& mField[ mPY[ 0 ] - 1 ][ mPX[ 0 ] ] != 1 ) { mPY[ i ]--; }	break;
			case 2: if ( mPY[ 0 ] < FIELD_SIZE	&& mField[ mPY[ 0 ] + 1 ][ mPX[ 0 ] ] != 1 ) { mPY[ i ]++; }	break;
			case 1: if ( mPX[ 0 ] > 0 			&& mField[ mPY[ 0 ] ][ mPX[ 0 ] - 1 ] != 1 ) { mPX[ i ]--; }	break;
			case 3: if ( mPX[ 0 ] < FIELD_SIZE	&& mField[ mPY[ 0 ] ][ mPX[ 0 ] + 1 ] != 1 ) { mPX[ i ]++; }	break;
		}
		mField[ mPY[ i ] + i ][ mPX[ i ] ] = 2;
		mField[ mPY[ i ] ][ mPX[ i ] + i ] = 2;
		mField[ mPY[ i ] - i ][ mPX[ i ] ] = 2;
		mField[ mPY[ i ] ][ mPX[ i ] - i ] = 2;
		
		mField[ mPY[ i ] ][ mPX[ i ] ] = 2;
	}
前回の参照魚さんの回答で壁との当たり判定と動くところ、バグの修正まではできたのですが、肝心の餌を食べたら蛇が伸びるところがうまくいきません。

はじめは、mPX, mPYは配列ではなかったのですが、0番目は頭、1番以降は餌を食べたときに追加される胴体、というふうにしようと配列にしました。
配列の中に配列と、ややこしくなってしまい、参照魚さんが示してくれたコードと入り交じってよくわからなくってしまいました・・・

一つ一つやるたびに躓くのですが・・・今回もよろしくおねがいします。

cupa
記事: 117
登録日時: 2年前

Re: スネークゲーム、伸ばすところがうまくいかない

#2

投稿記事 by cupa » 2年前

コードの説明を簡潔にすると、はじめのところで前回の座標をクリア(削除)して、押されたキーによって移動方向を変え、それが動けるところならば動かす。最後のところで、新しくなった座標に書き込み、それを蛇の長さだけ繰り返す。です。

参照魚
記事: 109
登録日時: 6年前

Re: スネークゲーム、伸ばすところがうまくいかない

#3

投稿記事 by 参照魚 » 2年前

前提として気になるところとして下記を見直した方がよいかと思います。

コード:

#define FIELD_SIZE		(20+2) // 壁も含めてフィールドサイズとみなす
byte mField[ FIELD_SIZE ][ FIELD_SIZE] = {...}; // ↑ここにあわせて+2は取る

// フィールドの種類を数値で直接記載しないで抽象化する
enum {
	FILED_NONE,
	FILED_WALL,
	FILED_FOOD,
	FILED_SNAKE,
};
状態の更新と描画のため処理がUpdateの中に混在しています。UpdateではmFiledの変更は行わず、蛇とフードの座標の更新のみ行います。DrawではいったんmFiledを(壁以外)全クリアして、Updateで更新した蛇とフードの座標を参照してmFiledを更新・描画します。

コード:

// 移動可能な場所がチェック
bool FiledCheck( int x, int y ){

	if ( ( 0 <= x && x < FIELD_SIZE ) &&
		 ( 0 <= y && y < FIELD_SIZE ) ) {
		switch ( mField[ y ][ x ] ) {
		case FILED_NONE : return true;
		case FILED_WALL : return false;
		case FILED_SNAKE: return true;
		case FILED_FOOD : return true;
		}
	}
	return false;
}

void Update() {
	if ( mFoodFlag != true ) {
		mFoodFlag = true;
		do {
			mFX = getMinToMaxRand( 1, FIELD_SIZE-1 );
			mFY = getMinToMaxRand( 1, FIELD_SIZE-1 );
		} while ( mField[ mFY ][ mFX ] != FILED_NONE ); // 何もないところでなければやり直す
	}

	if ( mFX == mPX[0] && mFY == mPY[0] ) {
		mFoodFlag = false;
		mPX[mPLength] = mPX[mPLength-1];  // 新パーツはそれまでの最後のパーツと同じ位置に追加
		mPY[mPLength] = mPY[mPLength-1]; // ↑進行方向とか考慮すると面倒なので手抜き
		mPLength++;
	}

	if ( CheckHitKey( KEY_INPUT_UP	) == 1 ) mOnKey = 0;
	if ( CheckHitKey( KEY_INPUT_LEFT	) == 1 ) mOnKey = 1;
	if ( CheckHitKey( KEY_INPUT_DOWN	) == 1 ) mOnKey = 2;
	if ( CheckHitKey( KEY_INPUT_RIGHT	) == 1 ) mOnKey = 3;

	// 先頭のパーツの座標を保存しておく	
	int	px = mPX[0];
	int	py = mPY[0];

	// 先頭のパーツの座標はいじらない(★で使うから)
	switch ( mOnKey ) {
	case 0: if ( FiledCheck( px,    py-1  ) ) { py--;	}	break;
	case 2: if ( FiledCheck( px,    py+1 ) ) { py++;	}	break;
	case 1: if ( FiledCheck( px-1, py    ) ) { px--;	}	break;
	case 3: if ( FiledCheck( px+1, py    ) ) { px++;	}	break;
	}

	// ★座標を後ろのパーツから更新(ひとつ前のパーツの座標にする)
	for ( auto i = mPLength-1; i; --i ) {
		mPX[i] = mPX[i-1];
		mPY[i] = mPY[i-1];
	}
	// 更新された座標は最後に先頭のパーツにセット
	mPX[0] = px;
	mPY[0] = py;
}

void Draw() {
	// フィールド全体をスキャンして壁以外をクリア
	for ( auto y = 0; y < FIELD_SIZE; y++ ) {
		for ( auto x = 0; x < FIELD_SIZE; x++ ) {
			if ( mField[y][x] != FILED_WALL ) {
				mField[y][x] = FILED_NONE;
			}
		}
	}
	
	// 蛇部分をセット
	mField[ mPY[0] ][ mPX[0] ] = FILED_SNAKE;		// 先頭
	for ( auto i = 1; i < mPLength; i++ ) {
		mField[ mPY[i] ][ mPX[i] ] = FILED_SNAKE;		// 伸びた部分
	}

	// フード部分をセット
	if ( mFoodFlag ) {
		mField[ mFY ][ mFX ] = FILED_FOOD;
	}
	
	// 描画
	for ( int y = 0; y < FIELD_SIZE; y++ ) {
		for ( int x = 0; x < FIELD_SIZE; x++ ) {
			int chip = mField[ y ][ x ];
			const char* chipTex[ 4 ] = { " ", "#", "●", "◯" };

			DrawString( x * CHIP_SIZE, y * CHIP_SIZE, chipTex[ chip ], GetColor( 255, 255, 255 ) );
		}
	}
}
上記は自分自身のパーツも貫通してしまう仕様ですが、まずは単純に伸びていくところを確実に実装してください。

cupa
記事: 117
登録日時: 2年前

Re: スネークゲーム、伸ばすところがうまくいかない

#4

投稿記事 by cupa » 2年前

回答ありがとうございます。

コード:

#include "../DxLib/DxLib.h"

#define FIELD_SIZE		20 + 2

#define CHIP_SIZE		20

byte mField[ FIELD_SIZE ][ FIELD_SIZE ] = {
	//1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19,20,21,22
	{ 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, 0, 0, 0, 0, 0, 0, 0, 1 },//2
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//3
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//4
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//5
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//6
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//7
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//8
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//9
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//10
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//11
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//12
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//13
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//14
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//15
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//16
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//17
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//18
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//19
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//20
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },//21
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },//22
};

enum {
	eScene_Game,
	eScene_Clear,
	eScene_GameOver
}eScene = eScene_Game;

//フィールドの種類を数値で直接記載しないで抽象化する
enum {
	FILED_NONE,
	FILED_WALL,
	FILED_FOOD,
	FILED_SNAKE,
};

int getMinToMaxRand( int min, int max );
int toChipSize( int n );

void Init();
void OnTimer();
bool FieldCheck( int x, int y );
void Update();
void Draw();

int mNowClock, mLastClock;
int mPX[ 200 ], mPY[ 200 ], mPMuki, mPLength, mLastPX, mLastPY;
int mMoveX[ 4 ] = { 0, -1, 0, 1 }, mMoveY[ 4 ] = { -1, 0, 1, 0 };
int mFX, mFY;
bool mFoodFlag;
int mOnKey;

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	ChangeWindowMode( TRUE );
	SetDrawScreen( DX_SCREEN_BACK );
	if ( DxLib_Init() == -1 ) return -1;
	
	Init();
	
	mLastClock = GetNowCount();
	while ( ProcessMessage() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 )
	{
		ClearDrawScreen();
		
		OnTimer();
		
		ScreenFlip();
	}
	
	DxLib_End();
	return 0;
}

int getMinToMaxRand( int min, int max ) {
	int r;
	r = GetRand( max - min ) + min;
	return r;
}

int toChipSize( int n ) {
	int cs, s = CHIP_SIZE;
	cs = n / s;
	return cs;
}

void Init() {
	for ( byte i = 0; i < 200; i++ ) {
		mPX[ i ] = 6, mPY[ i ] = 10;
	}
}

// 移動可能な場所がチェック
bool FieldCheck( int x, int y ){

	if ( ( 0 <= x && x < FIELD_SIZE ) &&
		 ( 0 <= y && y < FIELD_SIZE ) ) {
		switch ( mField[ y ][ x ] ) {
		case FILED_NONE : return true;
		case FILED_WALL : return false;
		case FILED_SNAKE: return true;
		case FILED_FOOD : return true;
		}
	}
	return false;
}

void Update() {
	if ( mFoodFlag != true ) {
		mFoodFlag = true;
		do {
			mFX = getMinToMaxRand( 1, FIELD_SIZE-1 );
			mFY = getMinToMaxRand( 1, FIELD_SIZE-1 );
		} while ( mField[ mFY ][ mFX ] != FILED_NONE );//何もないところでなければやり直す
	}

	if ( mFX == mPX[0] && mFY == mPY[0] ) {
		mFoodFlag = false;
		mPX[mPLength] = mPX[mPLength-1];	//新パーツはそれまでの最後のパーツと同じ位置に追加
		mPY[mPLength] = mPY[mPLength-1];	//↑進行方向とか考慮すると面倒なので手抜き
		mPLength++;
	}

	if ( CheckHitKey( KEY_INPUT_UP	) == 1 ) mOnKey = 0;
	if ( CheckHitKey( KEY_INPUT_LEFT	) == 1 ) mOnKey = 1;
	if ( CheckHitKey( KEY_INPUT_DOWN	) == 1 ) mOnKey = 2;
	if ( CheckHitKey( KEY_INPUT_RIGHT	) == 1 ) mOnKey = 3;

	//先頭のパーツの座標を保存しておく	
	int	px = mPX[0];
	int	py = mPY[0];

	//先頭のパーツの座標はいじらない(★で使うから)
	switch ( mOnKey ) {
	case 0: if ( FieldCheck( px,    py-1  ) ) { py--;	}	break;
	case 2: if ( FieldCheck( px,    py+1 ) ) { py++;	}	break;
	case 1: if ( FieldCheck( px-1, py    ) ) { px--;	}	break;
	case 3: if ( FieldCheck( px+1, py    ) ) { px++;	}	break;
	}

	//★座標を後ろのパーツから更新(ひとつ前のパーツの座標にする)
	for ( auto i = mPLength-1; i; --i ) {
		mPX[ i ] = mPX[ i - 1 ];
		mPY[ i ] = mPY[ i - 1 ];
	}
	//更新された座標は最後に先頭のパーツにセット
	mPX[ 0 ] = px;
	mPY[ 0 ] = py;
}

void Draw() {
	//フィールド全体をスキャンして壁以外をクリア
	for ( auto y = 0; y < FIELD_SIZE; y++ ) {
		for ( auto x = 0; x < FIELD_SIZE; x++ ) {
			if ( mField[ y ][ x ] != FILED_WALL ) {
				mField[ y ][ x ] = FILED_NONE;
			}
		}
	}
	
	//蛇部分をセット
	mField[ mPY[0] ][ mPX[0] ] = FILED_SNAKE;		// 先頭
	for ( auto i = 1; i < mPLength; i++ ) {
		mField[ mPY[i] ][ mPX[i] ] = FILED_SNAKE;		// 伸びた部分
	}

	//フード部分をセット
	if ( mFoodFlag ) {
		mField[ mFY ][ mFX ] = FILED_FOOD;
	}
	
	//描画
	for ( int y = 0; y < FIELD_SIZE; y++ ) {
		for ( int x = 0; x < FIELD_SIZE; x++ ) {
			int chip = mField[ y ][ x ];
			const char* chipTex[ 4 ] = { " ", "#", "●", "◯" };

			DrawString( x * CHIP_SIZE, y * CHIP_SIZE, chipTex[ chip ], GetColor( 255, 255, 255 ) );
		}
	}
}

void OnTimer() {
	mNowClock = GetNowCount();
	if ( mNowClock >= mLastClock + 200 ) {
		mLastClock = mNowClock;
		Update();
		Draw();
	}
}


どこでUpdate()、Draw()を呼べばいいのでしょうか?
OnTimer()内で呼んでいるのですが、それで実行するとウィンドウが一瞬で閉じてしまいます

アバター
usao
記事: 1887
登録日時: 11年前

Re: スネークゲーム、伸ばすところがうまくいかない

#5

投稿記事 by usao » 2年前

> 状態の更新と描画のため処理がUpdateの中に混在しています。UpdateではmFiledの変更は行わず…

mField って,そもそも「描画のための」データなのでしょうか?

ちょっと前に
「そのデータは何の座標系の値なのか?」と問うた気がしますが,同様に
「mField って何のためのデータなの? 役割は何なの?」というのをもっときちっとした方が良いように見えます.


壁の有無の判定に専ら mField が用いられているのであれば,その点では mField とはロジック側の存在なのであって,少なくとも「描画のためだけのデータ」ではないものと見えますが,
もしも描画に際して参照するための存在なのだとしたら,描画の度に毎度 mField を弄るというのは馬鹿馬鹿しいと思えます.(私ならそのデータの更新は Update() の側こそふさわしいと考えます.)

というかそれ以前に,いちいち 【mField に値を入れて → それを参照する】
という,間に mField を挟む行為自体が意味不明なのでそこを見直すべきではないのでしょうか?
(コンソールアプリみたく出力処理の自由度に著しい制限があるのでもないのでしょうし)

アバター
usao
記事: 1887
登録日時: 11年前

Re: スネークゲーム、伸ばすところがうまくいかない

#6

投稿記事 by usao » 2年前

そもそも mField とかいうデータ,必要ですか? 無くても何も問題ないように思うのですが.

……って言われたら,それに何と答える(反論する)のでしょう?

もしもその答えが将来の課題の話になるようであれば,そこは一旦忘れて,まずは「基本動作をまともにやれるだけのもの」という目標だけに注力するステップを設けた方が楽なのでは.

例えば,「後々,いろんな形の壁を作りたいのだ」とかいう話があるのだとしても,そのことを基本動作もおぼつかない今の時点からサポートしようとして「二兎を追う者は…」な状態に陥っていないか?っていう.
逃げない兎を相手にしているのなら一匹(一羽?)ずつ狙っていくのが早いのでは.

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

Re: スネークゲーム、伸ばすところがうまくいかない

#7

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

cupa さんが書きました:
2年前
OnTimer()内で呼んでいるのですが、それで実行するとウィンドウが一瞬で閉じてしまいます
このような場合、バグにより強制終了になっていることを疑うべきですね。

今回の場合、mPLength がグローバル変数のデフォルト値である0のままUpdate関数を実行しているため、

コード:

	//★座標を後ろのパーツから更新(ひとつ前のパーツの座標にする)
	for ( auto i = mPLength-1; i; --i ) {
の部分で i が -1 からループを開始するために範囲外へのアクセスが発生し、
i の値が十分小さくなるとアクセス先が有効なメモリ領域を外れてしまい、強制終了になることがあるようです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
usao
記事: 1887
登録日時: 11年前

Re: スネークゲーム、伸ばすところがうまくいかない

#8

投稿記事 by usao » 2年前

オフトピック
mPX[], mPY[] の履歴に関しては,
内容をいちいちバケツリレーみたく更新するんじゃなくてリングバッファ扱いするのが楽だと思う

cupa
記事: 117
登録日時: 2年前

Re: スネークゲーム、伸ばすところがうまくいかない

#9

投稿記事 by cupa » 2年前

usaoさん、変数の命名や説明不足で申し訳ございません。

私はまだ初心者で、そのあたりがおろそかになってしまうことがよくあります。

>そもそも mField とかいうデータ,必要ですか? 無くても何も問題ないように思うのですが.

すみません。まだこのやり方しかわからないのでこのやり方でやっているのですが、他の最適な方法があるのなら教えてもらえると助かります。
({...},
{...}, これで初期化しているのが無駄ということでしょうか?それならFOR文で回せばいいというはわかるのですが・・・)

アバター
usao
記事: 1887
登録日時: 11年前

Re: スネークゲーム、伸ばすところがうまくいかない

#10

投稿記事 by usao » 2年前

オフトピック

> 他の最適な方法があるのなら教えてもらえると助かります。

そういうことを言いたいのではなくて,
自身が用意したデータの必要性とか役割とか使い方等に関して,もっとこう強い意志というか考えを持って「こうなのだから→こう書くのだ」という明確な筋道に沿ってプログラミングを行うべきなんじゃないのだろうか?
…っていうような話をしている.

こうなるべき/こうではないべき という判断基準があなたの中にちゃんと存在していて,それに基づいた判断が行わていれば

> 参照魚さんが示してくれたコードと入り交じってよくわからなくってしまいました・・・

なんてことにならないんじゃないかな,とか思うわけ.

あなたが考えている方法論が何らかの意味で良かろうが悪かろうが,とにかく「その方法論の上ではこうであるべき」っていうのがあるよね,っていう.

ざっくり言えば,

> 一つ一つやるたびに躓く

っていうのは,自身で把握できないものを書いてるからじゃないのか?っていう.
であれば,話を把握してから書いたらいいんじゃない?

アバター
usao
記事: 1887
登録日時: 11年前

Re: スネークゲーム、伸ばすところがうまくいかない

#11

投稿記事 by usao » 2年前

> まだこのやり方しかわからないのでこのやり方でやっている

というのは全くOK.

あなたがいう「このやり方」の詳細~全容まで をあなた自身がしっかりと把握しているのだろうか?
というのが疑問というか怪しいように見えるのだけど大丈夫か? ということ.
プログラムは詳細まで具体的に処理を書かなきゃならんわけなので.

参照魚
記事: 109
登録日時: 6年前

Re: スネークゲーム、伸ばすところがうまくいかない

#12

投稿記事 by 参照魚 » 2年前

Init()でmPLength=1;してください。書き忘れてました。

アバター
usao
記事: 1887
登録日時: 11年前

Re: スネークゲーム、伸ばすところがうまくいかない

#13

投稿記事 by usao » 2年前

オフトピック
わからんもの は わからん.そんなの仕方ない.

ただ,わからないもの を わからないままで 取り込んでいくと
コードのわからん具合がどんどん膨れていってしまうのではなかろうか.
「さっぱりわからんけども現時点で何故か動く」状態と化したコードが手に入ったとして
そこから先を自分でやっていけるのか?

…みたいなことを勝手に思ったんだけど,余計な話だったな.
混乱させる意図があったわけじゃないし
目の前の問題点に即応する内容の話でもないので, 放置/無視 してくれてOK.

---

「mFieldが要るのか?」という話については…
【「四角いフィールドの外周部にしか壁が無い」という世界だけをとりあえず扱うということで良いのならば】,

・壁の判定に関しては「座標値だけから壁か否かを判定する」ことが可能だよね.
 (その世界では (0,0) は壁だろうけど,(1,1)は壁じゃないはず…みたいな.それだけのこと.)
・描画に際しては,蛇や餌の座標値は mField とは別に存在しているのだから,そっちの値を参照すれば実施できる.

つまり,mFIield には特に(これ以外の用途が無いのであれば)役割が無い,つまり不要ってことになる.

cupa
記事: 117
登録日時: 2年前

Re: スネークゲーム、伸ばすところがうまくいかない

#14

投稿記事 by cupa » 2年前

usaoさん、詳しい話までありがとうございます。勉強になりました。

アバター
usao
記事: 1887
登録日時: 11年前

Re: スネークゲーム、伸ばすところがうまくいかない

#15

投稿記事 by usao » 2年前

オフトピック
これ以上どうでもいい話をここには書かない.
こっちに(もっと毒がある感じで)書いてるので,気になるならどうぞ.
(一応,私が思うスネークゲームの基礎部分の実装も書いてみた)
blog/7311

返信

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