テトリス ブロックの色分け

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

テトリス ブロックの色分け

#1

投稿記事 by コン » 14年前

DXライブラリでテトリスを作成しているんですが、下記のようにおおよそのプログラムを組んでみました。
しかし、新しいブロックが画面に出てきた時に、既に積まれているブロックの色も新しく出てきたブロックの色に変わってしまい、ブロックすべてが同じ色になるという結果になってしまいます。
原因はどの部分にあるのでしょうか。
投げやりで申し訳ありませんが、教えていただけると大変助かります。

int gameoverに関してはまだ手を付けてないので無視でおねがいします。

コード:


#include<DxLib.h>


char KeyBuf[256];


int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}

//ステージ・フィールドの定義
int stage[21][12] = {0};
int field[21][12] = {0};

//ブロックの定義

int Block[7] = {0};//ブロックの画像を格納する配列
int block[4][4] = {0};
//ブロックの
int block_list[7][4][4] =     {{{0,1,0,0},
								{0,1,0,0},
								{0,1,0,0},
								{0,1,0,0}},

							   {{0,0,0,0},
								{0,1,1,0},
								{0,1,1,0},
								{0,0,0,0}},

	                           {{0,0,1,0},
								{0,1,1,0},
								{0,1,0,0},
								{0,0,0,0}},

							   {{0,1,0,0},
								{0,1,1,0},
								{0,0,1,0},
								{0,0,0,0}},

							   {{0,0,0,0},
								{0,1,0,0},
								{1,1,1,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,0},
								{0,1,0,0},
								{0,1,0,0}}};


							
//グローバル変数
int x = 120, y = 0;
int gameover = 0;
int block_type;

//ブロックの落下時間の調整変数
int time = 0;

//関数プロトタイプ宣言
void Initialize();
int CreateBlock();
void ShowGameField();
void MoveBlock(int, int);
int CheckOverlap(int, int);
void LockBlock();
void ControlBlock();
int TurnBlock();
int TimeProcessing();//時間関係の処理
void CheckLines();


//初期化------------------------------------------------------------------------------------------------
void Initialize()
{
	
	//ブロック画像のロード
	Block[0] = LoadGraph("block1.png");
	Block[1] = LoadGraph("block2.png");
	Block[2] = LoadGraph("block3.png");
	Block[3] = LoadGraph("block4.png");
	Block[4] = LoadGraph("block5.png");
	Block[5] = LoadGraph("block6.png");
	Block[6] = LoadGraph("block7.png");

	
	
	int i,j;//forループ制御用

	//画面と壁の初期設定
	for(i = 0; i <= 20; i++){
		for(j = 0; j <= 11; j++){
			if((j == 0) || (j == 11) || (i == 20)){
				field[i][j] = stage[i][j] = 8;
			}
			else{
				field[i][j] = stage[i][j] = 0;
			}
		}
	}

	CreateBlock();//ブロック初期位置の設定・ブロックの生成
	
}

//ブロックの生成-----------------------------------------------------------------------------
int CreateBlock()
{
	x = 4, y = 0;
	int i,j;//forループ制御用
	//ブロックの種類用。0~6の乱数を格納
	
	block_type = GetRand(6);//乱数の数値を格納
	

	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			block[i][j] = 0;
			block[i][j] = block_list[block_type][i][j];
		}
	}

	//壁+ブロックをフィールドへ
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			field[i][j+4] = stage[i][j+4] + block[i][j];
			
			//初期位置に固定ブロックがあったらゲームオーバー
			if(field[i][j+4] > 1){
				gameover = 1;
				return 1;
			}
		}
	}
	
	ShowGameField();
	return 0;
}

//画面の表示--------------------------------------------------------------------
void ShowGameField()
{

	if(gameover){//ゲームオーバーの処理
	}

//ブロックの描画
	for(int y = 0; y < 21; y++){
 			for(int x = 0; x < 12; x++){
				if(field[y][x] == 1){
					switch(block_type){
						case 0:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+1], FALSE);						
							break;
						case 1:
							DrawGraph(x*20+40, y*20,Block[field[y][x]], FALSE);
							break;
						case 2:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+1], FALSE);
							break;
						case 3:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+2], FALSE);
							break;
						case 4:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+3], FALSE);
							break;
						case 5:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+4], FALSE);
							break;
						case 6:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+5], FALSE);
							break;
						}
				}
			}
	}
	
}

