配列を用いたゲームのマップの作り方

前置き

はじめまして、C言語DXライブラリだけでゲームを作っている朕です!!
C言語とプログラミングの面白さを伝えたいので、作ったプログラムを紹介していきます!!

今回は1年生がプログラミング演習1で配列を学ぶようなので、配列を用いたゲームのマップを作る方法を紹介していきます!!

ideoneでも可能なサンプルコードも置いてあるので、このnoteを読んでほかの生徒に自慢しちゃおう!!!!

作ったゲームの紹介

今回紹介するプログラムは私が作ったゲーム、

「おぼれ死ぬBOちゃん!!!!!!!!!!!」 
リンク -> "kfip-games.link
"

に使用されているコードです!!

おぼれ死ぬBOちゃん!!!!!!!!!!!

ゲーム中のコードの紹介

さて、本題のプログラム紹介に移ります。ゲームのプログラム中から抜き出しているのでこれだけでは動かない&DXライブラリを使用しているので理解できなくても問題ありません!!

ドーーーーーン!!!!!!!

const int MAP_SIZE_X = 32;  						//マップチップx サイズ
const int MAP_SIZE_Y = 32;							//マップチップy サイズ
const int NUM_CHIP_X = 20;							//マップチップx 数
const int NUM_CHIP_Y = 15;							//マップチップy 数
//マップ
int MapData1[] = {
	337,337,337,337,337, 337,337,337,337,337, 337,337,337,337,337, 337,337,337,337,337,
	003,003,003,003,003, 003,003,003,003,003, 003,003,003,003,003, 003,337,337,337,337,
	003,003,003,003,003, 003,003,003,003,003, 003,003,003,003,003, 003,337,337,337,337,
	337,337,003,003,003, 337,337,337,337,337, 337,337,337,337,003, 003,337,337,337,337,
	337,337,003,003,003, 003,003,003,003,003, 003,003,003,003,003, 337,337,337,337,337,

	337,337,003,003,003, 003,003,003,003,003, 003,003,003,003,003, 337,337,337,337,337,
	337,337,337,003,003, 337,337,337,337,337, 337,337,337,337,337, 337,337,337,337,337,
	337,337,337,003,003, 337,337,337,337,337, 337,337,337,337,337, 337,337,337,337,337,
	337,337,337,003,003, 337,337,337,337,337, 337,337,337,337,337, 337,337,337,337,337,
	337,337,337,003,003, 337,337,337,337,337, 337,337,337,337,337, 337,337,337,337,337,

	337,337,337,337,003, 003,003,003,003,003, 003,003,003,003,003, 337,337,337,337,337,
	337,337,337,337,003, 003,003,003,003,003, 003,003,003,003,003, 003,003,337,337,337,
	337,337,337,337,337, 337,337,337,337,337, 337,337,337,003,003, 003,003,003,003,063,
	337,337,337,337,337, 337,337,337,337,337, 337,337,337,337,337, 337,003,003,003,063,
	337,337,337,337,337, 337,337,337,337,337, 337,337,337,337,337, 337,337,337,337,337,
};
while (1) {
	    if (ProcessMessage() != 0)  break;      //メッセージ処理
		if (ClearDrawScreen() != 0)  break;     //画面消去
		GetHitKeyStateAll(keys);				//キーの入力を待つ

		//マップの描写
		for (int i = 0; i < NUM_CHIP_X; i++) {
			for (int j = 0; j < NUM_CHIP_Y; j++) {
				int spot = MapData1[i + j * NUM_CHIP_X];		//マップチップの数字を得る
				if (spot == 003) {
					DrawGraph(i * MAP_SIZE_X, j * MAP_SIZE_Y, field[spot], FALSE);
				}
				else if (spot == 337) {
					DrawGraph(i * MAP_SIZE_X, j * MAP_SIZE_Y, river[spot % 192], FALSE);
				}
				else if (spot == 063) {
					DrawGraph(i * MAP_SIZE_X, j * MAP_SIZE_Y, field[spot], FALSE);
				}
			}
         }
}

きっっっったないコードですね~!!!
これを改善してideoneでも動くコードにして説明します!!

ideoneでも動くサンプルコード

はい!!このコードならこのままideoneにコピペしても動きます!!

