画像(logo)

HOME/[C言語DXライブラリ]ブロックパズルの作り方 目次/四日目 当たり判定「壁」

広告

[C言語 DXライブラリ ブロックパズルの作り方]
四日目 当たり判定「壁」

広告

↓2016年02月29日発売↓

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

目次へ戻る

当たり判定

当たり判定のお時間です!今回は横に移動するのと壁の当たり判定を確認する所までやっていきます。

キー入力

まずは横に動かすためのキー入力の簡単なプログラムを作ってみます。

実行すると入力待ちの無限ループになりますので矢印キーの左か右を押してください!

#include "DxLib.h"

void my_get_key(void);

int key[256];

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

	int Color_White = GetColor(255,255,255);

	while(ProcessMessage() == 0){
		ClearDrawScreen();

		my_get_key();

		if(key[KEY_INPUT_LEFT] > 0){
			DrawFormatString(0,0,Color_White,
				"左=%d",key[KEY_INPUT_LEFT]);
		}
		if(key[KEY_INPUT_RIGHT] > 0){
			DrawFormatString(0,20,Color_White,
				"右=%d",key[KEY_INPUT_RIGHT]);
		}

		ScreenFlip();
	}

	DxLib_End();
	return 0;
}

void my_get_key(){
	int i;
	char keys[256];
	
	GetHitKeyStateAll(keys);
	for(i=0;i<256;i++){
		if(keys[i] != 0){
			key[i]++;
		}
		else{
			key[i] = 0;
		}
	}
}

■実行結果■

画像(cdxb_4_1)

キー入力を確認するためのプログラムです。

矢印キーの「左←」か「右→」を押すと反応するようになってます。

全てのキーの入力状態を取得

まず256種類全てのキーの入力状態を取得する関数が

char keys[256];
GetHitKeyStateAll(keys);

この「GetHitKeyStateAll()」という関数になります。

実行すると変数「keys」のキー入力があった場所に「0」以外が返されます。

そして256種類のキーは定数化されているのでこの「keys」を調べて

if(keys[KEY_INPUT_LEFT] != 0){
	/*左が押された時の処理*/
}

のようにすればキーが押された時の処理ができます。

「KEY_INPUT_LEFT」・・・左

「KEY_INPUT_UP」・・・上

「KEY_INPUT_RIGHT」・・・右

「KEY_INPUT_DOWN」・・・下

「KEY_INPUT_Z」・・・Z

「KEY_INPUT_H」・・・H

「KEY_INPUT_RETURN」・・・エンター

とりあえず今回使用するキーの定数になります。

他のキーに関しては「dxlib キー リファレンス」などで検索してみてください。

押しっぱなし、ちょい押し

上記の方法でもキー入力は取得できますが、押しっぱなした時や少しだけ押された時などの微妙なニュアンスのキー入力処理ができません。

そこで少し工夫したものが次の関数になります。

void my_get_key(){
	int i;
	char keys[256];
	
	GetHitKeyStateAll(keys);
	for(i=0;i<256;i++){
		if(keys[i] != 0){
			key[i]++;
		}
		else{
			key[i] = 0;
		}
	}
}

キーの入力状態をグローバルに用意した変数「int key[256]」にインクリメント、値の増加というカタチによって保存しなおします。

こうする事によってさきほどのプログラムの実行結果のようにキーを少し押せば値が少しだけ上昇し、長押せばその押した分だけ値が上昇するので微妙なキー入力のニュアンスも処理できるようになります!

実際に使う時は

if(key[KEY_INPUT_LEFT] > 0){
	/*左が押された時の処理*/
}

のようにすればキーが押されれば即時に反応しますし、

if(key[KEY_INPUT_LEFT] > 100){
	/*左が押された時の処理*/
}

長押しした時

if(key[KEY_INPUT_LEFT] > 10 && key[KEY_INPUT_LEFT] < 30){
	/*左が押された時の処理*/
}

ちょい押しした時

のように細かく入力を処理できます。

ちなみに、この関数は「ゲームプログラミングの館」さんというサイトからほぼそのまま流用させて頂いております。

他にも本格的なゲームの作り方などがやさしく解説されておりますので興味ある方はぜひ一度覗いてみてください。

当たり判定

キー入力のやり方がわかったので次は当たり判定です。このままだと壁を突き抜けて、どこまででも行ってしまいます。

