画像(logo)

HOME/[C言語コンソール]ブロックパズルの作り方 目次/二日目 ブロックと壁を表示

広告

[C言語 コンソール ブロックパズルの作り方]
二日目 ブロックと壁を表示

広告

↓2016年02月29日発売↓

12歳からはじめる ゼロからのC言語 ゲームプログラミング教室

目次へ戻る

ブロックと壁を表示

今回は「stage」と「block」を重ねるようにして「field」を作る所までやっていきましょう!

「0」・・・何もない

「1」・・・ブロック

「9」・・・壁

を頭に入れておきましょう!

「for」ループのイメージ

ブロックパズルを作る上で、2次元配列の平面を、端から、端まで調べるのに2重の「for」ループがたくさん使われます。

これが慣れないとなかなか難しいので、まずはブロック「block」を使ってそのループのイメージをつかみましょう!

ブロック(block[4][4])

0,0,0,0

0,1,1,0

0,1,1,0

0,0,0,0

この2次元配列の平面を端から、端まで調べます。

for(y=0;y<4;y++){
	for(x=0;x<4;x++){
	}
}

こちらが2重の「for」ループです。

ループの内側にループがありますね!

イメージとしては最初に内側のループを終わらせてから、外側のループを一つ進めるような感じになります。

では実際にプログラムで確認してみましょう。

次のプログラムを今は内容を気にせずにそのままコピーして実行してみてください。

一回一回入力待ちになるので何かキーを押してください。

#include <stdio.h>
#include <conio.h>

int block[4][4] = {
	{0,0,0,0},
	{0,1,1,0},
	{0,1,1,0},
	{0,0,0,0}
};

int main(){
	int stop;
	int x,y;
	for(y=0;y<4;y++){
		for(x=0;x<4;x++){
			if(block[y][x]==0){
				printf("0");
			}
			else if(block[y][x] == 1){
				printf("1");
			}
			stop = _getch();
		}
		printf("\n");
	}
	return 0;
}

■実行結果■

画像(cb_2_1)

■説明■

まずは内側のループで横一列を描き・・・。

0000

外側のループを一つ進めて再び内側のループへ・・・。

0000

011

なんとなく動きが確認できましたでしょうか?

繰り返しますが2重以上のループは内側から外側のループへと移るようなイメージになります。

これを使って2次元配列をいろいろといじるので動きをイメージできるようにしておきましょう。

あと今回のようにプログラム途中の動きを確認したい時は

#include <conio.h>

int stop;
stop = _getch();	

一文字入力用の関数「_getch()」を使うと一つ一つの動きを止められるので便利です。

左上から右下へ

2次元配列は左上が(0,0)でそこから右下方向に展開します。

たとえば「field[23][18]」という2次元配列の場合は

画像(cb_2_2)

左上が(0,0)、右下が(22,17)というように左上から右下にかけて展開していきます。

ここで気づかれた方いるかもしれませんが、これを「x,y」の座標で考えた時、普通は(x,y)の順番で座標を表しますが、当サイトでは2次元配列表記に合わせて(y,x)の順番で表記します。

ブロックと壁を表示

それでは長らくお待たせしましたが、ようやくプログラムを実際に組んでみたいと思います。

よく使う数字は定数化

よく使う数字は定数化してしまいます。

/*ブロックの縦幅・横幅*/
#define BLOCK_HEIGHT 4
#define BLOCK_WIDTH 4

/*フィールドの縦幅・横幅*/
#define FIELD_HEIGHT 23
#define FIELD_WIDTH 18

ブロックの幅とフィールドの幅はよく登場するので定数化しました。

これをしておけば後でプログラムを確認する時や自分のオリジナリティを出すべくフィールドの拡張がしたい場合などにも便利ですね。

広告

変数は基本的にグローバル

ループ用に使う変数などを除いて今回はできるだけわかりやすくするべく変数などはグローバルで宣言していきます。

int block[BLOCK_HEIGHT][BLOCK_WIDTH];
int stage[FIELD_HEIGHT][FIELD_WIDTH];
int field[FIELD_HEIGHT][FIELD_WIDTH];

/*最初は四角いブロックのみ*/
int blocks[BLOCK_HEIGHT][BLOCK_WIDTH] = {
	{0,0,0,0},
	{0,1,1,0},
	{0,1,1,0},
	{0,0,0,0}
};

/*ブロックの横位置*/
int block_x;

/*ブロックの縦位置*/
int block_y;

ブロックの横位置と縦位置は

↓この左上の部分
0000
0110
0110
0000

の座標になります。

あと特に意味はないのですがブロックを調べる時など小さいループには変数「x,y」フィールドを調べる時など大きいループには変数「i,j」を使用しております。

初期化

まずは変数などを初期化していきます。

