スコアの実装について

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

スコアの実装について

#1

投稿記事 by ariant » 14年前

こんにちは、

現在DXライブラリ置き場というサイトの
、サンプルプログラムの10の落ちものプログラムに、
17のプログラムにあったカウントをするプログラムを使えないかと思い実装しようとしています。

色がそろった時に100ポイントずつポイントを増やしていくようにしたいと思っています。

コード:

#include "DxLib.h"
#include <stdio.h>	// ファイル操作に必要なヘッダファイル
#include <string.h>	// 文字列操作に必要なヘッダファイル


#define BLOCKTYPE_NUM	5	// ブロックの種類の数

#define BLOCK_SIZE		24	// ブロックのドットサイズ
#define WORLD_WIDTH		8	// ステージの幅
#define WORLD_HEIGHT	16	// ステージの高さ

#define STAGE_X	210	// ステージの左上頂点のX座標
#define STAGE_Y	50	// ステージの左上頂点のY座標

#define WAIT	500	// 黙っててブロックが落ちるまでの時間

// ステージデータ
char Block[ WORLD_WIDTH ][ WORLD_HEIGHT ] ;		// 実際のデータ
char BufferBlock[ WORLD_WIDTH ][ WORLD_HEIGHT ] ;	// 一時状態保存用ブロックデータ

// アクティブブロックデータ
int ActiveX , ActiveY ;	// アクティブブロックの一番下のブロックの位置
char ActiveBlock[ 3 ] ;	// アクティブなブロックのデータ

// カウンター
int WaitCounter ;	// 下に勝手に落とすまでの時間計測用
int NowTime ;	// 現在のフレームで経過した時間
int OldTime ;	// 前のフレームのときにGetNowCount関数で得たタイム

// ブロックの種類ごとの色データ
int BlockColor[ 5 ][ 3 ] =
{
	{ 0 , 0 , 255 } , { 255 , 0 , 0 } ,{ 255 , 255 , 0 } ,
	{ 0 , 255 , 0 } , { 102 , 51 , 0 } 
} ;


void InitGame( void ) ;				// ゲームの初期化
void CreateNewActiveBlock( void ) ;		// 新しいブロックの生成
int KeyInput( void ) ;				// キー入力処理
int TimeFunc( void ) ;				// 時間関係処理
int MoveActiveBlock( int MoveX , int MoveY ) ;	// アクティブブロックの移動
int CheckHitActiveBlock( int x , int y ) ;	// アクティブブロックが画面上のブロックに当たっていないか調べる
int LockActiveBlock( int x , int y ) ;		// アクティブブロックを固定する及び次のブロックを出すもし次のブロックを出すスペースがなかったらゲームオーバー
void GameOver( void ) ;				// ゲームオーバー処理
int CheckEliminatBlock( void ) ;		// 消えるブロックがあるか調べてあったら消す処理をする
void InitBufferBlock( void ) ;			// 一時使用用ブロックデータの初期化
int CheckEliminatBlockToOne( int x , int y ) ;	// 特定ブロックが消えるか探索
int ScreenDraw( void ) ;			// 画面描画処理関数



void DrawNum( int x , int y , int Num ) ;	// 数値を画面に表示する関数





// WinMain関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
		 LPSTR lpCmdLine, int nCmdShow )
{
   ChangeWindowMode(TRUE);//ウィンドウモード

	SetGraphMode( 640 , 480 , 16 ) ;
	if( DxLib_Init() == -1 )	// DXライブラリ初期化処理
	{
		 return -1;				// エラーが起きたら直ちに終了
	}

	// ゲームを初期化
	InitGame() ;

	// 描画先画面を裏画面にセット
	SetDrawScreen( DX_SCREEN_BACK ) ;

	// メインループ
	while( ProcessMessage() == 0 )
	{


		// キー入力処理
		KeyInput() ;

		// 時間経過処理
		TimeFunc() ;

		// 画面描画
		ScreenDraw() ;

		// 裏画面の内容を表画面に反映させる
		ScreenFlip() ;
	}

	// DXライブラリの終了
	DxLib_End() ;

	// 終了
	return 0 ;
}