//ブロックの落下--------------------------------------------------------------------
void MoveBlock(int x2, int y2)
{
	int i,j;//forループ制御用

	//今までのブロックを消去
	for(i = 0; i < 4; i++){
			for(j = 0; j < 4; j++){
				field[y+i][x+j] -= block[i][j];
			}
	}
	

	//ブロックの座標更新
	x = x2;
	y = y2;
	
	//新しい座標でブロックを入れなおす
	for(i = 0; i < 4; i++){
			for(j = 0; j < 4; j++){
				field[y+i][x+j] += block[i][j];
				
			}
	}
	ShowGameField();
	
}

//ブロックの移動操作------------------------------------------------------------------------
void ControlBlock()
{
	if(!CheckOverlap(x+1, y)){
		if(KeyBuf[KEY_INPUT_RIGHT]  ){ 
			MoveBlock(x+1, y);
			WaitTimer( 130 ) ;//1マスずつ移動させるため
		}
	}
	
	if(!CheckOverlap(x-1, y)){
		if(KeyBuf[KEY_INPUT_LEFT]  ){ 
			MoveBlock(x-1, y);
			WaitTimer( 130 ) ;//1マスずつ移動させるため
		}
	}

	if(!CheckOverlap(x, y+1)){
		if(KeyBuf[KEY_INPUT_DOWN] ){ 
			MoveBlock(x, y+1);
			WaitTimer( 50 ) ;//1マスずつ移動させるため			
		}
	}
	if(!CheckOverlap(x, y)){
		if(KeyBuf[KEY_INPUT_Z] ){
			TurnBlock();
			WaitTimer( 180 ) ;
		}
	}
}

//ブロックの回転処理--------------------------------------------------------------------------
int TurnBlock()
{
	int i,j;//forループ制御用
	int temp[4][4] = {0};//ブロックを一時保存するための配列

	//ブロックを回転する前にtempに保存
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			temp[i][j] = block[i][j];
		}
	}

	//ブロックの回転
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			block[i][j] = temp[3-j][i];
		}
	}

	//重なっているブロックが出たらブロックを回転前に戻して中止
	if(CheckOverlap(x,y)){
		for(i = 0; i < 4; i++){
			for(j = 0; j < 4; j++){
				block[i][j] = temp[i][j];
			}
		}
		return 1;
	}

	//一旦フィールドからブロックを消して回転後のブロックを再表示
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			field[y+i][x+j] -= temp[i][j];
			field[y+i][x+j] += block[i][j];
		}
	}

	ShowGameField();

	return 0;
}

//ブロックが重なったかどうかの検査----------------------------------------------------------------------------------------
int CheckOverlap(int x2, int y2)
{
	int i,j;//forループ制御用

	///ブロックが向かう位置に固定ブロックもしくは壁があるかを検査
	for(i = 0; i < 4; i++){
			for(j = 0; j < 4; j++){
				if(block[i][j]){
					if(stage[y2+i][x2+j] != 0){
						return 1;
					}
				}
			}
	}
	return 0;
}

//ブロックの壁化---------------------------------------------------------
void LockBlock()
{
	int i,j;//forループ制御用

	//ブロックを壁に加える
	for(i = 0; i < 21; i++){
		for(j = 0; j < 12; j++){
			stage[i][j] = field[i][j];
		}
	}
	CheckLines();//横一列が揃ったが判定し処理する関数を呼ぶ

	//列完成判定後の壁をフィールドへ
	for(i = 0; i < 21; i++){
		for(j = 0; j < 12; j++){
			field[i][j] = stage[i][j];
		}
	}
}

//時間の処理・ブロックの落下----------------------------------------------------------------------------------------------------------
int TimeProcessing()
{
//時間加算
		if((time <= 30) && (gameover == 0)){
			time++;
		}
		
		else{

			//重なりがなければ移動
			if(!CheckOverlap(x, y+1)){
				MoveBlock(x, y+1);	
			}

			//重なりがあれば壁化
			else{
				LockBlock();
				CreateBlock();
				
			}
		time = 0;
		}
		
		return 0;
}