void my_init_var(){
	int i,j;

	for(i=0;i<FIELD_HEIGHT;i++){
		for(j=0;j<FIELD_WIDTH;j++){
			stage[i][0] = 9;
			stage[i][1] = 9;
			stage[i][2] = 9;
			stage[20][j] = 9;
			stage[21][j] = 9;
			stage[22][j] = 9;
			stage[i][15] = 9;
			stage[i][16] = 9;
			stage[i][17] = 9;		
		}
	}

	block_x = 7;
	block_y = 0;
}

「stage[23][18]」に壁の部分を作るべく左右、下を壁である「9」にします。

上の部分には、はみ出さないように重ねあわせるので壁は作りません。

あとはブロックの横位置「block_x」と縦位置「block_y」を設定して初期化は終わりです。

ブロックを登録

次にブロックを登録します。

void my_make_block(){
	int x,y;

	for(y=0;y<BLOCK_HEIGHT;y++){
		for(x=0;x<BLOCK_WIDTH;x++){
			block[y][x] = blocks[y][x];
		}
	}
}

ブロックの元となる「blocks」からブロックをゲーム進行時のブロックの受け皿である「block」に移し替えます。

最初はわかりやすいように四角いブロックのみで話を進めていきます。

後半にブロックの元となる「blocks」でブロックの種類を増やして、ここでブロックをランダムに発生させていきます。

重ね合わせる

「field[23][18]」に「stage[23][18]」と「block[4][4]」を重ね合わせていきます。

void my_make_field(){
	int i,j,x,y;

	for(i=0;i<FIELD_HEIGHT;i++){
		for(j=0;j<FIELD_WIDTH;j++){
			field[i][j] = stage[i][j];	
		}
	}

	for(y=0;y<BLOCK_HEIGHT;y++){
		for(x=0;x<BLOCK_WIDTH;x++){
			field[block_y + y][block_x + x] += block[y][x];
		}
	}	
}

先に「field[23][18]」に「stage[23][18]」を重ね合わせます。

for(i=0;i<FIELD_HEIGHT;i++){
	for(j=0;j<FIELD_WIDTH;j++){
		field[i][j] = stage[i][j];	
	}
}

次に残る「block[4][4]」を重ね合わせます。

for(y=0;y<BLOCK_HEIGHT;y++){
	for(x=0;x<BLOCK_WIDTH;x++){
		field[block_y + y][block_x + x] += block[y][x];
	}
}

ここで重ね合わせる場所ですが先ほどのブロック位置「block_x,block_y」を加える事によってその位置からブロックを重ね合わせる事ができます。

field[block_y + y][block_x + x] += block[y][x];

先に重ねた「stage[23][18]」を消さないように「+=」と足し合わせるカタチで重ねていくトコロにも注意です。

これで「field[23][18]」に必要な情報が入ったのでこれを画面に出力するだけです。

画面表示

では先ほどの「field[23][18]」を使って画面を描いていきます。

void my_draw_field(){
	int i,j;

	system("cls");

	for(i=0;i<FIELD_HEIGHT;i++){
		for(j=0;j<FIELD_WIDTH;j++){
			if(field[i][j] == 9)printf("■");
			else if(field[i][j] == 1)printf("□");
			else printf(" ");
		}
		printf("\n");
	}
}

画面消去には「system("cls");」を使います。

使う時は「#include <stdlib.h>」が必要です。

そして2重の「for」ループを使ってそれぞれの要素を置き換えながら画面を描いていきます。

内側の「for」ループが終わった時にそのままでは横につながっていってしまうので改行してあげます。

メイン

メインです。

int main(){
	my_init_var();
	my_make_block();
	my_make_field();
	my_draw_field();
	return 0;
}

今回はただ表示するだけなので今作った関数を並べるだけです。

画像(cb_2_3)

壁とブロックが表示できました!

最初はわかりやすいように全体を描画してますが次回以降は内側の部分だけを描いていきます。

ここまでの中間ソースになります。

中間ソース1

それでは次回は落下させてみたいと思います。

次回

三日目 落下

□ページの先頭へ□

□目次へ戻る□

□HOME□

広告

↓2017年06月16日発売↓

やさしいC 第5版 (「やさしい」シリーズ)

新品価格
¥2,700から
(2017/5/1 13:05時点)

↓2014年08月09日発売↓

新・明解C言語 入門編 (明解シリーズ)

新品価格
¥2,484から
(2017/5/1 13:08時点)

↓2016年02月20日発売↓

新・解きながら学ぶC言語

新品価格
¥2,160から
(2017/5/1 13:10時点)

↓2017年02月11日発売↓

C言語プログラミング基本例題88 88

新品価格
¥3,024から
(2017/5/1 13:12時点)

↓2016年12月15日発売↓

Cの絵本 第2版 C言語が好きになる新しい9つの扉

新品価格
¥1,490から
(2017/5/1 13:13時点)

↓2017年02月08日発売↓

新・明解C言語で学ぶアルゴリズムとデータ構造 (明解シリーズ)

新品価格
¥2,700から
(2017/5/1 13:15時点)