Skip to content

Instantly share code, notes, and snippets.

@KentaroAOKI
Created April 29, 2021 02:13
Show Gist options
  • Save KentaroAOKI/fcf4b732f2cd2d04283cae26f69ef230 to your computer and use it in GitHub Desktop.
Save KentaroAOKI/fcf4b732f2cd2d04283cae26f69ef230 to your computer and use it in GitHub Desktop.
// 初学者のためのゲームプログラミング
// #01 とりあえず動かしてみよう
// ゲームのルール
// - 主人公(MAN("a"))を動かしてブロック(BLOCK(","))をゴール(GOAL("O"))に移動
// - ステージ全てのブロック(BLOCK)をゴール(GOAL)に移動させたら終了
#include <iostream>
// ステージのMAPデータ
const char gStageData[] = "\
########\n\
#a #\n\
# , #\n\
# , #\n\
# O O#\n\
########";
// ステージのMAPサイズ
const int gStageWidth = 8;
const int gStageHeight = 6;
// ステージ上のオブジェクト識別番号
enum Object {
OBJ_SPACE,
OBJ_WALL,
OBJ_GOAL,
OBJ_BLOCK,
OBJ_BLOCK_ON_GOAL,
OBJ_MAN,
OBJ_MAN_ON_GOAL,
OBJ_UNKNOWN,
};
// プロトタイプ宣言
// ステージのマップデータからゲームの状態(state)を作成
void initialize(Object* state, int w, int h, const char* stageData);
// ゲームの状態(state)からゲーム画面を出力
void draw(const Object* state, int w, int h);
// 入力(input)状態から、主人公(MAN)とブロック(BLOCK)を動かしてゲームの状態(state)を更新
void update(Object* state, char input, int w, int h);
// 全てのブロック(BLOCK)がゴール(GOAL)に置かれているか確認 全てゴールに置かれていたらtrueを返す
bool checkClear(const Object* state, int w, int h);
void initialize(Object* state, int width, int height, const char* stageData) {
const char* d = stageData;
int x = 0;
int y = 0;
while (*d != NULL)
{
Object t;
switch (*d)
{
case ' ': t = OBJ_SPACE; break;
case '#': t = OBJ_WALL; break;
case 'O': t = OBJ_GOAL; break;
case ',': t = OBJ_BLOCK; break;
case 'Q': t = OBJ_BLOCK_ON_GOAL; break;
case 'a': t = OBJ_MAN; break;
case '@': t = OBJ_MAN_ON_GOAL; break;
case '\n':
x = 0;
++y;
t = OBJ_UNKNOWN;
break;
default: t = OBJ_UNKNOWN; break;
}
++d;
if (t != OBJ_UNKNOWN) {
state[y * width + x] = t;
x++;
}
}
}
void draw(const Object* state, int width, int height) {
const char font[] = { ' ', '#', 'O', ',', 'Q', 'a', '@' };
// 画面消去
std::cout << "\x1B[2J\x1B[H";
// ゲームの状態(state)からゲーム画面を出力(左上から右下まで順に描く)
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
Object o = state[y * width + x];
std::cout << font[o];
}
std::cout << std::endl;
}
}
void update(Object* state, char input, int w, int h) {
// 入力(input)状態によって主人公(MAN)の相対的な移動先を決定
int dx = 0;
int dy = 0;
switch (input) {
case 'a':
dx = -1;
break;
case 's':
dx = 1;
break;
case 'w':
dy = -1;
break;
case 'z':
dy = 1;
break;
}
// 主人公(MAN)の場所(x, y)をゲームの状態(state)から探す
int i = 0;
for (i = 0; i < w * h; ++i) {
if (state[i] == OBJ_MAN || state[i] == OBJ_MAN_ON_GOAL) {
break;
}
}
int x = i % w;
int y = i / w;
// 主人公(MAN)の移動先(tx, ty)を計算
int tx = x + dx;
int ty = y + dy;
if (tx < 0 || ty < 0 || tx >= w || ty >= h) {
return;
}
// ゲームの状態(state)を更新する
int p = y * w + x;
int tp = ty * w + tx;
if (state[tp] == OBJ_SPACE || state[tp] == OBJ_GOAL) {
// 移動先が空きかゴールであれば、主人公(MAN)の移動先と移動元の状態(state)を更新する
state[tp] = (state[tp] == OBJ_GOAL) ? OBJ_MAN_ON_GOAL : OBJ_MAN;
state[p] = (state[p] == OBJ_MAN_ON_GOAL) ? OBJ_GOAL : OBJ_SPACE;
}
else if (state[tp] == OBJ_BLOCK || state[tp] == OBJ_BLOCK_ON_GOAL) {
// 移動先がブロックであれば、ブロックを動かすことができるか確認する
int tx2 = tx + dx;
int ty2 = ty + dy;
if (tx2 < 0 || ty2 < 0 || tx2 >= w || ty2 >= h) {
return;
}
int tp2 = (ty + dy) * w + (tx + dx);
if (state[tp2] == OBJ_SPACE || state[tp2] == OBJ_GOAL) {
// ブロックの移動先が空きかゴールであれば、ブロック(BLOCK)と主人公(MAN)の移動先と移動元の状態(state)を更新する
state[tp2] = (state[tp2] == OBJ_GOAL) ? OBJ_BLOCK_ON_GOAL : OBJ_BLOCK;
state[tp] = (state[tp] == OBJ_BLOCK_ON_GOAL) ? OBJ_MAN_ON_GOAL : OBJ_MAN;
state[p] = (state[p] == OBJ_MAN_ON_GOAL) ? OBJ_GOAL : OBJ_SPACE;
}
}
}
bool checkClear(const Object* state, int width, int height) {
// ゲームの状態(state)にブロック(ゴールに移動されていないブロック)が存在すればfalse
for (int i = 0; i < width * height; ++i) {
if (state[i] == OBJ_BLOCK) {
return false;
}
}
return true;
}
int main()
{
char input;
Object* state = new Object[gStageWidth * gStageHeight];
initialize(state, gStageWidth, gStageHeight, gStageData);
while (true)
{
// メインループ
draw(state, gStageWidth, gStageHeight);
if (checkClear(state, gStageWidth, gStageHeight)) {
break;
}
std::cout << "a:left s:right w:up z:down. What direction do you move?" << std::endl;
std::cin >> input;
update(state, input, gStageWidth, gStageHeight);
}
delete[] state;
state = NULL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment