/* * 大砲ゲーム Ver.7 * by yanagawa@kushiro-ct.ac.jp * 開発履歴 * Ver.7 ミサイル弾を追加した. * Ver.6 ソースコードの分割・整理.効果音追加.動作速度一定化. * Ver.5 敵機の種類を複数化した.ソースコードの微修正. * Ver.4 爆発表現とタイトル画面を追加した. * Ver.3 デモンストレーションモードの実験. * Ver.2 敵機と砲弾を複数にした. * Ver.1 敵機を撃ち落とせるようにした. */ //#include #include #include #include #include #include "object.h" #include "gameutil.h" #define INTERVAL 20 // 単位時間(ミリ秒) #define GRAVITY 0.01 // 重力加速度 #define N_TYPE 4 // 敵機の種類,don't change #define N_ENEMY 10 // 敵機の最大数 #define N_BULLET 20 // 砲弾の最大数 #define READYINT 10 // 発射の時間間隔(ループ回数) #define BOOMDUR 15 // 爆発の持続時間(ループ回数) #define START_SND "/usr/share/sounds/gaim/redalert.wav" // 開始音 #define SHOT_SND "/usr/share/sounds/k3b_wait_media1.wav" // 発射音 #define BOOM_SND "/usr/share/sounds/gnobots2/splat.wav" // 爆発音 // 物体形状構造体 typedef struct { double sx, sy; // サイズ void (*draw)(double x, double y); // 描画関数ポインタ } Shape; // 敵機構造体 typedef struct { Object obj; Shape shape; } Enemy; /* 敵機の初期化 */ void InitEnemy(Enemy *enemy, double px, double py, double vx, double vy, int life, Shape shape) { InitObject(&(enemy->obj), px, py, vx, vy, shape.sx, shape.sy, life); enemy->shape = shape; } void InitEnemies(Enemy enemy[], int n, double px, double py, double vx, double vy, int life, Shape shape[]) { int i; for (i = 0; i < n; i++) { InitEnemy(&enemy[i], px, py, vx, vy, life, shape[Rand(N_TYPE)]); } } /* 砲弾の初期化 */ void InitBullet(Object *bullet, double px, double py, double vx, double vy, int life) { InitObject(bullet, px, py, vx, vy, 0.0, 0.0, life); } void InitBullets(Object bullet[], int n, double px, double py, double vx, double vy, int life) { int i; for (i = 0; i < n; i++) { InitBullet(&bullet[i], px, py, vx, vy, life); } } /* ミサイルの運動 */ void MoveMissile(Object *obj) { int w, h; getmaxyx(stdscr, h, w); MoveObject(obj); if ((int)(obj->px) < 0) obj->life = 0; else if ((int)(obj->px) >= w) obj->life = 0; else if ((int)(obj->py) < 0) obj->life = 0; else if ((int)(obj->py) >= h) obj->life = 0; } /* 砲弾の運動 */ void MoveBullet(Object *obj) { int w, h; getmaxyx(stdscr, h, w); obj->vy += GRAVITY; MoveObject(obj); if ((int)(obj->px) < 0) obj->life = 0; else if ((int)(obj->px) >= w) obj->life = 0; else if ((int)(obj->py) >= h) obj->life = 0; } void MoveBullets(Object bullet[], int n) { int i; for (i = 0; i < N_BULLET; i++) { switch (bullet[i].life) { case 1 : MoveBullet(&bullet[i]); break; case 2 : MoveMissile(&bullet[i]); break; default : break; } } } /* 敵の運動 */ void MoveEnemy(Enemy *enemy) { int w, h; getmaxyx(stdscr, h, w); MoveObject(&(enemy->obj)); if (enemy->obj.life < 0) enemy->obj.life++; // 爆発中 if ((int)(enemy->obj.px) < -10) enemy->obj.life = 0; if ((int)(enemy->obj.py) < 0) enemy->obj.life = 0; if ((int)(enemy->obj.py) >= h) enemy->obj.life = 0; } // ミサイルの表示 void DrawMissile(Object *obj) { UseColor(6); DrawBlocks((int)(obj->py), (int)(obj->px), "#"); UseColor(7); DrawBlocks((int)(obj->py-obj->vy), (int)(obj->px-obj->vx), "."); DrawBlocks((int)(obj->py-2*obj->vy), (int)(obj->px-2*obj->vx), "&"); } /* 砲弾の表示 */ void DrawBullet(Object *bullet) { UseColor(3); mvaddch((int)(bullet->py), (int)(bullet->px), '*'); } void DrawBullets(Object bullet[], int n) { int i; for (i = 0; i < n; i++) { switch (bullet[i].life) { case 1 : DrawBullet(&bullet[i]); break; case 2 : DrawMissile(&bullet[i]); break; default : break; } } } /* 角度の表示 */ void DrawAngle(int y, int x, int angle) { UseColor(7); mvprintw(y, x, "angle : %d deg", angle); } /* 敵機の描画関数 */ void DrawEnemy0(double px, double py) { int x, y; UseColor(2); x = (int)px - 3; y = (int)py; DrawBlocks(y-1, x, " *|| "); DrawBlocks(y , x, "<=====P"); DrawBlocks(y+1, x, " *\\\\ "); }; void DrawEnemy1(double px, double py) { int x, y; UseColor(4); x = (int)px - 4; y = (int)py; DrawBlocks(y-1, x, " -//| /"); DrawBlocks(y , x, "-=======/"); DrawBlocks(y+1, x, " -\\\\| "); }; void DrawEnemy2(double px, double py) { int x, y; UseColor(6); x = (int)px - 6; y = (int)py; DrawBlocks(y-2, x, " /#| "); DrawBlocks(y-1, x, " *|#| /|"); DrawBlocks(y , x, "<###########="); DrawBlocks(y+1, x, " *\\#\\ "); DrawBlocks(y+2, x, " \\#\\ "); }; void DrawEnemy3(double px, double py) { int x, y; UseColor(2); x = (int)px - 2; y = (int)py; DrawBlocks(y-1, x, "--## "); DrawBlocks(y , x, "@@@@@"); }; void DrawBoom(double px, double py, int size) { int x, y; UseColor(1); size = size*10/BOOMDUR; if (size < 4) { x = (int)px - 1; y = (int)py; DrawBlocks(y , x, "( )"); } else if (size < 7) { x = (int)px - 3; y = (int)py; DrawBlocks(y-1, x, " &&& "); DrawBlocks(y , x, " & & "); DrawBlocks(y+1, x, " &&& "); } else { x = (int)px - 5; y = (int)py; DrawBlocks(y-2, x, " &&&&& "); DrawBlocks(y-1, x, " &&& &&& "); DrawBlocks(y , x, "&& &&"); DrawBlocks(y+1, x, " &&& &&& "); DrawBlocks(y+2, x, " &&&&& "); } } /* 敵機の表示 */ void DrawEnemy(Enemy *enemy) { if (enemy->obj.life == 1) { // 機体 enemy->shape.draw(enemy->obj.px, enemy->obj.py); } else { // 爆発 DrawBoom(enemy->obj.px, enemy->obj.py, -enemy->obj.life); } } void DrawEnemies(Enemy enemy[], int n) { int i; for (i = 0; i < n; i++) { if (enemy[i].obj.life != 0) DrawEnemy(&enemy[i]); } } /* ゲームの本体 */ void Game(int mode) { Object bullet[N_BULLET]; Enemy enemy[N_ENEMY]; int t; int h, w; int key, fire, ready, angle; int i, j; char autokey[10] = "z- - - k j"; Shape shape[] = { {3.0, 1.0, DrawEnemy0}, {4.0, 1.0, DrawEnemy1}, {5.0, 1.0, DrawEnemy2}, {2.0, 1.0, DrawEnemy3} }; PlaySnd(START_SND); InitRand(); InitBullets(bullet, N_BULLET, 0.0, 0.0, 0.0, 0.0, 0); InitEnemies(enemy, N_ENEMY, 0.0, 0.0, 0.0, 0.0, 0, shape); angle = 45; ready = 0; timeout(0); while (1) { InitWait(); erase(); getmaxyx(stdscr, h, w); DrawBullets(bullet, N_BULLET); DrawEnemies(enemy, N_ENEMY); DrawAngle(0, 0, angle); refresh(); fire = 0; key = getch(); if ((key == EOF) && (mode == 'd')) key = autokey[Rand(10)]; switch (key) { case 'h' : case 'k' : case KEY_LEFT : case KEY_UP : angle += 5; break; // 角度 up case 'l' : case 'j' : case KEY_RIGHT : case KEY_DOWN : angle -= 5; break; // 角度 down case ' ' : fire = 1; break; // 砲弾発射 case 'z' : fire = 2; break; // ミサイル発射 case 'q' : return; // ゲーム中止 } if (angle < 0) angle = 0; if (angle > 90) angle = 90; /* 砲弾発射 */ if (ready <= 0) { if (fire != 0) { for (i = 0; i < N_BULLET; i++) { if (bullet[i].life) continue; PlaySnd(SHOT_SND); InitBullet(&bullet[i], 0.0, (double)(h-1), cos(angle*M_PI/180.0)*(1+fire)/2, -sin(angle*M_PI/180.0)*(1+fire)/2, fire); ready = READYINT; break; } } } else { ready--; } /* 撃墜 */ for (i = 0; i < N_BULLET; i++) { if (bullet[i].life == 0) continue; for (j = 0; j < N_ENEMY; j++) { if (enemy[j].obj.life > 0) { if (ChkHit(&bullet[i], &enemy[j].obj) != 0) { PlaySnd(BOOM_SND); enemy[j].obj.life = -BOOMDUR; // 爆発 bullet[i].life = 0; break; } } } } /* 砲弾移動 */ MoveBullets(bullet, N_BULLET); /* 敵機移動 */ for (j = 0; j < N_ENEMY; j++) { if (enemy[j].obj.life != 0) { MoveEnemy(&enemy[j]); } else { t = Rand(N_TYPE); if (t >= 3) { // 陸上 InitEnemy(&enemy[j], (double)(w+Rand(10)+5), (double)(h-1), -(Rand(7)+3)*0.01 , 0.0, 1, shape[t]); } else { // 航空 InitEnemy(&enemy[j], (double)(w+Rand(10)+5), (double)Rand(h/2), -(Rand(7)+3)*0.1 , 0.0, 1, shape[t]); } } } Wait(INTERVAL); // 動作速度一定版 sleep() } } /* タイトル画面 */ int Title() { int h, w, key; getmaxyx(stdscr, h, w); erase(); attrset(0); UseColor(11); DrawBlocks(h/2-9, (w-42)/2, "### # # # # # ### # # ## # # # "); DrawBlocks(h/2-8, (w-42)/2, "# ### # # # # # # # # # # ### # # "); DrawBlocks(h/2-7, (w-42)/2, "# # # ## # ## # # # ## # ## # # # # "); DrawBlocks(h/2-6, (w-42)/2, "# ### # ## # ## # # # ## # # ### # # "); DrawBlocks(h/2-5, (w-42)/2, "### # # # # # # ### # # ## # # ### ###"); attrset(A_BOLD); UseColor(1); CenterStr(h/2-4, w/2, "大砲ゲーム"); UseColor(2); CenterStr(h/2-2, w/2, "Push [Space] to start game"); CenterStr(h/2-1, w/2, "Push [S] to start in silent mode"); CenterStr(h/2, w/2, "Push [D] to start demo"); CenterStr(h/2+1, w/2, "Push [Q] to quit"); UseColor(3); CenterStr(h/2+3, w/2, "[Space] [z] [↑] [↓]"); CenterStr(h/2+4, w/2, "bullet missile up down"); move(0, 0); timeout(-1); key = getch(); return (key); } int main() { int key; setlocale(LC_ALL, ""); initscr(); noecho(); cbreak(); curs_set(0); keypad(stdscr, TRUE); InitColor(COLOR_BLACK); attrset(A_BOLD); // 高輝度表示 while (1) { key = Title(); if (key == 'q') break; if ((key == 's') || (key == 'd')) { SetSnd(0); } else { SetSnd(1); } Game(key); } endwin(); return (0); }