課設題目
實現功能:
飛機鼠標控制–飛機武器升級–敵機發射子彈–boss發射散彈–boss血條記錄–我方多條生命
圖片資源和源碼在下面
鏈接:https://pan.baidu.com/s/1uTQVHAaWfWHXFg3p5zQ4KA
提取碼:y606
源碼:
#include <graphics.h>
#include <conio.h>
#include <math.h>
#include <stdio.h>
#pragma comment(lib,"Winmm.lib") // 引用 Windows Multimedia API
#define High 800 // 遊戲畫面尺寸
#define Width 800
IMAGE img_bk; // 背景圖片
IMAGE img_planeNormal1, img_planeNormal2; // 正常飛機圖片
IMAGE img_planeExplode1, img_planeExplode2; // 爆炸飛機圖片
IMAGE img_enemyPlane1, img_enemyPlane2; // 敵機圖片
IMAGE boss1_a, boss1_b; // boss圖片
IMAGE bullet_lis[10][2]; // 我方飛機子彈圖片
float e_speed[3] = { 0.4,0.5,0.6 }; //敵機隨機飛行速度列表
int enemy_cnt = 5; //同一畫面最大敵機數量
int enemy_life = 3; //敵機的生命值
int e_bullet_cnt = 20; //同一畫面最多敵機子彈數量
int bullet_type = 2; //我方飛機子彈種類
int bullet_rank = 0; //我方飛機now子彈等級 and 對應打boss的傷害爲 bullet_rank+1
int bullet_cnt = 20; //我方飛機最大子彈數量
int isExpolde = 0; //飛機是否爆炸
int score = 0; //得分
int b_bullet_cnt = 5; //boss子彈同一畫面最大數量
int time_cnt = 0; //用於控制boss子彈發射間隔
struct Plane { //我方飛機屬性
float x, y;
int life;
float w, h;
}plane;
struct Bullet { //我方飛機子彈屬性
float x, y;
int life;
float w, h;
}bullet[200];
struct Enemy { //敵機屬性
float x, y;
int speed; //準確來說敵機速度是e_speed[enemy.speed]
int life;
float w, h;
}enemy[20];
struct Enemy_bullet { //敵機子彈屬性
float x, y;
float speed;
int life;
float w, h;
}e_bullet[100];
struct Boss { //boss屬性
float x, y;
float w, h;
float add_x, add_y; //x,y軸移動速度
int life; //生命值大小
int is_active; //boss是否出現
int is_protect;
}boss;
struct Boss_bullet { //boss子彈屬性
float x, y;
float w, h;
float add_x, add_y;
int life;
}b_bullet[20][3];
void startup(); // 數據初始化(加載圖片資源,初始化飛機屬性)
void show(); // 畫面刷新
void updateWithoutInput(); // 與用戶輸入無關的更新
void updateWithInput(); // 與用戶輸入有關的更新
void gameover(); //遊戲結束
void reset_plane(); //設置我方飛機的初始屬性
void reset_bullet(); //設置我方子彈 和 敵軍子彈的大小
void reset_enemy(int i); //設置敵機屬性
void reset_e_bullet(Enemy a); //設置敵機子彈屬性
void reset_boss(); //設置boss屬性
void reset_b_bullet(Boss_bullet a[3]); //設置boss屬性
int is_crash(Enemy a, Bullet b); //子彈--敵機碰撞檢測
int is_crash_boss(Boss a, Bullet b); //子彈--boss碰撞檢測
int is_crash_plane(Plane a, Enemy_bullet b); //我方--敵機子彈碰撞檢測
int is_crash_boss_plane(Plane a, Boss_bullet b); //我方--boss子彈碰撞檢測
int main()
{
startup(); // 數據初始化
while (1) // 遊戲循環執行
{
show(); // 顯示畫面
updateWithoutInput(); // 與用戶輸入無關的更新
updateWithInput(); // 與用戶輸入有關的更新
if (isExpolde == 1) break;
}
gameover(); // 遊戲結束、後續處理
return 0;
}
void startup() // 數據初始化(加載圖片資源,初始化飛機屬性)
{
mciSendString("open image/game_music.mp3 alias bkmusic", NULL, 0, NULL);//打開背景音樂
mciSendString("play bkmusic repeat", NULL, 0, NULL); // 循環播放
initgraph(Width, High);
loadimage(&img_bk, "image/back2.jpg", 800, 800);
loadimage(&img_planeNormal1, "image/plane1.jpg");
loadimage(&img_planeNormal2, "image/plane2.jpg");
loadimage(&img_enemyPlane1, "image/enemyPlane1.jpg");
loadimage(&img_enemyPlane2, "image/enemyPlane2.jpg");
loadimage(&img_planeExplode1, "image/planeExplode_1.jpg");
loadimage(&img_planeExplode2, "image/planeExplode_2.jpg");
loadimage(&bullet_lis[0][0], "image/bullet1_a.jpg");
loadimage(&bullet_lis[0][1], "image/bullet1_b.jpg");
loadimage(&bullet_lis[1][0], "image/bullet2_a.jpg");
loadimage(&bullet_lis[1][1], "image/bullet2_b.jpg");
loadimage(&bullet_lis[2][0], "image/bullet3_a.jpg");
loadimage(&bullet_lis[2][1], "image/bullet3_b.jpg");
loadimage(&boss1_a, "image/boss_a.jpg");
loadimage(&boss1_b, "image/boss_b.jpg");
reset_plane(); //我方飛機的初始化
reset_boss(); //boss的初始化
reset_bullet(); //子彈(我方+敵人)的初始化
for (int i = 0; i < enemy_cnt; i++) //敵機的初始化
{
enemy[i].h = 135;
enemy[i].w = 92;
reset_enemy(i);
}
BeginBatchDraw();
}
void show() //
{
putimage(0, 0, &img_bk); // 顯示背景
if (isExpolde == 0)
{
int tx = 91;
int ty = 106;
putimage(plane.x - tx / 2, plane.y - ty / 2, &img_planeNormal1, NOTSRCERASE); // 顯示正常飛機
putimage(plane.x - tx / 2, plane.y - ty / 2, &img_planeNormal2, SRCINVERT);
if (boss.is_active == 1) //如果出現boss
{
putimage(boss.x, boss.y, &boss1_a, NOTSRCERASE); //繪製boss
putimage(boss.x, boss.y, &boss1_b, SRCINVERT);
for (int k = 0; k < b_bullet_cnt; k++) //繪製boss子彈
{
for (int i = 0; i < 3; i++)
{
if (b_bullet[k][i].life == 0) continue;
putimage(b_bullet[k][i].x, b_bullet[k][i].y, &bullet_lis[0][0], NOTSRCERASE);
putimage(b_bullet[k][i].x, b_bullet[k][i].y, &bullet_lis[0][1], SRCINVERT);
}
}
//繪製boss血條
setlinecolor(BLACK); //設置當前畫線顏色
rectangle(100, 5, Width - 100, 20);
setfillcolor(RED); //設置當前填充顏色。
if (boss.life < 0) boss.life = 0;
solidrectangle(100, 5,100+ boss.life*(Width - 200)*0.01, 20);
}
for (int i = 0; i < bullet_cnt; i++) //繪製我方飛機子彈
{
if (bullet[i].life == 0) continue;
putimage(bullet[i].x - bullet[i].w / 2, bullet[i].y, &bullet_lis[bullet_rank][0], NOTSRCERASE);
putimage(bullet[i].x - bullet[i].w / 2, bullet[i].y, &bullet_lis[bullet_rank][1], SRCINVERT);
}
for (int i = 0; i < enemy_cnt; i++) //繪製敵機
{
putimage(enemy[i].x, enemy[i].y, &img_enemyPlane1, NOTSRCERASE);
putimage(enemy[i].x, enemy[i].y, &img_enemyPlane2, SRCINVERT);
}
for (int i = 0; i < e_bullet_cnt; i++) //繪製敵機子彈
{
if (e_bullet[i].life == 0) continue;
putimage(e_bullet[i].x, e_bullet[i].y, &bullet_lis[0][0], NOTSRCERASE); // 顯示敵機子彈
putimage(e_bullet[i].x, e_bullet[i].y, &bullet_lis[0][1], SRCINVERT);
}
}
else
{
putimage(plane.x - 50, plane.y - 60, &img_planeExplode1, NOTSRCERASE); // 顯示爆炸飛機
putimage(plane.x - 50, plane.y - 60, &img_planeExplode2, SRCINVERT);
}
outtextxy(Width*0.30, High*0.95, "得分:");
char s[5];
sprintf(s, "%d", score);
outtextxy(Width*0.40, High*0.95, s);
outtextxy(Width*0.55, High*0.95, "生命:");
sprintf(s, "%d", plane.life);
outtextxy(Width*0.65, High*0.95, s);
FlushBatchDraw();
Sleep(2);
}
void updateWithoutInput()
{
if (isExpolde == 0)
{
time_cnt++; //算是boss子彈的計時器吧
if (boss.is_active == 1) //如果出現boss
{
if (boss.y < 25) //boss的前搖(裝逼進場)
{
boss.y += boss.add_y;
}
else
{
boss.x += boss.add_x; //boss的左右搖擺
if (boss.x + boss.w > Width || boss.x < 0)
{
boss.add_x = 0 - boss.add_x;
}
}
for (int k = 0; k < b_bullet_cnt; k++) //boss子彈的移動
{
for (int i = 0; i < 3; i++)
{
if (b_bullet[k][i].life == 0) continue;
if (b_bullet[k][i].y < Width - 10)
{
b_bullet[k][i].x += b_bullet[k][i].add_x;
b_bullet[k][i].y += b_bullet[k][i].add_y;
}
else
{
b_bullet[k][i].life = 0; //如果boss子彈超出邊界 消失它
}
}
}
if (time_cnt % 400 == 0) //boss不定時發射子彈
{
for (int k = 0; k < b_bullet_cnt; k++)
{ //找到消失狀態的子彈 發射它
if (b_bullet[k][0].life == 0 && b_bullet[k][1].life == 0 && b_bullet[k][2].life == 0)
{
reset_b_bullet(b_bullet[k]);
break;
}
}
}
for (int k = 0; k < b_bullet_cnt; k++) //boss子彈和我方飛機的碰撞檢測
{
for (int i = 0; i < 3; i++)
{
if (b_bullet[k][i].life == 0) continue;
if (is_crash_boss_plane(plane, b_bullet[k][i]) == 1)
{
plane.life -= 1;
b_bullet[k][i].life = 0; //如果boss某個子彈碰撞了 那這個子彈要消失
}
}
}
}
for (int i = 0; i < bullet_cnt; i++) //我方子彈的移動
{
if (bullet[i].life == 0) continue;
if (bullet[i].y > 0)
{
bullet[i].y -= 2;
}
else //如果子彈超出邊界 讓他消失
{
bullet[i].life = 0;
}
}
for (int i = 0; i < enemy_cnt; i++) //敵機的移動
{
if (enemy[i].y < High - 25)
{
enemy[i].y = enemy[i].y + e_speed[enemy[i].speed];
}
else
{
reset_enemy(i);
}
}
for (int i = 0; i < e_bullet_cnt; i++) //敵方子彈的移動
{
if (e_bullet[i].life == 0) continue;
if (e_bullet[i].y < High - 10)
{
e_bullet[i].y += e_bullet[i].speed;
}
else
{
e_bullet[i].life = 0; //如果子彈超出邊界 讓他消失
}
}
for (int i = 0; i < e_bullet_cnt; i++) //敵方子彈和我方飛機的碰撞檢測
{
if (e_bullet[i].life == 0) continue;
if (is_crash_plane(plane, e_bullet[i]) == 1)
{
plane.life -= 1;
e_bullet[i].life = 0;
}
}
for (int i = 0; i < bullet_cnt; i++) //我方子彈和boss碰撞檢測
{
if (bullet[i].life == 0) continue;
if (boss.is_active == 0 || boss.life < 0) break;
if (is_crash_boss(boss, bullet[i]) == 1)
{
boss.life -= (bullet_rank + 1);
bullet[i].life = 0;
}
}
for (int i = 0; i < enemy_cnt; i++) //我方子彈和敵機的檢測
{
for (int j = 0; j < bullet_cnt; j++)
{
if (bullet[j].life == 0) continue;
if (is_crash(enemy[i], bullet[j]) == 1) // 子彈擊中敵機
{
bullet[j].life = 0; //子彈消失
if (enemy[i].life <= 1) //判斷敵機的生命值夠不夠
{
reset_enemy(i); //重置敵機
mciSendString("close gemusic", NULL, 0, NULL); // 先把前面一次的音樂關閉
mciSendString("open image/gotEnemy.mp3 alias gemusic", NULL, 0, NULL); // 打開音樂
mciSendString("play gemusic", NULL, 0, NULL); // 僅播放一次
score++;
if (score == 2) //如果分數等於2 武器進化
{
bullet_rank += 1;
reset_bullet(); //更新進化武器的圖片
}
else if (score == 4) //如果分數等於4 武器進化
{
bullet_rank += 1;
reset_bullet(); //更新進化武器的圖片
}
if (score > 0 && score % 5 == 0 && score % 2 != 0)
{
mciSendString("close 5music", NULL, 0, NULL); // 先把前面一次的音樂關閉
mciSendString("open image/5.mp3 alias 5music", NULL, 0, NULL); // 打開音樂
mciSendString("play 5music", NULL, 0, NULL); // 僅播放一次
}
if (score % 10 == 0)
{
mciSendString("close 10music", NULL, 0, NULL); // 先把前面一次的音樂關閉
mciSendString("open image/10.mp3 alias 10music", NULL, 0, NULL); // 打開音樂
mciSendString("play 10music", NULL, 0, NULL); // 僅播放一次
}
if (score >= 6) //達到一定分數 出現boss
{
boss.is_active = 1;
enemy_cnt = 0; //boss出現 同時減少其他小敵機
for (int p = 0; p < e_bullet_cnt; p++) //之前敵機發射的子彈消失
{
e_bullet[p].life = 0;
}
}
}
else
{
enemy[i].life -= 1;
}
}
}
}
}
}
void updateWithInput()
{
if (isExpolde == 0)
{
MOUSEMSG m; // 定義鼠標消息
while (MouseHit()) //這個函數用於檢測當前是否有鼠標消息
{
m = GetMouseMsg();
if (m.uMsg == WM_MOUSEMOVE)
{
// 飛機的位置等於鼠標所在的位置
plane.x = m.x;
plane.y = m.y;
}
else if (m.uMsg == WM_LBUTTONDOWN)
{
// 按下鼠標左鍵,發射子彈
for (int i = 0; i < bullet_cnt; i++)
{
if (bullet[i].life == 0)
{
bullet[i].x = plane.x;
bullet[i].y = plane.y - 53;
bullet[i].life = 1;
break;
}
}
mciSendString("close fgmusic", NULL, 0, NULL); // 先把前面一次的音樂關閉
mciSendString("open image/f_gun.mp3 alias fgmusic", NULL, 0, NULL); // 打開音樂
mciSendString("play fgmusic", NULL, 0, NULL); // 僅播放一次
}
}
}
}
void gameover()
{
EndBatchDraw();
_getch();
closegraph();
}
void reset_plane() //設置我方飛機的初始屬性
{
plane.x = Width * 0.5;
plane.y = High * 0.7;
plane.w = 91;
plane.h = 106;
plane.life = 10; //我方飛機的初始生命值
}
void reset_bullet() //重置我方子彈 和 敵軍子彈的大小
{
for (int i = 0; i < bullet_cnt; i++)
{
if (bullet_rank == 0)
{
bullet[i].w = 8;
bullet[i].h = 20;
}
else if (bullet_rank == 1)
{
bullet[i].w = 40;
bullet[i].h = 36;
}
else if (bullet_rank == 2)
{
bullet[i].w = 65;
bullet[i].h = 40;
}
}
for (int i = 0; i < e_bullet_cnt; i++)
{
e_bullet[i].w = 8;
e_bullet[i].h = 20;
}
}
void reset_enemy(int i) //設置敵機屬性
{
enemy[i].x = rand() % Width;
enemy[i].y = -200;
enemy[i].speed = rand() % 3;
enemy[i].life = enemy_life;
reset_e_bullet(enemy[i]); //開始時生成一個敵人 就附加子彈
}
void reset_e_bullet(Enemy a) //設置敵機子彈屬性
{
for (int i = 0; i < e_bullet_cnt; i++)
{
if (e_bullet[i].life == 0)
{
e_bullet[i].x = a.x + a.w / 2;
e_bullet[i].y = a.y + a.h;
e_bullet[i].speed = e_speed[a.speed] + 0.3;
e_bullet[i].life = 1;
break;
}
}
}
void reset_boss() //設置boss屬性
{
boss.w = 200;
boss.h = 213;
boss.x = Width / 2 - boss.w / 2;
boss.y = 0 - boss.h;
boss.life = 100;
boss.add_x = 0.7;
boss.add_y = 0.3;
}
void reset_b_bullet(Boss_bullet a[3]) //設置boss屬性
{
for (int i = 0; i < 3; i++)
{
a[i].x = boss.x + boss.w / 2;
a[i].y = boss.y + boss.h;
a[i].add_y = 0.5;
a[i].w = 8;
a[i].h = 20;
a[i].life = 1;
}
a[0].add_x = -0.5;
a[1].add_x = 0;
a[2].add_x = 0.5;
}
int is_crash(Enemy a, Bullet b) //子彈和敵機是否相撞
{
int rex = (a.w + b.w) / 2;
int rey = (a.h + b.h) / 2;
int lx = abs((int)(a.x + a.w / 2 - b.x - b.w / 2));
int ly = abs((int)(a.y + a.h / 2 - b.y - b.h / 2));
if (lx < rex &&ly < rey)
{
return 1;
}
return 0;
}
int is_crash_boss(Boss a, Bullet b) //子彈和boss是否相撞
{
int rex = (a.w + b.w) / 2;
int rey = (a.h + b.h) / 2;
int lx = abs((int)(a.x + a.w / 2 - b.x - b.w / 2));
int ly = abs((int)(a.y + a.h / 2 - b.y - b.h / 2));
if (lx < rex &&ly < rey)
{
return 1;
}
return 0;
}
int is_crash_plane(Plane a, Enemy_bullet b) //敵機子彈是否和我方飛機相撞
{
a.x -= a.w / 2;
a.y -= a.h / 2;
int rex = (a.w + b.w) / 2;
int rey = (a.h + b.h) / 2;
int lx = abs((int)(a.x + a.w / 2 - b.x - b.w / 2));
int ly = abs((int)(a.y + a.h / 2 - b.y - b.h / 2));
if (lx < rex &&ly < rey)
{
return 1;
}
return 0;
}
int is_crash_boss_plane(Plane a, Boss_bullet b) //boss子彈是否和我方飛機相撞
{
a.x -= a.w / 2;
a.y -= a.h / 2;
int rex = (a.w + b.w) / 2;
int rey = (a.h + b.h) / 2;
int lx = abs((int)(a.x + a.w / 2 - b.x - b.w / 2));
int ly = abs((int)(a.y + a.h / 2 - b.y - b.h / 2));
if (lx < rex &&ly < rey)
{
return 1;
}
return 0;
}