vol.2 フィールド上でのビーム照射、死亡判定

目次

はじめに

今回はもう少しフィールドでいろいろな動作ができるようにしていきます。
まだプレイヤーが移動できるだけなので、様々な機能を追加していきましょう。

ビーム照射

移動キーとは別のキーを押すことによって一直線上に攻撃を繰り出すようなプログラムを実装していきます。
まだ攻撃を繰り出す「ような」プログラムなので、実際に攻撃をしているようには見えませんが、
そこはイメージを膨らませて...w

i,k,j,l,mキーを押すことによって、プレイヤーからそれぞれ上、下、左、右、右斜め上にビームが出ることとしましょう。
ビームは ■■■■■■■■ のように表現します。

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

//縦・横を10で定義
#define WIDTH 10
#define HEIGHT 10

int main(void)
{
	int x, y;
	//プレイヤーのx座標、y座標
	int px = 0, py = 0; 
	//キー入力用
	int key;

	//配列の3は、全角文字2バイト+終了コード \0 1バイト 合計3バイト分
	char field[HEIGHT][WIDTH][3];

	//fieldの初期化 今回はすべて□
	for (y = 0; y < HEIGHT; y++){
		for (x = 0; x < WIDTH; x++){
			//プレイヤーのx座標,y座標によってfieldの情報を変えます。
			if (x == px && y == py) strcpy_s(field[y][x], 3, "△"); 

			else strcpy_s(field[y][x], 3, "□"); 
		}
	}


	//無限ループにすることによって、画面の更新を繰り返していきます。
	while(1){

		//画面の更新
		system("cls");

		//fieldの表示
		for (y = 0; y < HEIGHT; y++){
			for (x = 0; x < WIDTH; x++){
				printf("%s", field[y][x]);
			}
			printf("\n");
		}
		
		//プレイヤーのx座標、y座標が変更されてしまう前に、あらかじめ現在のfieldを初期化しておきます。
		else strcpy_s(field[y][x], 3, "□");

		//キーを取得して、押されたキーによってプレイヤーのx座標、y座標を変更していきます。
		key = _getch();

		switch(key){
		case 'w':
			if (py == 0) break;

			py--;
			break;
		case 's':
			if (py == HEIGHT - 1) break;

			py++;
			break;
		case 'a':
			if (px == 0) break; 

			px--;
			break;
		case 'd':
			if (px == WIDTH - 1) break;

			px++;
			break;

		//ビームの表現
		case 'i': //←←←
			if (py == 0) break; //←←←

			for (y = py - 1; y >= 0; y--) //←←←
				strcpy_s(field[y][px], 3, "■"); //←←←
			break; //←←←
		case 'k': //←←←
			if (py == HEIGHT - 1) break; //←←←

			for (y = py + 1; y < HEIGHT; y++) //←←←
				strcpy_s(field[y][px], 3, "■"); //←←←
			break; //←←←
		case 'j': //←←←
			if (px == 0) break; //←←←

			for (x = px - 1;x >= 0; x--) //←←←
				strcpy_s(field[py][x], 3, "■"); //←←←
			break; //←←←
		case 'l': //←←←
			if (px == WIDTH - 1) break; //←←←

			for (x = px + 1; x < WIDTH; x++) //←←←
				strcpy_s(field[py][x], 3, "■"); //←←←
			break; //←←←
		case 'm': //←←←
			if (y == 0 || x == WIDTH - 1) break; //←←←

			for (y = py - 1, x = px + 1; y >= 0 ,x < WIDTH ; y-- ,x++) //←←←
				strcpy_s(field[y][x], 3, "■"); //←←←
			break; //←←←

		default:
			break;
		
		}

		//プレイヤーの新しいx座標、y座標を使ってfieldを更新します。
		strcpy_s(field[py][px], 3, "△");
		
	}

	_getch();
	return 0;
}

iキーを押したとき、ビームは上に照射されるようにプログラムするのですが、プレイヤーの1つ上からビームが描画されるので
プレイヤーのy座標が0だと困ります。なので、if文で場合分け。
for文を使ってまとめて縦にビームを入れます。
残りのキーも同様です。

mキーについてですが、for文が少々おかしな形をしていますが、ちゃんと動きます。
for文は
for(条件1;条件2;条件3) 命令
の形を満たしていれば問題ありません。
極論を言ってしまえば、while(1)をfor(;;)と書き換えることも可能となります。

死亡判定

さっきのコードだとビームの上にプレイヤーが乗ると、プレイヤーの新しいx座標、y座標によってfieldが更新され、
ビームがなくなってしまいます。
そもそもビームにあたったらプレイヤーはひとたまりもないはずですよね?
そこで、プレイヤーがビームにあたったらゲームオーバーとしましょう。
ゲームオーバーした時、その場でプレイヤーを × で表示してゲームオーバーと表示させます。

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

//縦・横を10で定義
#define WIDTH 10
#define HEIGHT 10