//横一列が完成しているかの確認。揃った場合その列を消し上のブロックを下す-----------------------------------------------------------------------
void CheckLines()
{
	int i,j,k;//forループ制御用
	int comp;//横一列揃っていれば1、1つでも隙間があれば0

	while(1){
		for(i = 0; i < 20; i++){
			comp = 1;

				for(j = 0; j < 11; j++){
					if(stage[i][j] == 0){
						comp = 0;
					}
				}
				if(comp == 1){
					break;
				}	
			}
			if(comp == 0){
				break;
			}

			//列を消去
			for(j = 1; j < 11; j++){
				stage[i][j] = 0;
			}

			//消えた列より上にあった固定ブロックえお列の消えたところへ下す
			for(k = i; k > 0; k--){
				for(j = 1; j <11; j++){
					stage[k][j] = stage[k-1][j];
				}
			}
		}
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	//画面のサイズ
	SetWindowSize(580,400);
	//画面タイトル
	SetWindowText("test");


	//このウィンドウなどの内部的な初期化
	if(DxLib_Init() == -1)return -1;

	//タイムの初期化
   	time = 0;
	
	//ステージ初期化
	Initialize();
	
	//ブロック・背景のロード
	int a;
	a = LoadGraph("背景.png");
	
	
	// 描画先画面を裏画面にセット
	SetDrawScreen( DX_SCREEN_BACK ) ;

	while(!ProcessMessage() && !CheckHitKey(KEY_INPUT_SPACE)){
		ClsDrawScreen();//裏画面の初期化
		GetHitKeyStateAll(KeyBuf);//入力値の格納
		//-------------------------------------//
				
	//背景の画像表示
		DrawGraph(60,0,a,TRUE);

		//ブロック操作
		ControlBlock();
		
                          //ブロック・画面の設定
		ShowGameField();

		//時間関係処理
		TimeProcessing();
		//--MainEnd--------------------------//
		ScreenFlip(); //裏画面を表画面に反映

		
	}	
	
	DxLib_End() ;				// DXライブラリ使用の終了処理
	
	return (0) ;					// ソフトの終了

}


						


アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: テトリス ブロックの色分け

#2

投稿記事 by h2so5 » 14年前

block_typeがグローバル変数なのが問題ではないでしょうか。

box
記事: 2002
登録日時: 15年前

Re: テトリス ブロックの色分け

#3

投稿記事 by box » 14年前

意味合いが不明な変数(グローバル変数であることは見ればわかるので、
どういう意味の変数なのかをコメントに書く方がいいと思います)があって、中身はよくわかりませんが、
コン さんが書きました:

コード:

					switch(block_type){
						case 0:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+1], FALSE);						
							break;
						case 1:
							DrawGraph(x*20+40, y*20,Block[field[y][x]], FALSE);
							break;
						case 2:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+1], FALSE);
							break;
						case 3:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+2], FALSE);
							break;
						case 4:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+3], FALSE);
							break;
						case 5:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+4], FALSE);
							break;
						case 6:
							DrawGraph(x*20+40, y*20,Block[field[y][x]+5], FALSE);
							break;
						}
上記の
case 0:
のところで
+1
しているところが他のcaseとトーンが合っていないような気がします。
本題とは関係なかったり、気のせいだったりするのならばいいのですが。

また、このswitch文を実行するのは
field[y][x]

1
の場合のようですので、仮に
case 0:
のところが実は
-1
であったりするならば、わざわざcase分けしなくても
DrawGraph(x*20+40, y*20,Block[block_type], FALSE);
1行で事足りるような気もします。
本題と関係なかったりするならばいいのですが。

まあ、DxLibやゲームプログラミングには全く興味がない者のたわごととして
ごらんになってください。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

Re: テトリス ブロックの色分け

#4

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

これって元は、
「プログラミング講座 コウのポケット - GNIT -」
http://www.nhk.or.tv/kow/program/index.php
のプログラムですね?

で色の件ですが、block_typeで色を決めているので当然ながら新しいブロックが出る度に色が変わります。
提案ですが、ブロックの原型から出現しているブロックだけ複製を作って、1の値を置き換えてblock_typeを埋め込んではどうでしょうか?
ただし、block_typeが0から始まっていると何も無いところと区別がつかなくなるのでblock_typeが1から始まるように変更します。
でfield配列の方にもblock_typeの値で書き込むわけです。そうしれば、そのまま描画使うことが出来ます。

あと毎回フルスクリーンに切り替わって不便なので下記関数をDxLib_Init()に入れていただきたいです。
ChangeWindowMode(TRUE);
それと画像がない環境向けにDrowBoxで描画していただけると助かります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#5

投稿記事 by コン » 14年前

>>h2so5さん

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

blck_typeをグローバル変数から外すと

