/* * 大砲ゲーム 2007 Ver.1 * by yanagawa@kushiro-ct.ac.jp * * 開発履歴 * Ver.1 敵を撃ち落とせるようにした */ #include #include #include #include #include "gameutil.h" #define SCR_MIN_W 40 #define SCR_MIN_H 24 Screen scr; // 画面情報 #define GRAVITY 0.01; // 重力加速度 /* 移動物体構造体 */ typedef struct { double px, py; // 位置 (position) double vx, vy; // 速度 (velocity) double sx, sy; // サイズ(中心からの距離) int life; // 生死判定用フラグ (0:dead / 1:alive) } Object; /* 物体の初期化 */ void InitObject(Object *obj, double px, double py, double vx, double vy, double sx, double sy, int life) { obj->px = px; obj->py = py; obj->vx = vx; obj->vy = vy; obj->sx = sx; obj->sy = sy; obj->life = life; } void InitEnemy(Object *enemy, double px, double py, double vx, double vy, int life) { InitObject(enemy, px, py, vx, vy, 3.0, 1.0, life); } void InitBullet(Object *bullet, double px, double py, double vx, double vy, int life) { InitObject(bullet, px, py, vx, vy, 0.5, 0.5, life); } /* 物体の運動 */ void MoveObject(Object *obj) { obj->px += obj->vx; obj->py += obj->vy; } /* 弾丸の運動 */ void MoveBullet(Object *obj) { obj->vy += GRAVITY; MoveObject(obj); if (((int)(obj->px) < 0) || ((int)(obj->px) >= scr.w)) obj->life = 0; if ((int)(obj->py) >= scr.h) obj->life = 0; } /* 敵の運動 */ void MoveEnemy(Object *obj) { MoveObject(obj); if (((int)(obj->px) < 0) || ((int)(obj->px) >= scr.w)) obj->life = 0; if (((int)(obj->py) < 0) || ((int)(obj->py) >= scr.h)) obj->life = 0; } /* 弾丸の表示 */ void DrawBullet(Object *bullet) { attrset(COLOR_PAIR(3)|A_BOLD); mvaddch((int)(bullet->py), (int)(bullet->px), '*'); } /* 大砲の表示 */ void DrawCannon(int angle) { attrset(COLOR_PAIR(7)); mvprintw(0, 0, "angle : %d deg", angle); } /* アスキーアート文字列の表示 */ void DrawText(int y, int x, char *s) { if (y < 0) return; if (y >= scr.h) return; while (*s != '\0') { if ((0 <= x) && (x < scr.w) && (*s != ' ')) mvaddch(y, x, *s); s++; x++; } } /* 敵の表示 */ void DrawEnemy(Object *enemy) { int x, y; attrset(COLOR_PAIR(2)); x = (int)(enemy->px) - 3; y = (int)(enemy->py); DrawText(y-1, x, " *|| "); DrawText(y , x, "<=====P"); DrawText(y+1, x, " *\\\\ "); } /* 衝突の判定 */ int ChkHit(Object *obj1, Object *obj2) { if (fabs(obj1->px - obj2->px) > (obj1->sx + obj2->sx)) return (0); if (fabs(obj1->py - obj2->py) > (obj1->sy + obj2->sy)) return (0); return (1); } /* ゲームの本体 */ void Game() { Object bullet; Object enemy; int key, fire, angle; InitRand(); InitBullet(&bullet, 0.0, 0.0, 0.0, 0.0, 0); InitEnemy(&enemy, 0.0, 0.0, 0.0, 0.0, 0); angle = 45; timeout(0); while (1) { /* 表示 */ erase(); if (ChkScreen(&scr)) Warning(1, 1, "Screen Too Small."); if (bullet.life != 0) DrawBullet(&bullet); if (enemy.life != 0) DrawEnemy(&enemy); DrawCannon(angle); refresh(); /* 入力 */ fire = 0; ; key = getch(); switch (key) { case KEY_UP : angle += 5; break; // 角度 up case KEY_DOWN : angle -= 5; break; // 角度 down case ' ' : fire = 1; break; // 発射 case 'q' : return; // ゲーム中止 default : break; } /* 移動 */ if ((fire == 1) && (bullet.life == 0)) { InitBullet(&bullet, 0.0, (double)(scr.h-1), cos(angle*M_PI/180.0), -sin(angle*M_PI/180.0), 1); } if ((bullet.life != 0) && (enemy.life != 0)) { if (ChkHit(&bullet, &enemy) != 0) { bullet.life = 0; enemy.life = 0; beep(); } } if (bullet.life != 0) { MoveBullet(&bullet); } /* 相互作用 */ if (enemy.life != 0) { MoveEnemy(&enemy); } else { InitEnemy(&enemy, (double)(scr.w-1), (double)Rand(scr.h/2), -(Rand(4)+3)*0.1 , 0.0, 1); } usleep(20000); } } /* タイトル画面 */ int Title() { int key; erase(); ChkScreen(&scr); attrset(COLOR_PAIR(1)); mvaddstr(scr.h/2-2, (scr.w-10)/2, "大砲ゲーム"); attrset(COLOR_PAIR(2)); mvaddstr(scr.h/2, (scr.w-21)/2, "Push [Space] to start"); mvaddstr(scr.h/2+1, (scr.w-16)/2, "Push [Q] to quit"); attrset(COLOR_PAIR(3)); mvaddstr(scr.h/2+3, (scr.w-17)/2, "[Space] [↑] [↓]"); mvaddstr(scr.h/2+4, (scr.w-17)/2, " fire up down"); move(0, 0); timeout(-1); key = getch(); return (key); } int main() { InitScreen(&scr, SCR_MIN_W, SCR_MIN_H); InitColor(COLOR_BLACK); while (1) { if (Title() == 'q') break; Game(); } EndScreen(); return (0); }