// ゲームの初期化
void InitGame( void ) 
{
	int i , j ;

	// 前回時間をセット
	OldTime = GetNowCount() ;

	// アクティブブロックの位置をセット
	ActiveX = WORLD_WIDTH / 2 ;
	ActiveY = 2 ;

	// アクティブブロックを生成
	CreateNewActiveBlock() ;

	// マップブロックの初期化
	for( i = 0 ; i < WORLD_HEIGHT ; i ++ )
		for( j = 0 ; j < WORLD_WIDTH ; j ++ )
			Block[ j ][ i ] = 0 ;
}

// 新しいブロックの生成
void CreateNewActiveBlock( void )
{
	int i ;

	// ランダムに3つブロックをセット
	for( i = 0 ; i < 3 ; i ++ )
		ActiveBlock[ i ] = GetRand( BLOCKTYPE_NUM - 1 ) + 1 ;
}

// キー入力処理
int KeyInput( void )
{
	int Key ;	// 入力されたキー
	static int OldKey ;	// 前フレームで取得したキー情報

	// キー入力を得る
	Key = GetJoypadInputState( DX_INPUT_KEY_PAD1 ) ;

	// キー入力に応じて処理をする
	if( Key & PAD_INPUT_DOWN )		MoveActiveBlock( 0 , 1 ) ;
	if( ( Key & ~OldKey ) & PAD_INPUT_LEFT && ActiveX > 0 )	MoveActiveBlock( -1 , 0 ) ;
	if( ( Key & ~OldKey ) & PAD_INPUT_RIGHT && ActiveX < WORLD_WIDTH - 1 )	MoveActiveBlock( 1 , 0 ) ;

	if( ( Key & ~OldKey ) & PAD_INPUT_A )
	{
		int TempBlock ;

		// アクティブブロックの配置を変更する
		TempBlock = ActiveBlock[ 2 ] ; ActiveBlock[ 2 ] = ActiveBlock[ 0 ] ; ActiveBlock[ 0 ] = TempBlock ;
		TempBlock = ActiveBlock[ 0 ] ; ActiveBlock[ 0 ] = ActiveBlock[ 1 ] ; ActiveBlock[ 1 ] = TempBlock ;
	}
	OldKey = Key ;

	// 終了
	return 0 ;
}

// 時間関係処理
int TimeFunc( void )
{
	int Time ;

	// 現在の時間を得る
	Time = GetNowCount() ;

	// 今フレームで経過した時間を得る
	NowTime = Time - OldTime ;

	// 現在の時間を保存
	OldTime = Time ; 

	// ウエイトカウンタに経過時間を加算する
	WaitCounter += NowTime ;

	// 一定時間が経過していたら勝手に下にブロックを落す
	if( WaitCounter > WAIT )
	{
		MoveActiveBlock( 0 , 1 ) ;

		// カウンターを0に戻す
		WaitCounter = 0 ;
	}

	// 終了
	return 0 ;
}

// アクティブブロックの移動
int MoveActiveBlock( int MoveX , int MoveY )
{
	int NewX , NewY ;

	// 移動後の座標をセットする
	NewX = MoveX + ActiveX ;
	NewY = MoveY + ActiveY ;

	// 左右移動の処理
	if( MoveX != 0 && NewX >= 0 && NewX < WORLD_WIDTH )
	{
		// 各3つのブロックが画面上のブロックに当たっていないか調べる
		if( CheckHitActiveBlock( NewX , NewY ) == - 1 )
		{
			// あたっていたら左右移動を無効にする
			MoveX = 0 ;
		}
	}

	// 上下移動の処理
	if( MoveY != 0 )
	{
		// 画面の一番下のブロック位置まで来ていたらブロックを固定させる
		if( NewY >= WORLD_HEIGHT )
		{
			LockActiveBlock( ActiveX , ActiveY ) ;

			// 移動を無効にする
			MoveY = 0 ;
		}
		else
		// 各3つのブロックが画面上のブロックに当たっていないか調べる
		if( CheckHitActiveBlock( NewX , NewY ) == - 1 )
		{
			// あたっていたらブロックを固定する
			LockActiveBlock( ActiveX , ActiveY ) ;

			// 移動を無効にする
			MoveY = 0 ;
		}
	}

	// 座標を移動する
	ActiveX += MoveX ;
	ActiveY += MoveY ;

	// 終了
	return 0 ;
}