コード:

 for(int y = 0; y < 21; y++){
            for(int x = 0; x < 12; x++){
                if(field[y][x] == 1){
                    switch(block_type){
block_typeの部分がエラーになるんですよ。


>>boxさん
確かにそうでした。
ご指摘ありがとうございました。

コン

Re: テトリス ブロックの色分け

#6

投稿記事 by コン » 14年前

>>softya(ソフト屋)さん

ご回答ありがとうございます。
自分自身まだ未熟者なので、もう少し詳しく解説していただると大変助かります。
図々しくて申し訳ありません。

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

Re: テトリス ブロックの色分け

#7

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

整理してみます。
番号をつけますので、分からない場合は番号と分からない点を質問してください。

(1)全部の色をblock_typeで色を決めているので当然ながら新しいブロックが出る度に色が変わります。
つまり、ブロック色を決める要件をグローバルなblock_type変数ではなく別のものにする必要があります。

(2)field配列とblock_list配列にある0と1でブロックの有無を表すのではなく、0は従来通りブロックなしで1以上はブロックの色を表すように変更してはどうでしょうか?

(3)block_type=ブロックの色番号が0から始まっているのですが(2)のために1から始まるようにします。そのため画像イメージのBlockの配列を参照する時は色-1する必要性が生じます。

(4)色をブロックの情報として持つ必要があるのでblock_list配列の今現在のテトリミノの複製を作って、そこの1の所を色番号に置き換えます。
あとは、その複製をブロックの落下処理に使います。

(5)field配列に書きこむ時も色番号のまま書き込みます。こうすれば色とりどりのテトリミノの情報がfield配列に書き残されますので、これをそのまま表示に使います。

以上です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#8

投稿記事 by コン » 14年前

>>softya(ソフト屋)さん


(4)色をブロックの情報として持つ必要があるのでblock_list配列の今現在のテトリミノの複製を作って、そこの1の所を色番号に置き換えます。
あとは、その複製をブロックの落下処理に使います。

今現在のテトリミノの複製をつくり方と、どの処理後に複製作ればいいのかがわからないです。

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

Re: テトリス ブロックの色分け

#9

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

CreateBlockで既に複製はしているので、この時に色番号を埋め込めば良いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#10

投稿記事 by コン » 14年前

自分なりに

コード:

  if(field[y][x] == 1){
                    switch(block_type){
                        case 0:
                            DrawGraph(x*20+40, y*20,Block[field[y][x]+1], FALSE);                       
                            break;
                        case 1:
                            DrawGraph(x*20+40, y*20,Block[field[y][x]], FALSE);
                            break;
                        case 2:
                            DrawGraph(x*20+40, y*20,Block[field[y][x]+1], FALSE);
                            break;
                        case 3:
                            DrawGraph(x*20+40, y*20,Block[field[y][x]+2], FALSE);
                            break;
                        case 4:
                            DrawGraph(x*20+40, y*20,Block[field[y][x]+3], FALSE);
                            break;
                        case 5:
                            DrawGraph(x*20+40, y*20,Block[field[y][x]+4], FALSE);
                            break;
                        case 6:
                            DrawGraph(x*20+40, y*20,Block[field[y][x]+5], FALSE);
                            break;
                        }
}
の部分を

コード:


if(field[y][x] != 0){
				switch(field[y][x]){
					case 1:
						DrawGraph(x*20+40, y*20,Block[field[y][x]-1], FALSE);
						break;
					case 2:
						DrawGraph(x*20+40, y *20,Block[field[y][x]-1], FALSE);
						break;
					case 3:
						DrawGraph(x*20+40, y *20,Block[field[y][x]-1], FALSE);
						break;
					case 4:
						DrawGraph(x*20+40, y *20,Block[field[y][x]-1], FALSE);
						break;
					case 5:
						DrawGraph(x*20+40, y *20,Block[field[y][x]-1], FALSE);
						break;
					case 6:
						DrawGraph(x*20+40, y *20,Block[field[y][x]-1], FALSE);
						break;
					case 7:
						DrawGraph(x*20+40, y *20,Block[field[y][x]-1], FALSE);
						break;	
				}
			}

コード:


	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			block[i][j] = 0;
			block[i][j] = block_list[block_type][i][j];
		}
	}
の部分の後に

コード:

	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			block[i][j] = 0;
			block[i][j] = block_list[block_type][i][j];
		}
	}
	
	switch(block_type){
	case 0:
		block[0][1] = 1;
		block[1][1] = 1;
		block[2][1] = 1;
		block[3][1] = 1;
		break;
	case 1:
		block[1][1] = 2;
		block[1][2] = 2;
		block[2][1] = 2;
		block[2][2] = 2;
		break;
	case 2:
		block[0][2] = 3;
		block[1][1] = 3;
		block[1][2] = 3;
		block[2][1] = 3;
		break;
	case 3:
		block[0][1] = 4;
		block[1][1] = 4;
		block[1][2] = 4;
		block[2][2] = 4;
		break;
	case 4:
		block[1][1] = 5;
		block[2][0] = 5;
		block[2][1] = 5;
		block[2][2] = 5;
		break;
	case 5:
		block[1][1] = 6;
		block[1][2] = 6;
		block[2][2] = 6;
		block[3][2] = 6;
		break;
	case 6:
		block[1][1] = 7;
		block[1][2] = 7;
		block[2][1] = 7;
		block[3][1] = 7;
		break;
	}

としてみたんですが、今度はブロックが一瞬で落ちて、2つ目以降のブロックの生成がうまくできません。

