vol.3 フィールド上の場面転換、村人の実装

目次

はじめに

前回まではフィールドの改造を主として行ってきましたが、今回からはいよいよ場面転換に入ります。
ドラクエのマップを想像してください。マップには町などがあって、プレイヤーがマップ上で町の上に
立とうとすると、その町に入ることができますよね。
今回はそういう別フィールドへの分岐を実装していきましょう。
これを応用していけばどんどんゲームの物語が展開できます。

フィールド転換

フィールド転換を実装するということで、前回まで実装されていたビームについての処理はコメントとして
省略していきます。
ちなみに、ソースコード中で長いコメントを作成するときは
/* ここに文字を入力 */
とすればできます。

さて、フィールド転換を実装していきましょう。
フィールド転換を実装するために、町を作成していきます。場所はどこでもいいですが、
今回はfieldの真ん中あたりの(4,4)に町を作成したいと思います。
町を作成するにあたって、fieldの更新に町の情報を入れ忘れないように注意しましょう。
町の実装は比較的容易なので、連続して町のフィールドについて実装していきます。

20×20で作成するこの町のフィールドは先ほどのフィールドと区別するために、◆で表現します。
町のフィールドでは(0,0)が入口(入)、(19,19)が出口(出)として、
町に出入りできるようにしましょう。
また、町から出たときは町の右側に出るようにします。

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

//縦・横を10で定義
#define WIDTH 10
#define HEIGHT 10
//町の縦・横を20で定義
#define M_WIDTH 20 //←←←
#define M_HEIGHT 20 //←←←

int main(void)
{
	int x, y;
	//while(1)脱出用 o:ループ 1:脱出
	int flag = 0;
	//プレイヤーのx座標、y座標
	int px = 0, py = 0;
	//町のx座標、y座標
	int mx = 4, my = 4; //←←←
	//キー入力用
	int key;

	//配列の3は、全角文字2バイト+終了コード \0 1バイト 合計3バイト分
	char field[HEIGHT][WIDTH][3]; //←←←
	char m_field[M_HEIGHT][M_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, "△");
			//x=mx=4,y=my=4のときは町を描画します。
			else if (x == mx && y == my)strcpy_s(field[y][x], 3, "町"); //←←←
			else strcpy_s(field[y][x], 3, "□");
		}
	}

	//m_fieldの初期化 今回はすべて◆
	for (y = 0; y < M_HEIGHT; y++){ //←←←
		for (x = 0; x < M_WIDTH; x++){ //←←←
			strcpy_s(m_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を初期化しておきます。
		strcpy_s(field[py][px], 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;
	
		default:
			break;

		}


		//町に入る判定
		if (px == mx && py == my){ //←←←
			//プレイヤーの座標を初期化
			px = 0, py = 0; //←←←

			while (1){ //←←←
				system("cls"); //←←←

				//(0,0)に入口
				strcpy_s(m_field[0][0], 3, "入"); //←←←
				//(M_WIDTH-1,M_HEIGHT)に出口
				strcpy_s(m_field[M_HEIGHT - 1][M_WIDTH-1], 3, "出"); //←←←
				//現在地
				strcpy_s(m_field[py][px], 3, "△"); //←←←

				//町の描画
				for (y = 0; y < M_HEIGHT; y++){ //←←←
					for (x = 0; x < M_WIDTH; x++){ //←←←
						printf("%s", m_field[y][x]); //←←←
					}
					printf("\n"); //←←←
				}
				//プレイヤーのx座標、y座標が変更されてしまう前に、あらかじめ現在のm_fieldを初期化しておきます。
				strcpy_s(m_field[py][px], 3, "◆"); //←←←

				key = _getch(); //←←←

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

					py--; //←←←
					break; //←←←
				case 's': //←←←
					if (py == M_HEIGHT - 1) break; //←←←

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

					px--; //←←←
					break; //←←←
				case 'd': //←←←
					if (px == M_WIDTH - 1) break; //←←←

					px++; //←←←
					break; //←←←
				default: //←←←
				        break; //←←←
				}

				strcpy_s(m_field[py][px], 3, "△"); //←←←
				
				if (py == M_HEIGHT - 1 && px == M_WIDTH - 1){ //←←←
					py = my, px = mx + 1; //←←←
					break; //←←←
				}
			}
		}

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

	}

		_getch();
		return 0;
	
}