int main(void)
{
	int x, y;
	//while(1)脱出用 o:ループ 1:脱出
	int flag = 0; //←←←
	//ビームのx座標、y座標格納用のカウンタ変数
	int x1 = 0,  y1 = 0; //←←←
	//プレイヤーのx座標、y座標
	int px = 0, py = 0; 
	//キー入力用
	int key;

	//配列の3は、全角文字2バイト+終了コード \0 1バイト 合計3バイト分
	char field[HEIGHT][WIDTH][3];

	//ビームの座標保存用
	int bx[100],by[100]; //←←←


	//fieldの初期化 今回はすべて□
	for (y = 0; y < HEIGHT; y++){
		for (x = 0; x < WIDTH; x++){
			//プレイヤーのx座標,y座標によってfieldの情報を変えます。
			if (x == px && y == py) strcpy_s(field[y][x], 3, "△"); 

			else strcpy_s(field[y][x], 3, "□"); 
		}
	}


	//無限ループにすることによって、画面の更新を繰り返していきます。
	while(1){

		//画面の更新
		system("cls");

		//fieldの表示
		for (y = 0; y < HEIGHT; y++){
			for (x = 0; x < WIDTH; x++){
				printf("%s", field[y][x]);
			}
			printf("\n");
		}
		
		//プレイヤーのx座標、y座標が変更されてしまう前に、あらかじめ現在のfieldを初期化しておきます。
		else strcpy_s(field[y][x], 3, "□");

		//キーを取得して、押されたキーによってプレイヤーのx座標、y座標を変更していきます。
		key = _getch();

		switch(key){
		case 'w':
			if (py == 0) break;

			py--;
			break;
		case 's':
			if (py == HEIGHT - 1) break;

			py++;
			break;
		case 'a':
			if (px == 0) break; 

			px--;
			break;
		case 'd':
			if (px == WIDTH - 1) break;

			px++;
			break;

		//ビームの表現
		case 'i': 
			if (py == 0) break; 

			for (y = py - 1; y >= 0; y--) {
				strcpy_s(field[y][px], 3, "■"); 
				//ビームのx座標、y座標を格納していく
				bx[x1] = px; //←←←
				by[y1] = y; //←←←
				x1++; //←←←
				y1++; //←←←
                        }
			break; 
		case 'k': 
			if (py == HEIGHT - 1) break; 

			for (y = py + 1; y < HEIGHT; y++) {
				strcpy_s(field[y][px], 3, "■"); 
			//ビームのx座標、y座標を格納していく
				bx[x1] = px; //←←←
				by[y1] = y; //←←←
				x1++; //←←←
				y1++; //←←←         
                      }               
			break; 
		case 'j': 
			if (px == 0) break; 

			for (x = px - 1;x >= 0; x--) {
				strcpy_s(field[py][x], 3, "■"); 
                       //ビームのx座標、y座標を格納していく
				bx[x1] = x; //←←←
				by[y1] = py; //←←←
				x1++; //←←←
				y1++; //←←←
			}
			break; 
		case 'l': 
			if (px == WIDTH - 1) break; 

			for (x = px + 1; x < WIDTH; x++) {
				strcpy_s(field[py][x], 3, "■"); 
				//ビームのx座標、y座標を格納していく
				bx[x1] = x; //←←←
				by[y1] = py; //←←←
				x1++; //←←←
				y1++; //←←←
			}
			break; 
		case 'm': 
			if (y == 0 || x == WIDTH - 1) break; 

			for (y = py - 1, x = px + 1; y >= 0 ,x < WIDTH ; y-- ,x++) {
				strcpy_s(field[y][x], 3, "■"); 
                                //ビームのx座標、y座標を格納していく
				bx[x1] = x; //←←←
				by[y1] = y; //←←←
				x1++; //←←←
				y1++; //←←←
                        }
			break; 

		default:
			break;
		
		}

		//プレイヤーの新しいx座標、y座標を使ってfieldを更新します。
                for (x = 0, y = 0; x <= x1, y <= y1; x++, y++){ //←←←
			if (px == bx[x] && py == by[y]){ //←←←
				flag = 1; //←←←
				break; //←←←
			}
		}
		
		if (flag == 1){ //←←←
			system("cls"); //←←←
			for (y = 0; y < HEIGHT; y++){ //←←←
				for (x = 0; x < WIDTH; x++){ //←←←
					if (x == px && y == py) strcpy_s(field[y][x], 3, "×"); //←←←
					else strcpy_s(field[y][x], 3, "□"); //←←←
				}
			}
			for (y = 0; y < HEIGHT; y++){ //←←←
				for (x = 0; x < WIDTH; x ++){ //←←←
					printf("%s", field[y][x]); //←←←
				}
				printf("\n"); //←←←
			}
			break; //←←←
		
		}

		strcpy_s(field[py][px], 3, "△");
		
	}

        printf("Game Over...\n"); //←←←

	_getch();
	return 0;
}

おわりに

今回はビームを照射し、死亡判定をするまで至りました。
死亡判定が少々クセのあるプログラムとなるので、今回はこの2題にて終わりたいと思います。
for文の珍しい使い方、座標を保存するということ、flagを用いたループ脱出法が今回のメインテーマでした。
お疲れ様でした。