原因はなんなのでしょうか。

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

Re: テトリス ブロックの色分け

#11

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

まず、色番号がblock_type + 1だとします。
最初のは、field[y][x]が0以外なら色番号で色番号-1がblock_typeですから
DrawGraph(x*20+40, y*20,Block[色番号-1], FALSE);
で描画すれば良いだけす。

後のは
block[j] = block_list[block_type][j];
としているときに値が1なら代わりに色番号を入れるだけです。
なので、残念ですが下記の部分は一切必要有りません。

コード:

    switch(block_type){
    case 0:
        block[0][1] = 1;
        block[1][1] = 1;
        block[2][1] = 1;
        block[3][1] = 1;
        break;
    case 1:
        block[1][1] = 2;
        block[1][2] = 2;
        block[2][1] = 2;
        block[2][2] = 2;
        break;
    case 2:
        block[0][2] = 3;
        block[1][1] = 3;
        block[1][2] = 3;
        block[2][1] = 3;
        break;
    case 3:
        block[0][1] = 4;
        block[1][1] = 4;
        block[1][2] = 4;
        block[2][2] = 4;
        break;
    case 4:
        block[1][1] = 5;
        block[2][0] = 5;
        block[2][1] = 5;
        block[2][2] = 5;
        break;
    case 5:
        block[1][1] = 6;
        block[1][2] = 6;
        block[2][2] = 6;
        block[3][2] = 6;
        break;
    case 6:
        block[1][1] = 7;
        block[1][2] = 7;
        block[2][1] = 7;
        block[3][1] = 7;
        break;
    }}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#12

投稿記事 by コン » 14年前

block[j] = block_list[block_type][j];
としているときに値が1なら代わりに色番号を入れるだけです。

↑ 色番号の変数はグローバル変数で、変数名[4][4] でいいのでしょうか。

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

Re: テトリス ブロックの色分け

#13

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

コン さんが書きました:block[j] = block_list[block_type][j];
としているときに値が1なら代わりに色番号を入れるだけです。
↑ 色番号の変数はグローバル変数で、変数名[4][4] でいいのでしょうか。


色の番号をグローバル変数にしないでください。
あと変数名[4][4] が意味不明ですが、色の番号をblock[j] に特定の条件で代入します(説明済み)。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#14

投稿記事 by コン » 14年前

これであってますか。

コード:

int CreateBlock()
{
	x = 4, y = 0;
	int i,j;//forループ制御用
	int color;//色番号
	
	int block_type;//ブロックの種類用。0~6の乱数を格納
	
	block_type = GetRand(6);//乱数の数値を格納

	color = block_type + 1//色番号に乱数数値を代入
      
      //種類ごとにブロックの読み込み
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			block[i][j] = 0;
			block[i][j] = block_list[block_type][i][j];
			//ブロックに色番号を代入
       if(block[i][j] == 1){
				block[i][j] = color;
			}
		}
	}

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

Re: テトリス ブロックの色分け

#15

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

そうです!シンプルですよね。
あと
block[j] = block_list[block_type][j];

if(block[j] == 1){
は一工夫すればif文にまとまります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#16

投稿記事 by コン » 14年前

先ほどのものでやってみたんですが、

DrawGraph(x*20+40, y*20,Block[color-1], FALSE);

colorの部分がエラーになってしまいます。

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

Re: テトリス ブロックの色分け

#17

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

ここの説明をよく読んでください。
softya(ソフト屋) さんが書きました:まず、色番号がblock_type + 1だとします。
最初のは、field[y][x]が0以外なら色番号で色番号-1がblock_typeですから
DrawGraph(x*20+40, y*20,Block[色番号-1], FALSE);
で描画すれば良いだけす。
colorはfield[y][x]から創りだすんです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#18

投稿記事 by コン » 14年前

DrawGraph(x*20+40, y*20,Block[color-1], FALSE);

の部分を

DrawGraph(x*20+40, y*20,Block[field[y][x]-1], FALSE);

にしたんですが、ブロックが一瞬で落ち、ブロックが生成されません。

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

Re: テトリス ブロックの色分け

#19

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

幾つか問題が出ると思います。
でも、そのまえに
(1)ブロックの色は表示はされたんですね?
(2)積み重なりの状態は異常はないですか?
を確認してください。

最新のソースコードを貼ってもらえますか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#20

投稿記事 by コン » 14年前

確認の結果はこんな感じです。
(1)ブロックのいろは表示されています。
(2)1つ目のブロックが一瞬で落下し、2つ目以降のブロックは生成されないです。

最新のソースコードはこちらです。

コード:

#include<DxLib.h>


char KeyBuf[256];


int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}

//ステージ・フィールドの定義
int stage[21][12] = {0};
int field[21][12] = {0};