村人実装

町には村人がいるものです。村人に話しかけられるようにしましょう。
村人の付近1マスにプレイヤーがいる状態で、cキーを押すと村人がしゃべってくれるようにしましょう。
村人に隣接しているすべてのマスをどのように表現するかがカギですね。
村人を(5,5)に設置します。

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

//縦・横を10で定義
#define WIDTH 10
#define HEIGHT 10
//町の縦・横を20で定義
#define M_WIDTH 20
#define M_HEIGHT 20

int main(void)
{
	int x, y;
	//while(1)脱出用 o:ループ 1:脱出
	int flag = 0;
	//プレイヤーのx座標、y座標
	int px = 0, py = 0;
	//町のx座標、y座標
	int mx = 4, my = 4;
	//村人Aのx座標、y座標
	int mbax = 5, mbay = 5; //←←←
	//キー入力用
	int key;

	//配列の3は、全角文字2バイト+終了コード \0 1バイト 合計3バイト分
	char field[HEIGHT][WIDTH][3];
	char m_field[M_HEIGHT][M_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, "△");
			//x=mx=4,y=my=4のときは町を描画します。
			else if (x == mx && y == my)strcpy_s(field[y][x], 3, "町");
			else strcpy_s(field[y][x], 3, "□");
		}
	}

	//m_fieldの初期化 今回はすべて◆
	for (y = 0; y < M_HEIGHT; y++){
		for (x = 0; x < M_WIDTH; x++){
			strcpy_s(m_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を初期化しておきます。
		strcpy_s(field[py][px], 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;


			
		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;

		}
		*/

		//町に入る判定
		if (px == mx && py == my){
			//プレイヤーの座標を初期化
			px = 0, py = 0;

			while (1){
				system("cls");

				//(0,0)に入口
				strcpy_s(m_field[0][0], 3, "入");
				//(M_WIDTH-1,M_HEIGHT)に出口
				strcpy_s(m_field[M_HEIGHT - 1][M_WIDTH-1], 3, "出");
				//村人Aを用意
				strcpy_s(m_field[mbay][mbax], 3, "人"); //←←←
				//現在地
				strcpy_s(m_field[py][px], 3, "△");

				//町の描画
				for (y = 0; y < M_HEIGHT; y++){
					for (x = 0; x < M_WIDTH; x++){
						printf("%s", m_field[y][x]);
					}
					printf("\n");
				}
				//プレイヤーのx座標、y座標が変更されてしまう前に、あらかじめ現在のm_fieldを初期化しておきます。
				strcpy_s(m_field[py][px], 3, "◆");

				key = _getch();

				switch (key){
				case 'w':
					if (py == 0 || (px==mbax && py-1==mbay)) break;

					py--;
					break;
				case 's':
					if (py == M_HEIGHT - 1 || (px==mbax && py+1==mbay)) break;

					py++;
					break;
				case 'a':
					if (px == 0 || (py==mbay && px-1==mbax)) break;

					px--;
					break;
				case 'd':
					if (px == M_WIDTH - 1 || (py==mbay && px+1==mbax)) break;

					px++;
					break;

					//村人と会話する判定
				case 'c': //←←←
					if ((mbax - 1 <= px && px <= mbax + 1) && (mbay - 1 <= py && py <= mbay + 1)){ //←←←
						printf("\n村人A : こんにちは!\n"); //←←←
						_getch(); //←←←
					}
					break; //←←←

				default:
					break;
				}

				strcpy_s(m_field[py][px], 3, "△");
				
				if (py == M_HEIGHT - 1 && px == M_WIDTH - 1){
					py = my, px = mx + 1;
					break;
				}
			}
		}

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

	}

		_getch();
		return 0;
	
}

おわりに

ここまでの内容でおおまかなゲームのフィールドに関する実装は全て終了しました。
あとは発想力次第なのですが、例えばある座標に行ったら別のある座標にテレポートするといったことも
充分実装できます。
次回からは「ステータス」について新たに実装していきたいと思います。
ステータスの実装には「構造体」という新しい概念が追加されるので、楽しみにしていてください。
お疲れさまでした。