// アクティブブロックが画面上のブロックに当たっていないか調べる
int CheckHitActiveBlock( int x , int y )
{
	int i ;

	// 3つあるブロックがそれぞれ画面上のブロックに当たっていないか調べる
	for( i = 0 ; y - i >= 0 && i < 3 ; i ++ )
	{
		// 当たっていたらここで終了
		if( Block[ x ][ y - i ] != 0 ) return -1 ;
	}

	// 当たっていない場合だけ0を返す
	return 0 ;
}

// アクティブブロックを固定する
// 及び次のブロックを出す
// もし次のブロックを出すスペースがなかったらゲームオーバー
int LockActiveBlock( int x , int y )
{
	int i ;

	for( i = 0 ; i < 3 ; i ++ )
	{
		// 画面上から外れている場合はセットしない
		if( y - i < 0 ) continue ;

		// ブロックの固定
		Block[ x ][ y - i ] = ActiveBlock[ i ] ;
	}

	// 消せるブロックがある場合は消す
	CheckEliminatBlock() ;

	// 新しいブロックをセット
	{
		// アクティブブロックの位置をセット
		ActiveX = WORLD_WIDTH / 2 ;
		ActiveY = 2 ;

		// 新しいアクティブブロックを生成
		CreateNewActiveBlock() ;

		// 次に出そうとしているスペースがなかったらゲームオーバー処理
		for( i = 0 ; i < 3 ; i ++ )
		{
			if( Block[ ActiveX ][ ActiveY - i ] != 0 ) GameOver() ;
		}
	}

	// カウンタリセット
	WaitCounter = 0 ;

	// 時間待ち
	WaitTimer( 200 ) ;

	// 終了
	return 0 ;
}

// ゲームオーバー処理
void GameOver( void ) 
{
	// 画面中心にゲームオーバーを表示
	ScreenDraw() ;
	DrawString( 300 , 220 , "GameOver" , GetColor( 255 , 255 , 255 ) ) ;
	ScreenFlip() ;

	// キー入力待ち
	WaitKey() ;

	// DXライブラリ終了
	DxLib_End() ;

	// ソフト終了
	exit( -1 ) ;
}

// 消えるブロックがあるか調べてあったら消す処理をする
int CheckEliminatBlock( void )
{
	int i , j , k;	// 汎用変数
	int ClsFlag ; // 一つでも消せたブロックがあったか、のフラグ

	
	int Counter;
	Counter = 0 ;			// カウンターを初期化

	do{
		// 一時使用用ブロックデータを初期化
		InitBufferBlock() ; 

		// 消せたブロックがあるか、フラグを倒す
		ClsFlag = FALSE ;

		// 各ブロックが消えるか調べる
		for( i = 0 ; i < WORLD_HEIGHT ; i ++ )
		{
			for( j = 0 ; j < WORLD_WIDTH ; j ++ )
			{
				// もしブロックがない場合は次に移る
				if( Block[ j ][ i ] == 0 ) continue ;

				// ブロックが消えるかどうか調べて調査結果をバッファに保存する
				BufferBlock[ j ][ i ] = CheckEliminatBlockToOne( j , i ) ;
			}
		}

		// 消えると判断されたブロックを消す
		for( i = 0 ; i < WORLD_HEIGHT ; i ++ )
		{
			for( j = 0 ; j < WORLD_WIDTH ; j ++ )
			{
				if( BufferBlock[ j ][ i ] == 1 )
				{
					ClsFlag = TRUE ;
					Block[ j ][ i ] = 0 ;
					

					//100点ずつ追加
					Counter += 100 ;

			// カウンタ値を表示
			DrawNum( 550 , 120 , Counter ) ;
				}
			}
		}



		// 空きを積める
		for( i = WORLD_HEIGHT - 2 ; i > -1 ; i -- )
		{
			for( j = 0 ; j < WORLD_WIDTH ; j ++ )
			{
				if( Block[ j ][ i ] != 0 )
				{
					for( k = i + 1 ; k < WORLD_HEIGHT && Block[ j ][ k ] == 0 ; k ++ ){}
					k -- ;
					
					if( k != i )
					{
						Block[ j ][ k ] = Block[ j ][ i ] ;
						Block[ j ][ i ] = 0 ;
					}
				}
			}
		}

	}while( ClsFlag ) ;	// 消せたブロックがあった場合再度チェック

	// 終了
	return 0 ;
}