//ブロックの定義

int Block[7] = {0};//ブロックの画像を格納する配列
int block[4][4] = {0};//落下中のブロックを格納
//ブロックの種類
int block_list[7][4][4] =     {{{0,1,0,0},
								{0,1,0,0},
								{0,1,0,0},
								{0,1,0,0}},

							   {{0,0,0,0},
								{0,1,1,0},
								{0,1,1,0},
								{0,0,0,0}},

	                           {{0,0,1,0},
								{0,1,1,0},
								{0,1,0,0},
								{0,0,0,0}},

							   {{0,1,0,0},
								{0,1,1,0},
								{0,0,1,0},
								{0,0,0,0}},

							   {{0,0,0,0},
								{0,1,0,0},
								{1,1,1,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,0},
								{0,1,0,0},
								{0,1,0,0}}};



								
//グローバル変数
int x = 120, y = 0;//ブロックの座標
int gameover = 0;

//ブロックの落下時間の調整変数
int time = 0;

//関数プロトタイプ宣言
void Initialize();
int CreateBlock();
void ShowGameField();
void MoveBlock(int, int);
int CheckOverlap(int, int);
void LockBlock();
void ControlBlock();
int TurnBlock();
int TimeProcessing();//時間関係の処理
void CheckLines();



//初期化------------------------------------------------------------------------------------------------
void Initialize()
{
	
	//ブロック画像のロード
	Block[0] = LoadGraph("block1.png");
	Block[1] = LoadGraph("block2.png");
	Block[2] = LoadGraph("block3.png");
	Block[3] = LoadGraph("block4.png");
	Block[4] = LoadGraph("block5.png");
	Block[5] = LoadGraph("block6.png");
	Block[6] = LoadGraph("block7.png");

	
	
	int i,j;//forループ制御用

	//画面と壁の初期設定
	for(i = 0; i <= 20; i++){
		for(j = 0; j <= 11; j++){
			if((j == 0) || (j == 11) || (i == 20)){
				field[i][j] = stage[i][j] = 8;
			}
			else{
				field[i][j] = stage[i][j] = 0;
			}
		}
	}

	CreateBlock();
}




//ブロックの生成-----------------------------------------------------------------------------
int CreateBlock()
{
	x = 4, y = 0;//ブロックの初期位置の座標
	
	int i,j;//forループ制御用
	int color;
	int block_type;//ブロックの種類用。0~6の乱数を格納
	
	block_type = GetRand(6);//乱数の数値を格納

	color = block_type + 1;//色番号に乱数数値を代入


	//種類ごとにブロックの読み込み
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			block[i][j] = 0;
			block[i][j] = block_list[block_type][i][j];
			if(block[i][j] == 1){
				block[i][j] = color;
			}
		}
	}

	//壁+ブロックをフィールドへ
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			field[i][j+4] = stage[i][j+4] + block[i][j];
			
			//初期位置に固定ブロックがあったらゲームオーバー
			if(field[i][j+4] > 1){
				gameover = 1;
				return 1;
			}
		}
	}
	ShowGameField();
	return 0;
}



//画面の表示--------------------------------------------------------------------
void ShowGameField()
{

	if(gameover){//ゲームオーバーの処理
	}


	//ブロックの描画
	for(int y = 0; y < 21; y++){
  		for(int x = 0; x < 12; x++){
			if(field[y][x] != 0){
				switch(field[y][x]){
					case 1:
						DrawGraph(x*20+40, y*20,Block[ field[y][x] -1], FALSE);
						break;
					case 2:
						DrawGraph(x*20+40, y *20,Block[ field[y][x] -1], FALSE);
						break;
					case 3:
						DrawGraph(x*20+40, y *20,Block[ field[y][x] -1], FALSE);
						break;
					case 4:
						DrawGraph(x*20+40, y *20,Block[field[y][x] -1], FALSE);
						break;
					case 5:
						DrawGraph(x*20+40, y *20,Block[field[y][x] -1], FALSE);
						break;
					case 6:
						DrawGraph(x*20+40, y *20,Block[ field[y][x] -1], FALSE);
						break;
					case 7:
						DrawGraph(x*20+40, y *20,Block [field[y][x] -1], FALSE);
						break;	
				}
			}
		}
	}
}


//ブロックの落下--------------------------------------------------------------------
void MoveBlock(int x2, int y2)
{
	int i,j;//forループ制御用

	//今までのブロックを消去
	for(i = 0; i < 4; i++){
			for(j = 0; j < 4; j++){
				field[y+i][x+j] -= block[i][j];
								
			}
	}
	

	//ブロックの座標更新
	x = x2;
	y = y2;
	

	//新しい座標でブロックを入れなおす
	for(i = 0; i < 4; i++){
			for(j = 0; j < 4; j++){
				field[y+i][x+j] += block[i][j];
				
			}
	}
	ShowGameField();
	
}