広告

固まったブロックや壁を保存「stage」

固まったブロックや壁の状態を保存しているのは「stage[23][18]」でした。

なのでこの「stage[23][18]」と現在のブロック「block[4][4]」を調べれば良さそうです。

void my_collision_left(){
	int x,y;

	collision_flag = 0;

	for(y=0;y<BLOCK_HEIGHT;y++){
		for(x=0;x<BLOCK_WIDTH;x++){
			if(block[y][x] != 0){
				if(stage[block_y + y][block_x + (x - 1)] != 0){
					collision_flag = 1;
				}
				else if((int)(block_y_count - (block_y * DRAW_BLOCK_WIDTH)) > 0){
					if(stage[block_y + (y + 1)][block_x + (x - 1)] != 0){
						collision_flag = 1;
					}
				}
			}
		}
	}
}

ブロックの左側の当たり判定を調べる「my_collision_left()」です。

当たり判定用のフラグとしてグローバル変数「int collision_flag」を用意してそこに当たり判定の結果を格納します。

そして当たり判定の方法ですが、まずは現在の「block[4][4]」の状態を調べます。

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

「block[4][4]」が「0」でなければ、つまりそこがブロックならば今度は「stage[23][18]」上の現在のブロックの座標周りを調べれば必要な情報が得られます。

if(stage[block_y + y][block_x + (x - 1)] != 0){
	collision_flag = 1;
}

今回は左側の当たり判定なので「x座標 - 1」の部分を調べれば大丈夫ですね!

これだけで基本は大丈夫ですが、マス目の間

画像(cdxb_4_2)

こんな状態の時の当たり判定も加えないと、画像の例ではもう左側には移動できないのにめり込むようなカタチで移動できてしまいます。

それを防ぐ為の判定部分も作ります。

else if((int)(block_y_count - (block_y * DRAW_BLOCK_WIDTH)) > 0){
	if(stage[block_y + (y + 1)][block_x + (x - 1)] != 0){
		collision_flag = 1;
	}
}

こちらの部分ですね!

まずさきほどの画像のような状態は次の計算で得られます。

if((int)(block_y_count - (block_y * DRAW_BLOCK_WIDTH)) > 0)

実際に落下している場所「block_y_count」からその落下しているマス目分引いたものが「0」以上であれば画像のような状態という事になります。

そしてこの状態というのはマス目でいうトコロの一つ下の部分との当たり判定になるので

if(stage[block_y + (y + 1)][block_x + (x - 1)] != 0){
	collision_flag = 1;
}

stage[block_y + (y + 1)][block_x + (x - 1)]と一つ下の部分の一つ左側の部分を調べれば画像のような状態の当たり判定も大丈夫です!

同じように右側の当たり判定用関数も作ります。

キー入力に当たり判定を組み込む

あとはキー入力時に当たり判定用関数を組み込むだけですね!

void my_move_block(){
	if(key[KEY_INPUT_LEFT] % 5 == 1){
		my_collision_left();
		if(collision_flag == 0){
			block_x--;
		}
	}

	if(key[KEY_INPUT_RIGHT] % 5 == 1){
		my_collision_right();
		if(collision_flag == 0){
			block_x++;
		}
	}
}

それぞれのキー入力に合わせて当たり判定用関数を呼び出し「collision_flag」を確認して「block_x」を移動させます。

キー入力はそのまま受け取るとけっこうシビアになるので余りをとる事によって少し調節しております。

これで左右の当たり判定ができました。

メイン

メインになります。

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

	my_init_var();

	while(ProcessMessage() == 0){
		ClearDrawScreen();

		my_make_block();
		my_get_key();
		my_move_block();
		my_draw_back();
		my_draw_variable();
		my_draw_block();
		my_draw_stage();
		my_fall_block();

		if(block_y_count > DRAW_BLOCK_WIDTH * 17){
			block_y_count = 0;
			block_y = 0;
		}

		ScreenFlip();
	}

	DxLib_End();
	return 0;
}

キー入力の「my_get_key()」と移動処理の「my_move_block()」を加えました。

画像(cdxb_4_3)

左右の壁を確認しながら落下します!

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

中間ソース3

それでは次回は底辺の当たり判定をつけたいと思います。

次回

五日目 当たり判定「底辺」

□ページの先頭へ□

□目次へ戻る□

□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時点)