広告
↓発売日:2018年09月22日↓
![]() |
新品価格 |
当たり判定のお時間です!今回は底辺の当たり判定とともにブロックを固定するトコロまでをやっていきたいと思います。
前回作った左右の当たり判定用の関数を少し変えて底辺の当たり判定用関数を作っていきます。
void my_collision_bottom(){
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 + 1)][block_x + x] != 0){
collision_flag = 1;
}
}
}
}
}
底辺の当たり判定になるので「y座標+1」の部分を調べれば大丈夫ですね。
今回からブロックが固定された後にブロックが再生成されるのでその処理を加えたいと思います。
void my_make_block(){
int x,y;
if(make_block_flag == 1){
for(y=0;y<BLOCK_HEIGHT;y++){
for(x=0;x<BLOCK_WIDTH;x++){
block[y][x] = blocks[y][x];
}
}
make_block_flag = 0;
}
}
ブロックを作る「my_make_block()」にブロックを生成するかどうかのフラグ「int make_block_flag」を加えました。
「make_block_flag == 1」の時にブロックを作ります。
今回はまだ四角いブロック一種類のみなので何の意味があるのかと思うトコロですがそのへんはもう少し後半にお話しします。
それではこれらを使ってブロックを固定していきます。
ブロック固定と言われると何か複雑な事をしそうな気がしますが、
1・底辺の当たり判定を調べる
2・当たり判定があれば現在の「block」の状態を「stage」に保存する
3・ブロックの座標を元に戻す
だけで意外と簡単にブロックは固定されます。
現在の「block」を「stage」に保存する「my_save_block()」です。
void my_save_block(){
int x,y;
for(y=0;y<BLOCK_HEIGHT;y++){
for(x=0;x<BLOCK_WIDTH;x++){
stage[block_y + y][block_x + x] += block[y][x];
}
}
}
言葉通りそのまま保存しているだけなので特に説明はいらないですね。
続いてブロックの座標を元に戻す「my_init_var2()」になります。
void my_init_var2(){
block_x = 7;
block_y = 0;
block_y_count = 0;
make_block_flag = 1;
}
ブロックの座標を元の位置に戻してあげます。
さきほどのブロック生成用のフラグも初期化します。
あとはこれらを組み合わせるだけです。
ブロック固定の「my_fix_block()」です。
void my_fix_block(){
my_collision_bottom();
if(collision_flag != 0){
my_save_block();
my_init_var2();
}
}
1・底辺の当たり判定を調べる
2・当たり判定があれば現在の「block」の状態を「stage」に保存する
3・ブロックの座標を元に戻す
の手順通りにブロックを固めるだけですね!
ブロック固定!
この時点で実行しても特に違和感がないので見落としがちですが、このままではブロックを固定した後にも「block_y++」の処理が一度行われるので一つ落ちた状態からブロックが現れてしまいます。
なので「my_fall_block」に少し手を加えます。
void my_fall_block(){
if(make_block_flag == 0){
block_y_count += block_speed;
block_y = block_y_count / DRAW_BLOCK_WIDTH;
}
}
ここでさきほどの「make_block_flag」が意味を成します。
ブロック生成中でなければ「block_y++」みたいな感じですね。
これでブロック固定後にブロックが下がってしまう事を防ぐ事ができます。
広告
さきほどの底辺の当たり判定用関数を使ってブロック降下処理も作ります。
if(key[KEY_INPUT_DOWN] % 5 == 1){
my_collision_bottom();
if(collision_flag == 0){
block_y++;
block_y_count = block_y * DRAW_BLOCK_WIDTH;
}
}
キー入力の「my_move_block()」内、「KEY_INPUT_DOWN」矢印キー下を押した場合の処理です。
さきほどの「my_collision_bottom();」を使って当たり判定がなければ「block_y++」、
そして「block_y_count」をそこに合わせてあげるように「block_y_count = block_y * DRAW_BLOCK_WIDTH;」と計算します。
ついでにゲームオーバーも作ってしまいます。
ブロックパズルにおいてのゲームオーバーの条件はブロック再生成時にそこにすでにあるブロックと重なってしまった場合なのでまずは重なった場合の当たり判定用関数を作ります。
void my_collision_center(){
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] != 0){
collision_flag = 1;
}
}
}
}
}
ブロックと重なってしまった場合なのでその場の判定ですね。
それではゲームオーバー判定用の関数を見てみます。
void my_gameover(){
my_collision_center();
if(collision_flag != 0){
gameover_flag = 1;
}
}
さきほどの関数を使ってゲームオーバー用に用意したフラグ「int gameover_flag」の切り替えをします。
これでゲームオーバーの判定ができるようになりました。
あとは「int main()」にゲームオーバーの条件を加えるだけです。
今回から「switch」文を使って初期化→ゲームループ→ゲームオーバーそれぞれを場面分けしていきます。
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
ChangeWindowMode(TRUE);
DxLib_Init();
SetDrawScreen(DX_SCREEN_BACK);
my_init_var();
while(ProcessMessage() == 0){
ClearDrawScreen();
switch(game_state){
case 0:
game_state = 5;
break;
case 5:
my_make_block();
my_gameover();
my_get_key();
my_move_block();
my_draw_back();
my_draw_variable();
my_draw_block();
my_draw_stage();
my_fix_block();
my_fall_block();
if(gameover_flag == 1){
game_state = 10;
}
break;
case 10:
my_draw_back();
my_draw_block();
my_draw_stage();
my_ed();
break;
default:
break;
}
ScreenFlip();
}
DxLib_End();
return 0;
}
「int game_state」という場面を表す変数を用意してそれぞれの場面分けをしております。
今回はゲームが始まってゲームオーバーになるまで一方通行ですが、次のステージに行きたい、ゲームオーバーになった時に最初からやり直させたいなどの処理を入れたい時はこの「switch」で分けた場面をもとにもどして再初期化などして対応します。
ゲームオーバー!
ここまでの中間ソースになります。
それでは次回はブロックの種類を増やすのと横一列が揃ったらブロックを消去してみたいと思います。
広告
↓発売日:2016年02月29日↓
![]() |
12歳からはじめる ゼロからのC言語 ゲームプログラミング教室 新品価格 |
↓発売日:2018年06月22日↓
![]() |
新品価格 |
↓発売日:2018年03月09日↓
![]() |
新品価格 |
↓発売日:2017年06月14日↓
![]() |
新品価格 |
↓発売日:2018年05月21日↓
![]() |
新品価格 |
↓発売日:2017年12月07日↓
![]() |
新品価格 |
↓発売日:2017年02月08日↓
![]() |
新・明解C言語で学ぶアルゴリズムとデータ構造 (明解シリーズ) 新品価格 |
↓発売日:2017年09月26日↓
![]() |
新品価格 |