//ブロックの移動操作------------------------------------------------------------------------
void ControlBlock()
{

	if(!CheckOverlap(x+1, y)){
		if(KeyBuf[KEY_INPUT_RIGHT]  ){ 
			MoveBlock(x+1, y);
			WaitTimer( 130 ) ;//1マスずつ移動させるため
					

		}
	}
	
	if(!CheckOverlap(x-1, y)){
		if(KeyBuf[KEY_INPUT_LEFT]  ){ 
			MoveBlock(x-1, y);
			WaitTimer( 130 ) ;//1マスずつ移動させるため
					
		
		}
	}

	if(!CheckOverlap(x, y+1)){
		if(KeyBuf[KEY_INPUT_DOWN] ){ 
			MoveBlock(x, y+1);
			WaitTimer( 50 ) ;//1マスずつ移動させるため
					
		}
	}
	if(!CheckOverlap(x, y)){
		if(KeyBuf[KEY_INPUT_Z] ){
			TurnBlock();
			WaitTimer( 180 ) ;
		}
	}
}


//ブロックの回転処理--------------------------------------------------------------------------
int TurnBlock()
{
	int i,j;//forループ制御用
	int temp[4][4] = {0};//ブロックを一時保存するための配列

	//ブロックを回転する前にtempに保存
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			temp[i][j] = block[i][j];
		}
	}

	//ブロックの回転
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			block[i][j] = temp[3-j][i];
		}
	}

	//重なっているブロックが出たらブロックを回転前に戻して中止
	if(CheckOverlap(x,y)){
		for(i = 0; i < 4; i++){
			for(j = 0; j < 4; j++){
				block[i][j] = temp[i][j];
			}
		}
		return 1;
	}

	//一旦フィールドからブロックを消して回転後のブロックを再表示
	for(i = 0; i < 4; i++){
		for(j = 0; j < 4; j++){
			field[y+i][x+j] -= temp[i][j];
			field[y+i][x+j] += block[i][j];
		}
	}

	ShowGameField();

	return 0;
}



//ブロックが重なったかどうかの検査----------------------------------------------------------------------------------------
int CheckOverlap(int x2, int y2)
{

	int i,j;//forループ制御用

	///ブロックが向かう位置に固定ブロックもしくは壁があるかを検査
	for(i = 0; i < 4; i++){
			for(j = 0; j < 4; j++){
				if(block[i][j]){
					if(stage[y2+i][x2+j] != 0){
						return 1;
					}
				}
			}
	}
	return 0;
}



//ブロックの壁化---------------------------------------------------------
void LockBlock()
{
	int i,j;//forループ制御用

	//ブロックを壁に加える
	for(i = 0; i < 21; i++){
		for(j = 0; j < 12; j++){
			stage[i][j] = field[i][j];
		}
	}
	CheckLines();//横一列が揃ったが判定し処理する関数を呼ぶ

	//列完成判定後の壁をフィールドへ
	for(i = 0; i < 21; i++){
		for(j = 0; j < 12; j++){
			field[i][j] = stage[i][j];
		}
	}
}



//時間の処理・ブロックの落下----------------------------------------------------------------------------------------------------------
int TimeProcessing()
{
//時間加算
		if((time <= 30) && (gameover == 0)){
			time++;
		}
		
		else{

			//重なりがなければ移動
			if(!CheckOverlap(x, y+1)){
				MoveBlock(x, y+1);	
			}

			//重なりがあれば壁化
			else{
				LockBlock();
				CreateBlock();
				
			}
		time = 0;
		}
		
		return 0;
}



//横一列が完成しているかを検査。揃った場合その列を消し上のブロックを下す-----------------------------------------------------------------------
void CheckLines()
{
	int i,j,k;//forループ制御用
	int comp;//横一列揃っていれば1、1つでも隙間があれば0

	while(1){
		for(i = 0; i < 20; i++){
			comp = 1;

				for(j = 0; j < 11; j++){
					if(stage[i][j] == 0){
						comp = 0;
					}
				}
				if(comp == 1){
					break;
				}	
			}
			if(comp == 0){
				break;
			}

			//列を消去
			for(j = 1; j < 11; j++){
				stage[i][j] = 0;
			}

			//消えた列より上にあった固定ブロックえお列の消えたところへ下す
			for(k = i; k > 0; k--){
				for(j = 1; j <11; j++){
					stage[k][j] = stage[k-1][j];
				}
			}
		}
}