ただ、ideoneにはDXライブラリをインポートしたり、画像をインストールできないので、ちょっとしょぼいですw

#include <stdio.h>

#define ScreenHeight 5			//画面の高さ
#define ScreenWidth 20			//画面の幅

//マップ a->空気,g->地面,m->山,t->木,b->箱
const char Map[ScreenHeight][ScreenWidth] = {
	"aaaaaaaaaaaaaaabbaaa",
	"aamaaaaaaaaaabbaaaaa",
	"ammmaaaaaaabbaaaaaaa",
	"mmmmmaaaabbaaaattttt",
	"gggggggggggggggggggg",
};

int main(void) {
	static char point = 0;
	for(int i=0 ; i<ScreenHeight ; i++){
		for(int j=0 ; j<ScreenWidth ; j++){
			point = Map[i][j];
			if(point == 'a'){
				printf(" ");
			}
			else if(point == 'g'){
				printf("■");
			}
			else if(point == 't'){
				printf("Y");
			}
			else if(point == 'm'){
				printf("^");
			}
			else if(point =='b'){
				printf("□");
			}
		}
		printf("\n");
	}
	return 0;
}
出力

解説

まず、最初の行の

#define ScreenHeight 5			//画面の高さ
#define ScreenWidth 20			//画面の幅

ここ、なんじゃこりゃ!!って思ったかもしれません。
大丈夫です、テストには出ません^^

これは「マクロ」という機能で「定数」に名前を与えるものです!!
簡単に言うとあだなのことで、画面の高さはScreenHeightと入力するだけで5を、画面の幅はScreenWidthと入力するだけで20を取得することが可能です。これの素晴らしさは記事の最後に書きますね!!

次に

//マップ a->空気,g->地面,m->山,t->木,b->箱
const char Map[ScreenHeight][ScreenWidth] = {
	"aaaaaaaaaaaaaaabbaaa",
	"aamaaaaaaaaaabbaaaaa",
	"ammmaaaaaaabbaaaaaaa",
	"mmmmmaaaabbaaaattttt",
	"gggggggggggggggggggg",
};

これはMap[ScreenHeight][ScreenWidth]という2重配列を宣言し、指定しているところです。charの前に書いてあるconstは変数の値を変更できなくする効果があります!!
読み取り専用の変数として宣言し、後から書き換えができなくなるので、今回のようなマップのようにあとから変更することのない変数につけると、間違えて書き換える心配がなくなります!!

aはair(空気)、bはbox(箱)、gはground(地面)、mはmountain(山)、tはtree(木)を表しています。

次にmain関数を見ていきます!!

static char point = 0;
	for(int i=0 ; i<ScreenHeight ; i++){
		for(int j=0 ; j<ScreenWidth ; j++){
			point = Map[i][j];
			if(point == 'a'){
				printf(" ");
			}
			else if(point == 'g'){
				printf("■");
			}
			else if(point == 't'){
				printf("Y");
			}
			else if(point == 'm'){
				printf("^");
			}
			else if(point =='b'){
				printf("□");
			}
		}
		printf("\n");
	}

まず、変数pointは二重配列Mapから1文字取得するための変数です。2重for文でMap[i][j]にある文字を変数pointに格納し、if文でその文字が何かを判別し、それに応じた図形をprintfで出力しています!!

本当はここはswicth文を使った方が美しいんですが、まだ習っていないと思うのでif文で書いてみました。(書けないわけじゃないんです!!本当ですよ信じてください!!!)


あとがき

読んでくれてありがとうございました!!
紹介したゲームのコードを読めるようになりたい、ゲームを作りたい!!って人はぜひ、ゲーム制作サークルKFIPへ来てください!!
ブロック崩しやシューティングゲームの制作講座やC言語勉強会などのイベントが盛りだくさん!!ボードゲームもしてるよ!!

先ほど後回しにしたマクロを使用するメリットは以下にまとめておきます!!

  1. 名前をつけることで、どのような変数かわかりやすいため読みやすい

  2. 後から変更しやすい -> 今回だと画面の高さと幅の変更があった場合、for文のループ回数をわざわざ変更しなくて済む

素晴らしいですね~!!!!


この記事が気に入ったらサポートをしてみませんか?