C语言写飞机大战编程项目
目录
一、设计目标
二、设计方案
三、游戏界面
四、操作说明(所完成程序使用和操作方法的简要说明)
五、C语言代码编写
一、设计目标
通过游戏设计,实现我方飞机与敌机的对战,设置不同类型敌机,且不同类型敌机血量不同,我方飞机可以全屏移动,敌机自上而下移动,不同敌机类型随机出现,我方飞机可以发射子弹攻击敌机,设置得分和血条,子弹击毁敌机实现敌机爆炸,增加得分,我方飞机与敌机相撞,将敌机撞毁,我方飞机血量减少并扣分,敌机越过我方防线,我方扣分。我方血量减少为0时失败,达到一定分数时胜利。在达到一定分数时,敌机下落速度加快,达到一定分数时,我方敌机移动加快。加入游戏背景图和背景音效,在击毁或撞毁敌机时有爆炸音效,失败、胜利有音乐播放。整个游戏,实现游戏菜单界面,按1开始游戏2退出游戏,3暂停游戏,实现暂停和继续游戏的切换,或暂停,退出游戏的切换。
二、设计方案
通过学习第三方工具easy X图形库的使用,以及photoshop的使用,制作图片和掩码图,加载到代码中,实现游戏背景和飞机图片,子弹图片,爆炸图片等各类不同图片的加载和输出。通过设计菜单界面实现开始、暂停游戏。使用枚举列出三种飞机类型,使用结构体定义与飞机有关的变量,包括飞机坐标,血量,位置,类型。使用模块化的方式,一次编写游戏开始菜单函数、图片加载函数、输出敌机函数、初始化游戏数据函数、击落飞机函数、游戏画面绘制函数、产生子弹函数、产生敌机函数、子弹移动函数、敌机移动函数、定时器封装函数(实现多架敌机随机先后出现,不要同时出现)、角色移动函数、主函数(主函数调用各函数)
三、游戏界面
1、游戏菜单界面,按1开始游戏,2退出游戏,3暂停游戏,实现暂停和继续游戏的切换,或暂停,退出游戏的切换。
2、游戏运行画面
四、操作说明(所完成程序使用和操作方法的简要说明)
wasd移动,空格发射子弹,子弹击毁敌机实现敌机爆炸,增加得分,我方飞机与敌机相撞,将敌机撞毁,我方飞机血量减少并扣分,敌机越过我方防线,我方扣分。我方血量减少为0时失败,达到一定分数(1000)时胜利。在达到一定分数时,敌机下落速度加快,达到一定分数时,我方敌机移动加快。
五、C语言代码编写
#include<graphics.h>
#include<conio.h>
#include<math.h>
#include<stdio.h>
#include<time.h>
#include<tchar.h>/*本游戏目前实现的功能为,1进入开始游戏,2退出游戏,3中途暂停,暂停后1继续或者2退出,血量100
进行记分,撞击敌机血量减少并扣分,敌机进入下方扣分,分数达到1000时胜利,血量小于1时失败,达到一定分数后,敌机加速移动,我方飞机也加速移动*/
#pragma comment(lib,"Winmm.lib")
#define High 1080 //游戏画面尺寸
#define Width 1080
#define Bullet_NUM 10//玩家子弹数量
#define ENEMY_NUM 8//敌机数量 enum My
{BIG, SMALL, SENIOR
};//使用枚举的方法,飞机类型有三种
IMAGE img_bk;//背景图片
float position_x, position_y;//飞机的位置
float bullet_x, bullet_y;//子弹位置
float enemy_x, enemy_y;//敌机位置
IMAGE img_planeNormal1, img_planeNormal2;//正常飞机图片
IMAGE img_bullet1, img_bullet2;//子弹图片
IMAGE img_planeExplode1, img_planeExplode2;//爆炸飞机图片
IMAGE img_enemy[3][2];//敌机图片
IMAGE img_background;//开始画面背景
IMAGE img_victory;//胜利时背景
IMAGE img_fail;//失败时背景
int isExplode = 0;//飞机是否爆炸
int score = 0,n=50;//得分
int m = 0, isexplode = 0;
int luxuanhong=0;//定义的一个变量
int gameStatus = 0;//游戏状态,0为初始菜单界面,1为正常游戏,2为结束游戏状态,3为游戏暂停void startMenu();//初始菜单界面void pauseMenu();//游戏暂停后的菜单界面,按3键后启动该界面
struct Plane//飞机结构(结构体)
{int x;int y;bool live;//是否存活int width, height;int hp;int Hp;int type;//敌机的类型
}player, bull[Bullet_NUM], enemy[ENEMY_NUM];
void startMenu()//显示开始的菜单
{putimage(250, 50, &img_background);//显示背景setbkmode(TRANSPARENT);//settextcolor(BLACK);setlinecolor(WHITE);settextstyle(50, 0, _T("黑体"));outtextxy(500, 400, L"1进入游戏");outtextxy(500, 500, L"2退出");FlushBatchDraw();Sleep(2);
if (GetAsyncKeyState('1'))
gameStatus = 1;
else if (GetAsyncKeyState('2'))
{gameStatus = 2;exit(0);
}
}
void pauseMenu()//显示暂停时的画面
{putimage(250, 50, &img_background);//显示背景setbkmode(TRANSPARENT);settextstyle(50, 0, _T("黑体"));outtextxy(500, 400, L"1继续游戏");outtextxy(500,500, L"2退出");FlushBatchDraw();Sleep(20);if (GetAsyncKeyState('1'))gameStatus = 1;else if (GetAsyncKeyState('2')){gameStatus = 2;exit(0);//直接结束程序}
}void load()//加载图片的函数,loadimage后图片俩俩出现,一张原图一张掩码图
{mciSendString(L"open 1.mp3 alias p", NULL, 0, NULL);//打开背景音乐mciSendString(L"play p repeat", NULL, 0, NULL);//循环播放//加载音乐/*initgraph(Width, High);*/
//设置窗口标题文字//SetWindowText(hwnd, L"飞机大战v2021.0");//loadimage(&img_bk, L"picture//4.jpg");//背景图片loadimage(&img_bk, L"picture//4.jpg");loadimage(&img_enemy[0][0], L"picture//10000.jpg");//敌机1图片loadimage(&img_enemy[0][1], L"picture//1000.jpg");loadimage(&img_background, L"picture//z.jpg");//开始菜单背景loadimage(&img_enemy[1][0], L"picture//t.jpg");//敌机2图片loadimage(&img_enemy[1][1], L"picture//q.jpg");loadimage(&img_enemy[2][0], L"picture//y.jpg");//敌机3图片loadimage(&img_enemy[2][1], L"picture//p.jpg");loadimage(&img_fail, L"picture//333.jpg");//失败图片loadimage(&img_victory, L"picture//22222.jpg");//胜利图片loadimage(&img_planeNormal1, L"picture//603.jpg");//我方飞机图片loadimage(&img_planeNormal2, L"picture//600.jpg");loadimage(&img_bullet1, L"picture//13.jpg");//子弹图片loadimage(&img_bullet2, L"picture//12.jpg");loadimage(&img_planeExplode1, L"picture//k.jpg");//爆炸图片loadimage(&img_planeExplode2, L"picture//009.jpg");}
void enemyHp(int i)
{//敌机大小血量,宽度,高度int flag = rand() % 15;//0-14,以下为各类型敌机的出现概率if (flag >= 0 && flag <= 2){enemy[i].type = BIG;enemy[i].hp = 3;enemy[i].width = 200;enemy[i].height = 143;}else if (flag >= 0 && flag <= 3){enemy[i].type = SENIOR;enemy[i].hp = 2;enemy[i].width = 232;enemy[i].height = 143;}else if (flag >= 0){enemy[i].type = SMALL;enemy[i].hp = 1;enemy[i].width = 100;enemy[i].height = 76;}
}
void gameInit()//初始化游戏数据
{player.x = 500;player.y = 600;player.live = true;player.Hp = 100;for (int i = 0; i < Bullet_NUM; i++)//初始化子弹{bull[i].x = 0;bull[i].y = 0;bull[i].live = false;}for (int i = 0; i < ENEMY_NUM; i++){enemy[i].live = false;enemyHp(i);}
}void playplane()//击落飞机
{for (int i = 0; i < ENEMY_NUM; i++){if (!enemy[i].live){continue;}for (int k = 0; k < Bullet_NUM; k++){if (!bull[k].live){continue;}if (bull[k].x > enemy[i].x - 25 && bull[k].x<enemy[i].x + enemy[i].width && bull[k].y>enemy[i].y && bull[k].y < enemy[i].y + enemy[i].height){bull[k].live = false;//子弹消失enemy[i].hp--;//血量减少,每次减少}}if (enemy[i].hp <= 0){enemy[i].live = false;//根据血量判断敌机生死if (enemy[i].type == BIG){score += 20;printf("%d", score);}if (enemy[i].type == SENIOR){score += 10; printf("%d", score);}if (enemy[i].type == SMALL){score += 5; printf("%d", score);}mciSendString(L"close 4", NULL, 0, NULL);//先把前面一次的音乐关闭mciSendString(L"open 4.mp3 alias 4", NULL, 0, NULL);//打开背景音乐mciSendString(L"play 4 ", NULL, 0, NULL);//循环播放}}
}
void show()//游戏绘制
{load();while (gameStatus == 3){pauseMenu();}putimage(0, 0, &img_bk);putimage(player.x, player.y, &img_planeNormal1);//显示正常飞机putimage(player.x, player.y, &img_planeNormal2);//显示正常飞机//putimage(enemy_x, enemy_y, &img_enemyPlane1, SRCAND);//显示敌机//putimage(enemy_x, enemy_y, &img_enemyPlane2, SRCPAINT);for (int i = 0; i < Bullet_NUM; i++){if (bull[i].live)//绘制子弹{putimage(bull[i].x, bull[i].y, &img_bullet1, SRCAND);//显示子弹putimage(bull[i].x, bull[i].y, &img_bullet2, SRCPAINT);}} //绘制敌机for (int i = 0; i < ENEMY_NUM; i++){if (enemy[i].live){if (enemy[i].type == BIG){putimage(enemy[i].x, enemy[i].y, &img_enemy[1][0], SRCAND);//显示敌机putimage(enemy[i].x, enemy[i].y, &img_enemy[1][1], SRCPAINT);}if (enemy[i].type == SENIOR){putimage(enemy[i].x, enemy[i].y, &img_enemy[2][0], SRCAND);//显示敌机putimage(enemy[i].x, enemy[i].y, &img_enemy[2][1], SRCPAINT);}if (enemy[i].type == SMALL){putimage(enemy[i].x, enemy[i].y, &img_enemy[0][0], SRCAND);//显示敌机putimage(enemy[i].x, enemy[i].y, &img_enemy[0][1], SRCPAINT);}}if (!enemy[i].live && enemy[i].hp <= 0){putimage(enemy[i].x, enemy[i].y, &img_planeExplode1, SRCAND);//显示爆炸敌机putimage(enemy[i].x, enemy[i].y, &img_planeExplode2, SRCPAINT);}if (abs(abs((int)player.x - (int)enemy[i].x) + abs((int)player.y - (int)enemy[i].y)) < 150&&isexplode==0){isexplode = 1;enemy[i].live = false;enemy[i].hp = 0;score-=5;player.Hp-=2;putimage(enemy[i].x, enemy[i].y, &img_planeExplode1, SRCAND);//显示爆炸敌机putimage(enemy[i].x, enemy[i].y, &img_planeExplode2, SRCPAINT);mciSendString(L"close 4", NULL, 0, NULL);//先把前面一次的音乐关闭mciSendString(L"open 4.mp3 alias 4", NULL, 0, NULL);//打开背景音乐mciSendString(L"play 4 ", NULL, 0, NULL);//循环播放}if (luxuanhong == 0 && enemy[i].y >= 750)//敌机跑到屏幕下方,扣分{luxuanhong = 1; score-=5;}}outtextxy(0, 5, L"得分:");TCHAR s[5];_stprintf_s(s, L"%d", score);outtextxy(150, 5, s);outtextxy(0, 50, L"血量:");TCHAR Hp[50];_stprintf_s(Hp, L"%d", player.Hp);outtextxy(150, 50, Hp);Sleep(2);} //产生子弹
void creatBullet()
{for (int i = 0; i < Bullet_NUM; i++){if (!bull[i].live){bull[i].x = player.x + 55;bull[i].y = player.y - 40;bull[i].live = true;break;}}
}//产生敌机
void creatEnemy()
{for (int i = 0; i < ENEMY_NUM; i++){if (!enemy[i].live){isexplode = 0;luxuanhong = 0;enemy[i].live = true;enemy[i].x = rand() % (Width - 100);enemy[i].y = 0;enemyHp(i);//重置机型血量break;}}
}//子弹移动
void BulletMove(int speed)
{for (int i = 0; i < Bullet_NUM; i++){if (bull[i].live)//假{bull[i].y -= speed;if (bull[i].y < 0){bull[i].live = false;//重新被找}}}
}//敌机移动
void enemyMore(int speed)
{for (int i = 0; i < ENEMY_NUM; i++)if (enemy[i].live){enemy[i].y += speed;if (enemy[i].y > High){enemy[i].live = false;}}
}//定时器封装,静态变量,只初始化一次,不重复初始化
bool Timer(int ms, int id)
{static DWORD t[10];//自动初始化为0if (clock() - t[id] > ms){t[id] = clock();return true;//保存上次数据记录}return false;//默认值,不是0就认为是真
}
void playerMove(int speed)//角色移动
{if (GetAsyncKeyState('W')){if (player.y > 0)//能移动{player.y -= speed;}}if (GetAsyncKeyState('S')){if (player.y < 700){player.y += speed;}}if (GetAsyncKeyState('A')){if (player.x + 60 > 0){player.x -= speed;}}if (GetAsyncKeyState('D')){if (player.x < 1000){player.x += speed;}}static DWORD t1 = 0, t2 = 0;if (GetAsyncKeyState(' ') && Timer(500, 1)){creatBullet();//创建一个子弹mciSendString(L"close 3 ", NULL, 0, NULL);mciSendString(L"open 3.mp3 alias 3", NULL, 0, NULL);//打开背景音乐mciSendString(L"play 3 ", NULL, 0, NULL);//循环播放}t2 = GetTickCount();}int main()
{load();initgraph(Width, High, SHOWCONSOLE);gameInit();//双缓冲绘图BeginBatchDraw();while (!gameStatus){startMenu();//pauseMenu();}while (player.Hp != 0 && score < 1000){if (GetAsyncKeyState('3')){while (1){pauseMenu();if (GetAsyncKeyState('1'))break;}}//system("pause");show();FlushBatchDraw();if (score < 200)playerMove(10);if(score>=200&&score<500)playerMove(15);if (score > 500 && score < 800)playerMove(16);if (score > 800 && score < 1000)playerMove(17);BulletMove(30);if (Timer(800, 0)){creatEnemy();//产生敌机}//时间函数,时间变化,t2变化,满足条件,定时器,控制敌机的出现,移动if (Timer(10, 2)){if (score < 200)enemyMore(2);if (score >= 200 && score < 500)enemyMore(3);if (score >= 500 && score < 800)enemyMore(4);if (score >=800 && score < 1000)enemyMore(4);}playplane();}cleardevice();if (player.Hp <= 0){//mciSendString(L"close fail", NULL, 0, NULL);//先把前面一次的音乐关闭//mciSendString(L"open fail.mp3 alias m", NULL, 0, NULL);//打开背景音乐//mciSendString(L"play m", NULL, 0, NULL);//循环播放putimage(0, 0, &img_fail);mciSendString(L"close p", NULL, 0, NULL);mciSendString(L"close wu", NULL, 0, NULL);//先把前面一次的音乐关闭mciSendString(L"open wu.mp3 alias m", NULL, 0, NULL);//打开背景音乐mciSendString(L"play m", NULL, 0, NULL);//循环播放}if (score == 1000){putimage(0, 0, &img_victory);mciSendString(L"close p", NULL, 0, NULL);mciSendString(L"close my", NULL, 0, NULL);//先把前面一次的音乐关闭mciSendString(L"open my.mp3 alias v", NULL, 0, NULL);//打开背景音乐mciSendString(L"play v ", NULL, 0, NULL);//循环播放system("pause");}EndBatchDraw();Sleep(1000000);return 0;
}