//↓ おまじない
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	//画面のサイズ
	SetWindowSize(580,400);
	//画面タイトル
	SetWindowText("test");

	
	

	//この下はウィンドウを使いたい場合は「/*」と「*/」消せば使える
	
	//ウィンドウにするかフルスクリーンにするか
	if(IDYES==MessageBox(NULL,"ウィンドウモードにしますか?(推奨)","確認",MB_YESNO | MB_ICONQUESTION) )
      	{ChangeWindowMode(TRUE);}else{ChangeWindowMode(FALSE);}
	
	//このウィンドウなどの内部的な初期化
	if(DxLib_Init() == -1)return -1;

	//タイムの初期化
      	time = 0;
	
	//ステージ初期化
	Initialize();
	
	//ブロック・背景のロード
	int a;
	a = LoadGraph("背景.png");
	
	
	// 描画先画面を裏画面にセット
	SetDrawScreen( DX_SCREEN_BACK ) ;

	while(!ProcessMessage() && !CheckHitKey(KEY_INPUT_SPACE)){
   		ClsDrawScreen();//裏画面の初期化
		GetHitKeyStateAll(KeyBuf);//入力値の格納
		//-------------------------------------//
		

	//メインゲーム
		
	//背景の画像表示
		DrawGraph(60,0,a,TRUE);
		//時間関係処理
		TimeProcessing();
		
            //ブロック操作
		ControlBlock();
		
            //ブロック画面描画
		ShowGameField();
		
		//--MainEnd--------------------------//
		ScreenFlip(); //裏画面を表画面に反映
		
		
		
	}	
	
	DxLib_End() ;				// DXライブラリ使用の終了処理
	
	return (0) ;					// ソフトの終了

}


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

Re: テトリス ブロックの色分け

#21

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

DrawGraph(x*20+40, y*20,Block[field[y][x]-1], FALSE);
が見当たらないのですが?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#22

投稿記事 by コン » 14年前

177行目のところに記述しています。

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: テトリス ブロックの色分け

#23

投稿記事 by h2so5 » 14年前

boxさんの
box さんが書きました:DrawGraph(x*20+40, y*20,Block[block_type], FALSE);
1行で事足りるような気もします。
という投稿に対して、
コン さんが書きました:>>boxさん
確かにそうでした。
ご指摘ありがとうございました。
と仰っている上に、softyaさんからも
softya さんが書きました:最初のは、field[y][x]が0以外なら色番号で色番号-1がblock_typeですから
DrawGraph(x*20+40, y*20,Block[色番号-1], FALSE);
で描画すれば良いだけす。
と重ねて指摘されているのも関わらず、なぜコードに反映されていないのでしょうか?

switch文を使う必要がないという事を理解されていないように思われます。

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

Re: テトリス ブロックの色分け

#24

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

コン さんが書きました:177行目のところに記述しています。
そこは、switch~caseで分ける必要はないでしょう。一行に修正できます。

それとすぐ落下する原因は、
if(field[j+4] > 1){
です。
field[j+4]が色番号になったので、1以上の可能性があります。
ここは、stage[j+4]とblock[j]に色があったら条件に変えるべきでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#25

投稿記事 by コン » 14年前

それとすぐ落下する原因は、
if(field[j+4] > 1){
です。
field[j+4]が色番号になったので、1以上の可能性があります。
ここは、stage[j+4]とblock[j]に色があったら条件に変えるべきでしょう。


↑↑これの意味がイマイチ分かりません。
どういうことなのでしょうか。

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

Re: テトリス ブロックの色分け

#26

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

そもそも、
if(field[j+4] > 1){
の意味を理解されていますか?
プログラムを解析してみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#27

投稿記事 by コン » 14年前

>>by softya(ソフト屋)さん

そもそも、
if(field[j+4] > 1){
の意味を理解されていますか?
プログラムを解析してみてください。

これは色番号を入れる前は0が空白、1がブロックだったので
field[j+4] > 1が、1より大きくなるということは新しく生成されたブロックの位置にすでにブロックがありgameoverになるということはわかるんですが、色番号を入れた時の条件分岐の所がイマイチ分からないんです…

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

Re: テトリス ブロックの色分け

#28

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

色番号なのでstage[j+4]とblock[j]ともに0~7?までの範囲ですよね。
これを加算した場合の数値は0~14?の範囲になります。
で、1+1=2だし2+0でも2なのでfield[j+4] は衝突判定には使えません。

なので、元のstage[j+4]とblock[j]の両方に色があれば衝突としましょうって話です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

コン

Re: テトリス ブロックの色分け

#29

投稿記事 by コン » 14年前

無事問題を解決することができました。
こんな私の質問に丁寧に解答してくださった皆さん本当にありがとうございました。

閉鎖

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