C言語 ゲームでのマップ切り替え
Q&A
Closed
解決したいこと
C言語で軽いゲームのようなものを作っています。いわゆる迷路ゲームのようなものです。
そこでマップの切り替えを行いたいのですがうまくいきません。
例えばソースコード中の二次元配列のmap[][100]をmap2[][100]に書き換える処理を考えたのですが、うまいことできません。どうすればできるでしょうか。
具体的には、ソースコード222行目にあるように、'N'キーを押したら別のマップに推移するようにしたいです。
該当するソースコード
#include <stdio.h>
#include <ncurses.h> // 今回の表示全般に必要
#include <stdlib.h> // system()に必要
#include <locale.h> // setlocale()による表示日本語化に必要
// map[][]の要素やCOLOR_PAIR()を参照するときに使うあだ名
#define HERO 1
#define EXIT 2
#define WALL 3
#define ROAD 4
#define HAKO 5
#define KAGI 6
#define MESG 10
// ヒーローの上下左右のマスを参照するときのあだ名
#define HERO_UPPER map[hero_y - 1][hero_x] // ヒーローの1個上のマス
#define HERO_UPPER2 map[hero_y - 2][hero_x] // ヒーローの2個上のマス
#define HERO_LOWER map[hero_y + 1][hero_x] // ヒーローの1個下のマス
#define HERO_LOWER2 map[hero_y + 2][hero_x] // ヒーローの2個下のマス
#define HERO_LEFT map[hero_y][hero_x - 1] // ヒーローの1個左のマス
#define HERO_LEFT2 map[hero_y][hero_x - 2] // ヒーローの2個左のマス
#define HERO_RIGHT map[hero_y][hero_x + 1] // ヒーローの1個右のマス
#define HERO_RIGHT2 map[hero_y][hero_x + 2] // ヒーローの2個右のマス
// ゲーム中の状態
#define LOCKED 1 // 未回収の鍵があり出口が閉じている状態
#define UNLOCKED 2 // 鍵を全部回収して出口が開いた状態
#define FINISHED 3 // 出口から脱出してゲームをクリアした状態
#define GAMEOVER 4
// getch()でのキー入力の待ち時間(単位:ms)
// 永久ループのインターバルを兼ねている
#define GETCH_WAIT 100
// このゲームの配色を設定する
void setup_my_colors(void)
{
// 使える色名はCOLOR_{BLACK|RED|GREEN|YELLOW|BLUE|MAGENTA|CYAN|WHITE}
init_color(COLOR_BLACK, 0, 0, 0); //RGB成分を0〜1000で指定
init_color(COLOR_WHITE, 1000, 1000, 1000);
init_color(COLOR_CYAN, 200, 800, 1000);
init_color(COLOR_GREEN, 200, 1000, 300);
init_color(COLOR_BLUE, 200, 300, 450);
init_color(COLOR_YELLOW, 1000, 1000, 200);
init_pair(HERO, COLOR_CYAN, COLOR_BLACK);
init_pair(EXIT, COLOR_GREEN, COLOR_BLACK);
init_pair(WALL, COLOR_BLUE, COLOR_BLUE);
init_pair(ROAD, COLOR_BLACK, COLOR_BLACK);
init_pair(HAKO, COLOR_YELLOW, COLOR_BLACK);
init_pair(KAGI, COLOR_WHITE, COLOR_BLACK);
init_pair(MESG, COLOR_WHITE, COLOR_BLACK);
}
void put_mesg_count(int y, int x, int n)
{
attrset(COLOR_PAIR(MESG));
mvprintw(y, x * 2, "残り歩数:%d", n);
}
// ヒーロー「大」を指定の座標に表示する関数(👻🐘🐧等で代替可)
void put_hero(int y, int x)
{
attrset(COLOR_PAIR(HERO)); mvaddstr(y, x * 2, "大");
}
// 出口「且」を指定の座標に表示する関数(🚪等で代替可)
void put_exit(int y, int x)
{
attrset(COLOR_PAIR(EXIT)); mvaddstr(y, x * 2, "且");
}
// 壁を指定の座標に表示する関数(全角空白、⛰等で代替可)
void put_wall(int y, int x)
{
attrset(COLOR_PAIR(WALL)); mvaddstr(y, x * 2, " ");
}
// 道を指定の座標に表示する関数(全角空白)
void put_road(int y, int x)
{
attrset(COLOR_PAIR(ROAD)); mvaddstr(y, x * 2, " ");
}
// 箱「田」を指定の座標に表示する関数(📦🗿💩等で代替可)
void put_hako(int y, int x)
{
attrset(COLOR_PAIR(HAKO)); mvaddstr(y, x * 2, "田");
}
// 鍵「¶」を指定の座標に表示する関数(🔑🗝💍等で代替可)
void put_kagi(int y, int x)
{
attrset(COLOR_PAIR(KAGI)); mvaddstr(y, x * 2, "¶");
}
// 一般的なメッセージを指定の座標に表示する関数
void put_mesg_main(int y, int x, char s[])
{
attrset(COLOR_PAIR(MESG)); mvaddstr(y, x * 2, s);
}
// 未回収の鍵の個数を指定の座標に表示する関数
void put_mesg_kagi(int y, int x, int n)
{
attrset(COLOR_PAIR(MESG));
mvprintw(y, x * 2, "Uncollected ¶ × %d", n);
// 🔑🗝💍等を使う場合はここの絵文字↑もそれに合わせること
}
int main(void)
{
// マップ1 ここから ------------------------------
int map_size_y = 13; // マップの縦幅
int map_size_x = 16; // マップの横幅
int hero_y = 5; // ヒーローのy座標の初期値
int hero_x = 13; // ヒーローのx座標の初期値
int uncollected_keys = 4; // 拾わなくてはならない鍵の個数
int count = 70;
// 2:出口、3:壁、4:道、5:箱、6:鍵
int map[][100] = { // とりあえずガバッっと大きめに横100で確保してある
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4 },
{ 4, 3, 6, 4, 4, 3, 3, 4, 3, 4, 4, 6, 3, 4, 3, 4 },
{ 4, 3, 3, 5, 4, 4, 4, 4, 4, 5, 4, 4, 5, 5, 3, 4 },
{ 4, 3, 6, 4, 3, 5, 4, 5, 4, 3, 5, 4, 5, 4, 3, 4 },
{ 4, 3, 3, 4, 4, 5, 4, 5, 4, 3, 4, 5, 3, 4, 3, 4 },
{ 4, 3, 2, 5, 4, 4, 3, 4, 5, 4, 4, 5, 4, 4, 3, 4 },
{ 4, 3, 3, 4, 4, 4, 4, 5, 4, 6, 3, 3, 5, 4, 3, 4 },
{ 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
};
// マップ1 ここまで ------------------------------
// マップ2 ここから ------------------------------
int map_size_y = 16; // マップの縦幅
int map_size_x = 19; // マップの横幅
int hero_y = 8; // ヒーローのy座標の初期値
int hero_x = 6; // ヒーローのx座標の初期値
int uncollected_keys = 9; // 拾わなくてはならない鍵の個数
// 2:出口、3:壁、4:道、5:箱、6:鍵
int map[][100] = { // とりあえずガバッっと大きめに横100で確保してある
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4 },
{ 4, 3, 4, 5, 4, 4, 4, 4, 3, 3, 3, 3, 4, 5, 4, 3, 4 },
{ 4, 3, 4, 5, 3, 3, 4, 4, 4, 4, 5, 4, 4, 4, 6, 3, 4 },
{ 4, 3, 6, 4, 3, 6, 5, 5, 5, 6, 3, 3, 4, 5, 4, 3, 4 },
{ 4, 3, 5, 3, 4, 3, 4, 2, 5, 3, 3, 6, 3, 3, 5, 3, 4 },
{ 4, 3, 4, 4, 4, 3, 5, 4, 4, 5, 4, 5, 4, 4, 6, 3, 4 },
{ 4, 3, 6, 3, 5, 5, 5, 3, 4, 3, 4, 3, 4, 3, 3, 3, 4 },
{ 4, 3, 3, 6, 4, 5, 4, 4, 4, 3, 4, 3, 6, 3, 3, 3, 4 },
{ 4, 3, 3, 4, 3, 4, 3, 3, 3, 3, 4, 4, 5, 4, 3, 3, 4 },
{ 4, 3, 4, 4, 5, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 4 },
{ 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
};
// マップ2 ここまで ------------------------------
***/
/***
// マップ3 ここから ------------------------------
int map_size_y = 18; // マップの縦幅
int map_size_x = 20; // マップの横幅
int hero_y = 15; // ヒーローのy座標の初期値
int hero_x = 2; // ヒーローのx座標の初期値
int uncollected_keys = 9; // 拾わなくてはならない鍵の個数
// 2:出口、3:壁、4:道、5:箱、6:鍵
int map[][100] = { // とりあえずガバッっと大きめに横100で確保してある
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4 },
{ 4, 3, 4, 4, 4, 4, 4, 3, 3, 3, 3, 6, 3, 4, 4, 4, 4, 4, 3, 4 },
{ 4, 3, 4, 3, 3, 3, 4, 3, 6, 4, 5, 4, 6, 4, 4, 3, 3, 4, 3, 4 },
{ 4, 3, 4, 3, 3, 3, 4, 3, 4, 3, 4, 3, 6, 3, 3, 3, 4, 4, 3, 4 },
{ 4, 3, 4, 3, 4, 4, 4, 3, 4, 3, 4, 3, 4, 4, 4, 4, 4, 4, 3, 4 },
{ 4, 3, 4, 3, 5, 5, 5, 4, 4, 3, 4, 3, 5, 3, 3, 5, 5, 5, 3, 4 },
{ 4, 3, 2, 3, 4, 6, 4, 3, 3, 3, 4, 4, 5, 6, 3, 4, 6, 4, 3, 4 },
{ 4, 3, 4, 3, 5, 5, 5, 4, 4, 3, 3, 4, 3, 4, 4, 5, 5, 5, 3, 4 },
{ 4, 3, 4, 3, 4, 4, 4, 3, 4, 3, 4, 4, 3, 3, 3, 4, 4, 4, 3, 4 },
{ 4, 3, 4, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4 },
{ 4, 3, 4, 3, 3, 3, 4, 3, 6, 4, 4, 5, 4, 4, 4, 3, 3, 4, 3, 4 },
{ 4, 3, 4, 4, 4, 4, 4, 3, 3, 3, 3, 6, 3, 4, 4, 4, 4, 4, 3, 4 },
{ 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4 },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
};
// マップ3 ここまで ------------------------------
***/
int state = LOCKED; // 状態(LOCKED, UNLOCKED, FINISHEDのいずれか)
int ch, y, x;
setlocale(LC_ALL,""); // 非ASCII文字(日本語や絵文字)の表示に必要
initscr(); // ncursesを使用する際、最初におこなう初期化
start_color(); // カラー表示を開始する
setup_my_colors(); // このゲームの配色を設定
curs_set(0); // カーソルを非表示にする
noecho(); // キー入力を非表示にする
cbreak(); // Enterキー無しでキー入力を受け取る
keypad(stdscr, TRUE); // カーソルキーを有効にする
//(上・下・左・右: KEY_{UP|DOWN|LEFT|RIGHT})
timeout(GETCH_WAIT); // getch()で読み取るキー入力の待ち時間(単位:ms)
// キーのオートリピートを止める(ゲーム終了時に元に戻すこと)
system("/usr/bin/xset r off");
while (1)
{
ch = getch(); // キー入力を読み取る(Enter不要)
if ((ch == 'q') || (ch == 'Q')) { break; } // while(1)から抜ける
if ((ch == 'n') || (ch == 'N'))
{ }
if (state != FINISHED) // ゲームがまだクリアされていない状態ならば
{
if (ch == KEY_UP)
{
switch (HERO_UPPER)
{
case ROAD:
hero_y--;
count--;
break;
case EXIT:
hero_y--;
count--;
if (uncollected_keys == 0) { state = FINISHED; } // クリア
break;
case HAKO:
if (HERO_UPPER2 == ROAD)
{
HERO_UPPER2 = HAKO;
HERO_UPPER = ROAD;
hero_y--;
count--;
}
break;
case KAGI:
HERO_UPPER = ROAD;
hero_y--;
count--;
uncollected_keys--;
if (uncollected_keys == 0) { state = UNLOCKED; } // 出口開く
break;
} // switch (HERO_UPPER) ここまで
} // if (ch == KEY_UP) ここまで
else if (ch == KEY_DOWN)
{
switch (HERO_LOWER)
{
case ROAD:
hero_y++;
count--;
break;
case EXIT:
hero_y++;
count--;
if (uncollected_keys == 0) { state = FINISHED; } // クリア
break;
case HAKO:
if (HERO_LOWER2 == ROAD)
{
HERO_LOWER2 = HAKO;
HERO_LOWER = ROAD;
hero_y++;
count--;
}
break;
case KAGI:
HERO_LOWER = ROAD;
hero_y++;
count--;
uncollected_keys--;
if (uncollected_keys == 0) { state = UNLOCKED; } // 出口開く
break;
} // switch (HERO_LOWER) ここまで
} // else if (ch == KEY_DOWN) ここまで
else if (ch == KEY_LEFT)
{
switch (HERO_LEFT)
{
case ROAD:
hero_x--;
count--;
break;
case EXIT:
hero_x--;
count--;
if (uncollected_keys == 0) { state = FINISHED; } // クリア
break;
case HAKO:
if (HERO_LEFT2 == ROAD)
{
HERO_LEFT2 = HAKO;
HERO_LEFT = ROAD;
hero_x--;
count--;
}
break;
case KAGI:
HERO_LEFT = ROAD;
hero_x--;
count--;
uncollected_keys--;
if (uncollected_keys == 0) { state = UNLOCKED; } // 出口開く
break;
} // switch (HERO_LEFT) ここまで
} // else if (ch == KEY_LEFT) ここまで
else if (ch == KEY_RIGHT)
{
switch (HERO_RIGHT)
{
case ROAD:
hero_x++;
count--;
break;
case EXIT:
hero_x++;
count--;
if (uncollected_keys == 0) { state = FINISHED; } // クリア
break;
case HAKO:
if (HERO_RIGHT2 == ROAD)
{
HERO_RIGHT2 = HAKO;
HERO_RIGHT = ROAD;
hero_x++;
count--;
}
break;
case KAGI:
HERO_RIGHT = ROAD;
hero_x++;
count--;
uncollected_keys--;
if (uncollected_keys == 0) { state = UNLOCKED; } // 出口開く
break;
} // switch (HERO_RIGHT) ここまで
} // else if (ch == KEY_RIGHT) ここまで
} // if (state != FINISHED) ここまで
// 表示のための処理開始
clear(); // 画面を消去する
// 画面がちらつくようならerase();に変更してみる
for (y = 0; y < map_size_y; y++)
{
for (x = 0; x < map_size_x; x++)
{
switch (map[y][x])
{
case WALL:
put_wall(y, x);
break;
case ROAD:
put_road(y, x);
break;
case HAKO:
put_hako(y, x);
break;
case KAGI:
put_kagi(y, x);
break;
case EXIT:
put_exit(y, x);
break;
} // switch (map[y][x]) ここまで
} // for (x = 0;〜) ここまで
} // for (y = 0;〜) ここまで
put_hero(hero_y, hero_x);
if(count <= 0)
{
count = 0;
}
put_mesg_count(2, 1, count);
switch (state)
{
case LOCKED: // まだ未回収の鍵があって出口が閉じている状態
put_mesg_main(0, 1, "Pick up all key and go to the exit!");
break;
case UNLOCKED: // 鍵を全部回収して出口が開いた状態
put_mesg_main(0, 1, "Hurry to the exit!");
break;
case FINISHED: // 出口から脱出してゲームをクリアした状態
put_mesg_main(0, 1, "Finished!! Quit \"q\"");
break;
case GAMEOVER:
put_mesg_main(0, 1, "Gameover!! Quit \"q\"");
break;
} // switch (state) ここまで
if(count == 0)
{
state = GAMEOVER;
}
put_mesg_kagi(1, 1, uncollected_keys);
refresh(); // このrefresh()によって実際に画面が再表示される
// 表示のための処理終わり
} // while(1)の永久ループはここまで
// while(1)の永久ループから抜けた後のゲーム終了の処理
endwin(); // ncurserを使った時の後始末
system("/usr/bin/xset r rate 500 33"); // キーのオートリピートを初期値に戻す
return 0;
}
### 自分で試したこと
if ((ch == 'n') || (ch == 'N'))
{
int map_size_y = 16; // マップの縦幅
int map_size_x = 19; // マップの横幅
int hero_y = 8; // ヒーローのy座標の初期値
int hero_x = 6; // ヒーローのx座標の初期値
int uncollected_keys = 9; // 拾わなくてはならない鍵の個
int i;
for(i = 0; i < sizeof(map2) / sizeof(map2[0][0]); i++)
{
map[i][i] = map2[i][i];
}
}
のようにしましたが実行した際に「segmantation fault(コアダンプ)」と表示されてしまいました。