// 一時使用用ブロックデータの初期化
void InitBufferBlock( void )
{
	int i , j ;

	for( i = 0 ; i < WORLD_HEIGHT ; i ++ )
	{
		for( j = 0 ; j < WORLD_WIDTH ; j ++ )
		{
			BufferBlock[ j ][ i ] = 0 ;
		}
	}
}

// 特定ブロックが消えるか探索
int CheckEliminatBlockToOne( int x , int y )
{
	int CheckBlock ;
	int i ;
	int BlockNum ;

	// チェックするブロックの種類を保存
	CheckBlock = Block[ x ][ y ] ;


	// 左右にどれだけつながっているか調べる
	for( i = 0 ; x + i >= 0 && Block[ x + i ][ y ] == CheckBlock ; i -- ){}
	i ++ ;
	for( BlockNum = 0 ; x + i < WORLD_WIDTH && Block[ x + i ][ y ] == CheckBlock ; BlockNum ++ , i ++ ){}

	// 3つ以上つながっていたらここで終了
	if( BlockNum >= 3 ) return 1 ;

	
	// 上下にどれだけつながっているか調べる
	for( i = 0 ; y + i >= 0 && Block[ x ][ y + i ] == CheckBlock ; i -- ){}
	i ++ ;
	for( BlockNum = 0 ; y + i < WORLD_HEIGHT && Block[ x ][ y + i ] == CheckBlock ; BlockNum ++ , i ++ ){}

	// 3つ以上つながっていたらここで終了
	if( BlockNum >= 3 ) return 1 ;


	// 左上から右下にかけて繋がっている数を調べる
	for( i = 0 ; y + i >= 0 && x + i >= 0 && Block[ x + i ][ y + i ] == CheckBlock ; i -- ){}
	i ++ ;
	for( BlockNum = 0 ; x + i < WORLD_WIDTH && y + i < WORLD_HEIGHT && Block[ x + i ][ y + i ] == CheckBlock ; BlockNum ++ , i ++ ){}

	// 3つ以上つながっていたらここで終了
	if( BlockNum >= 3 ) return 1 ;


	// 右上から左下にかけて繋がっている数を調べる
	for( i = 0 ; y + i >= 0 &&  x - i < WORLD_WIDTH && Block[ x - i ][ y + i ] == CheckBlock ; i -- ){}
	i ++ ;
	for( BlockNum = 0 ; x - i >= 0 && y + i < WORLD_HEIGHT && Block[ x - i ][ y + i ] == CheckBlock ; BlockNum ++ , i ++ ){}

	// 3つ以上つながっていたらここで終了
	if( BlockNum >= 3 ) return 1 ;


	// ここまで来ていたら消えない
	return 0 ;
}

// 画面描画処理関数
int ScreenDraw( void )
{
	int i , j , k ;
int Color ;	// 文字の色コード

// 白色コードを取得
	Color = GetColor( 255 , 255 , 255 ) ;

	// 画面を初期化
	ClearDrawScreen() ;


	
	// カウント値表示
		DrawString( 460 , 120 , "COUNT" , Color ) ;
		DrawNum( 550 , 120 , 0 ) ;



	// 枠を描画
	DrawBox( STAGE_X - 25 , STAGE_Y , STAGE_X ,
		STAGE_Y + WORLD_HEIGHT * BLOCK_SIZE ,
		GetColor( 255 , 255 , 255 ) , TRUE ) ;

	DrawBox( STAGE_X + WORLD_WIDTH * BLOCK_SIZE , STAGE_Y ,
		STAGE_X + 24 + WORLD_WIDTH * BLOCK_SIZE , STAGE_Y + WORLD_HEIGHT * BLOCK_SIZE ,
		GetColor( 255 , 255 , 255 ) , TRUE ) ;

	DrawBox( STAGE_X - 25 , STAGE_Y + WORLD_HEIGHT * BLOCK_SIZE ,
		STAGE_X + 25 + WORLD_WIDTH * BLOCK_SIZE , STAGE_Y + WORLD_HEIGHT * BLOCK_SIZE + 25 ,
		GetColor( 255 , 255 , 255 ) , TRUE ) ;

	// ブロックを描画
	for( i = 0 ; i < WORLD_HEIGHT ; i ++ )
	{
		for( j = 0 ; j < WORLD_WIDTH ; j ++ )
		{
			if( Block[ j ][ i ] != 0 )
			{
				k = Block[ j ][ i ] - 1 ;
				DrawBox( STAGE_X +j * BLOCK_SIZE , STAGE_Y + BLOCK_SIZE * i ,
					STAGE_X +j * BLOCK_SIZE + BLOCK_SIZE , STAGE_Y + i * BLOCK_SIZE + BLOCK_SIZE ,
					GetColor( BlockColor[ k ][ 0 ] ,BlockColor[ k ][ 1 ] ,BlockColor[ k ][ 2 ] ) , TRUE ) ;
			}
		}
	}

	// アクティブブロックを描画
	for( i = 0 ; i + ActiveY >= 0 && i < 3 ; i ++ )
	{
		k = ActiveBlock[ i ] - 1 ;

		DrawBox( STAGE_X + ActiveX * BLOCK_SIZE , STAGE_Y + ( ActiveY - i ) * BLOCK_SIZE , 
				STAGE_X + ActiveX * BLOCK_SIZE + BLOCK_SIZE , STAGE_Y + ( ActiveY - i ) * BLOCK_SIZE + BLOCK_SIZE ,
				GetColor( BlockColor[ k ][ 0 ] ,BlockColor[ k ][ 1 ] ,BlockColor[ k ][ 2 ] ) , TRUE ) ;
	}

	// 終了
	return 0 ;
}

// 数値を画面に表示する関数
void DrawNum( int x , int y , int Num )
{
	char StrBuf[ 80 ] ;

	// 数値を10進数文字列に変換
	itoa( Num , StrBuf , 10 ) ;

	// 画面に描画
	DrawBox( x , y , x + strlen( StrBuf ) * 20 , y + 20 , 0 , TRUE ) ;
	DrawString( x , y , StrBuf , GetColor( 255 , 255 , 255 ) ) ;
}

動かしてみると、色がそろって消えるときにカウントされていきません。
何が原因なのか、またどのようにすればよいかを指摘していただけたらと思います。

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: スコアの実装について

#2

投稿記事 by beatle » 14年前

想像するに、消えたブロックの数だけ点数が加算されてはまた0に戻るという動作ではないでしょうか。
どうしてそう判断したかというと、Counter変数がCheckEliminatBlock関数内部で宣言されており、ローカル変数に
なっているからです。
「DXライブラリ置き場」の「DXライブラリ サンプルプログラム」17番のプログラムでは、Counter変数は
グローバル変数になっています。
ローカルとグローバルの違いは分かりますか?(一応C言語の超基礎です)

ariant

Re: スコアの実装について

#3

投稿記事 by ariant » 14年前

グローバルは関数の外側でしたよね?
Counter変数の位置を変えましたが、動作は変わりませんでした。

どのようにすれば加算された数値を0に戻さず維持できるでしょうか?

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: スコアの実装について

#4

投稿記事 by beatle » 14年前

もしかして、Counter変数の位置を変えただけで、Counterを初期化する場所を変えてない、ということでしょうか。

コード:

// 消えるブロックがあるか調べてあったら消す処理をする
int CheckEliminatBlock( void )
{
    int i , j , k;  // 汎用変数
    int ClsFlag ; // 一つでも消せたブロックがあったか、のフラグ
 
    
    //int Counter; これを関数の外にしたのですよね?
    Counter = 0 ;           // カウンターを初期化 ←これが問題
 
    do{
もちろん、CheckEliminatBlock関数が呼び出されるたびにCounter変数に0を書き込んでいたら、それはダメですよね。

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: スコアの実装について

#5

投稿記事 by beatle » 14年前

ariant さんが書きました:グローバルは関数の外側でしたよね?
はい。その通りです。

閉鎖

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