/* * 迷路系ゲームの超基本サンプル Ver.0 * とりあえず,自キャラを迷路内で移動させるだけ. */ #include #include #include #include "aa.h" #include "mobj.h" #include "term.h" // タイトル画面 int Title(void) { int w, h; erase(); getmaxyx(stdscr, h, w); attron(COLOR_PAIR(6)); mvaddstr(h/2-4, (w-28)/2, "迷路系ゲームのサンプル Ver.0"); attron(COLOR_PAIR(2)); mvaddstr(h/2-2, (w-18)/2, "カーソルキーで移動"); mvaddstr(h/2-1, (w-13)/2, "[Q]キーで終了"); attron(COLOR_PAIR(1)); mvaddstr(h/2+1, (w-13)/2, "Hit Any Key!!"); refresh(); timeout(-1); return (getch()); } // ゲームオーバ画面 void GameOver(void) { int w, h; // erase(); // 新規の画面に表示 or 現在の画面にオーバーレイ getmaxyx(stdscr, h, w); attron(COLOR_PAIR(1)); CenterStr(h, w, -2, "#===============#"); CenterStr(h, w, -1, "# GAME OVER #"); CenterStr(h, w, 0, "# #"); CenterStr(h, w, +1, "# Press [Space] #"); CenterStr(h, w, +2, "#===============#"); refresh(); while (WaitKey(-1) != ' '); // [Space]キーで終了 } // マップの基準表示位置 #define MAP_X 5 #define MAP_Y 5 // ASCIIアート生成処理の簡単化のためのマクロ #define AAVAR Aa *aa; int e = 0; int i = 0; // 変数を定義 #define AAERR if (e) { FreeAa(aa); return (NULL); } // エラー処理 #define AANEW(w, h) AAVAR; if ((aa = NewAa(w, h)) == NULL) return (NULL); // AAを生成 #define AAROW(s) if (SetAaRow(aa, i, s) != 0) e++; i++; // 行文字列を設定 #define AAEND AAERR; return (aa); // 終了 // マップを生成 Aa *NewMap(void) { AANEW(11,9); AAROW("###########"); AAROW("# E #"); // E は敵キャラ AAROW("# ### ### #"); AAROW("# # # #"); AAROW("## # # # ##"); AAROW("# # #"); AAROW("# # ### # #"); AAROW("# M #"); // M は 自キャラ AAROW("###########"); AAEND; } /* * マップデータについては,この例のようにソースファイル内に * ハードコーディング(埋め込み)するよりも, * 次のような内容のデータファイルから入力する方がいろいろと捗るだろう. * * 11 9 * ########### * # # * ... * * 関数 Aa *LoadAa(char *file) とかを aa.c に追加しては? */ // キャラクタの初期位置をマップから取得・設定 int FindChar(Aa *map, Mobj *o, char sym) { char *p; int x, y; p = QueryAaCell(map, sym); // マップからキャラを検索 if (p == NULL) return (1); // 失敗 *p = ' '; // キャラのいたセルをクリア y = (p - map->cell)/(map->sx); x = (p - map->cell)%(map->sx); InitMobj(o, x, y, 0, 0, 1); return (0); // 成功 } // マップ上でキャラクタを実際に移動 void MoveChar(Aa *map, Mobj *o) { // 移動予定先のセルが... if (GetAaCell(map, o->px + o->vx, o->py + o->vy) != '#') { MoveMobj(o); // 通路なら実際に移動 } else { SetMobjVel(o, 0, 0); // 壁なら停止 } } // マップ上でキャラクタの移動方向の変更を要求 void ReqTurnChar(Aa *map, Mobj *o, int vx, int vy) { // 移動予定先のセルが通路なら... if (GetAaCell(map, o->px + vx, o->py + vy) != '#') { SetMobjVel(o, vx, vy); // 移動方向を変更(まだ移動しない) } } // 自キャラを操作 void CtrlHero(Aa *map, Mobj *o, int key) { switch (key) { case 'l': case KEY_RIGHT: ReqTurnChar(map, o, +1, 0); break; case 'j': case KEY_DOWN: ReqTurnChar(map, o, 0, +1); break; case 'h': case KEY_LEFT: ReqTurnChar(map, o, -1, 0); break; case 'k': case KEY_UP: ReqTurnChar(map, o, 0, -1); break; // default: SetMobjVel(o, 0, 0); break; // 無入力なら停止 default: break; // 無入力なら慣性運動 } } // キャラクタ間の衝突判定 int ChkHit(Mobj *o1, Mobj *o2) { if (o1->px != o2->px) return (0); // 衝突なし if (o1->py != o2->py) return (0); // 衝突なし return (1); // 衝突あり } // 位置(x0, y0) を基準としてキャラクタを表示 void MvDrawChar(int x0, int y0, Mobj *o, char shape) { mvaddch(y0 + o->py, x0 + o->px, shape); } // マップを表示 void DrawMap(Aa *map) { attron(COLOR_PAIR(4)); MvDrawAa(MAP_X, MAP_Y, map); } // 自キャラを表示 void DrawHero(Mobj *o) { attron(COLOR_PAIR(3)); MvDrawChar(MAP_X, MAP_Y, o, 'M'); } // 敵キャラを表示 void DrawEnemy(Mobj *o) { attron(COLOR_PAIR(1)); MvDrawChar(MAP_X, MAP_Y, o, 'E'); } // ゲームの本体 int Game(void) { Aa *map; // マップ Mobj *hero; // 自キャラ Mobj *enemy; // 敵キャラ int key; // 入力キー // 初期設定 if ((map = NewMap()) == NULL) return (1); if ((hero = NewMobj()) == NULL) return (1); if ((enemy = NewMobj()) == NULL) return (1); if (FindChar(map, hero, 'M')) return (1); if (FindChar(map, enemy, 'E')) return (1); while (1) { // 画面表示 erase(); DrawMap(map); DrawHero(hero); DrawEnemy(enemy); move(0, 0); #ifdef DEBUG attron(COLOR_PAIR(7)); printw("hero: %d %d\n", hero->px, hero->py); printw("enemy: %d %d\n", enemy->px, enemy->py); #endif refresh(); // 終了判定 if (hero->stts == 0) { GameOver(); break; } // キー入力/自キャラの移動 // usleep(100000); timeout(0); key = getch(); // これだと動作が不安定 key = WaitKey(100); // 100ms待機&キー入力 // getch() の改良版(key.c に解説あり) if (key == 'q') break; CtrlHero(map, hero, key); MoveChar(map, hero); // 敵キャラの移動 ... to-do // CtrlEnemy(map, enemy, hero); // 移動方向を決める(自キャラを追う等) // MoveChar(map, enemy); // キャラクタ間の相互作用 if (ChkHit(hero, enemy)) hero->stts = 0; // とりあえず,捕まったら終了へ } FreeMobj(hero); FreeAa(map); return (0); } int main(void) { // 端末の設定 setlocale(LC_ALL, ""); initscr(); curs_set(0); noecho(); cbreak(); keypad(stdscr, TRUE); // カラーの設定 start_color(); init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_YELLOW, COLOR_BLACK); init_pair(4, COLOR_BLUE, COLOR_BLACK); init_pair(5, COLOR_MAGENTA, COLOR_BLACK); init_pair(6, COLOR_CYAN, COLOR_BLACK); init_pair(7, COLOR_WHITE, COLOR_BLACK); bkgd(COLOR_PAIR(7)); attron(A_BOLD); // 太字を使う // メイン while (1) { if (Title() == 'q') break; // タイトル画面 if (Game() != 0) break; // ゲーム画面 } endwin(); return (0); }