C++ EGE 实现飞机大战小游戏图形界面

飞机大战因为没有了地图的限制,所以相比较坦克大战而言稍微简单一些。
而游戏的可玩性和复杂度一般应该是成正比的。
但是飞机大战并没有因为地图上的省略而变得没有可玩性,因为这个程序把像坦克大战那样需要地图的游戏的“空间”上的复杂,转换为了“时间”上的复杂。
该程序会根据不同时期的得分和进度,改变不同的策略。

技术环节:
编译环境:Windows VS2019

需求:
可控制飞机进行上下左右移动,所有飞机自动根据时间间隔发射子弹,己方子弹攻击到对方飞机,对敌人进行增添、我方道具使用、累加到一定分数出现最终boss及子弹攻击到对方飞机显示爆炸效果等。
当前游戏还增加了背景音乐和打击音效。

思路:
根据我方飞机和地方飞机各自的特性写出各自的类。

敌方飞机对象使用vector动态数组容器进行存储,所有敌方飞机移动实际上就是遍历一次敌机容器,让被一个飞机移动,同时便于向数组中尾插新的敌人,和删除生命值为空的敌人。

同样的思想可以用在子弹的发射上,只是子弹发射需要根据距上一次子弹发射后的时间来进行下一次子弹发射。
击中敌人的子弹和越过屏幕边界的子弹会被删除。

难点:
根据子弹发射时的时间减去子弹发射后一定时间的差,来进行无缝衔接的子弹发射。

将图片对象插入到数组中,将数组放入到游戏循环,根据击中飞机时为true的标记显示固定帧数的爆炸效果。

注意:
包含<graphics.h>图形库需要提前配置EGE图形库。
如要在其他graphics图形库下编译,可能需要修改部分代码。

图片素材来源于网络。
如有您需要图片素材,可以私信博主。

运行效果:




#include <graphics.h>  //图形库
#include <ctime>      //clock
#include <vector>     //动态数组容器using namespace std;    //设置图片对象宽高全局函数
//将设置图片对象宽高封装为一个函数
void setimage(int pwidth, int pheight, PIMAGE img_1)
{//获取参数图片对象的宽高int whidth = getwidth(img_1), height = getheight(img_1);//创建一个临时图片对象,这个新的图像对象的宽高为要重新设置的图像的宽高PIMAGE tempimg = newimage(pwidth, pheight);putimage(tempimg, 0, 0, pwidth, pheight, img_1, 0, 0, whidth, height);   //将原本img中的图像拉伸绘制到img_2中getimage(img_1, tempimg, 0, 0, pwidth, pheight);      //img再获取temp中的图像delimage(tempimg);  //使用完毕将释放掉
}struct bulxy           //子弹坐标和属性全局结构
{int b_x;           //横坐标int b_y;           //纵坐标int prop;          //子弹的属性
};//飞机父类
class Plane
{public:int health = 0;                 //飞机血量protected:int width = 0, height = 0;        //飞机的宽高int m_x = 0, m_y = 0;          //飞机横纵坐标clock_t now_1 = clock();       //发射子弹开始时间clock_t now_2 = 0;               //发射子弹后时间int timediff = 0;             //发射子弹时间差 now_2 - 1int sign = 0;                   //区分飞机变量bulxy temp = { 0 };                //用于向数组中插入结构vector<bulxy> bullvec;            //子弹动态数组public:int getwidth()                   //获取飞机宽{return width;}int getheight()                   //获取飞机高{return height;}
};//敌人飞机类
class Planehose: public Plane
{private:PIMAGE hoseimg_1 = newimage(); //敌人小兵PIMAGE bulletimg = newimage();   //子弹图片对象int planeprop = 0;             //飞机属性int speed_x = 0, speed_y = 0;   //子弹速度每帧x轴和y轴移动单位数int attack = 0;                  //敌机攻速(攻击间隔)//新建子弹函数,根据对象飞机属性新建固定的子弹inline void pushlaunch()                   //向数组插入\新建子弹{//根据属性确定子弹发射的位置和方式switch (planeprop){case 1:       //小兵case 2:     //大兵子弹temp.b_x = m_x + 51, temp.b_y = m_y + 60; //确定新子弹的位置temp.prop = 2;                       //子弹属性向左bullvec.push_back(temp);            //将子弹插入进数组中temp.prop = 3;                      //子弹属性向右bullvec.push_back(temp);break;case 3:       //小BOSS子弹temp.b_x = m_x + 110, temp.b_y = m_y + 180;    //确定新子弹的位置temp.prop = 2;                       //子弹属性向左bullvec.push_back(temp);temp.prop = 3;                     //子弹属性向右bullvec.push_back(temp);temp.prop = 1;                     //子弹属性向下bullvec.push_back(temp);break;case 4:       //最终BOSS子弹//所有子弹位于y轴位于m_y + 160,子弹属性为1temp.b_y = m_y + 160, temp.prop = 1;//分别设置每发子弹的x轴,然后将这枚子弹插入进子弹数组中temp.b_x = m_x - 20;bullvec.push_back(temp);temp.b_x = m_x + 76;bullvec.push_back(temp);temp.b_x = m_x + 172;bullvec.push_back(temp);temp.b_x = m_x + 268;bullvec.push_back(temp);temp.b_x = m_x + 364;bullvec.push_back(temp);temp.b_x = m_x + 460;bullvec.push_back(temp);}}//子弹发射速度inline void attackspeed(){now_2 = clock();           //获取一次系统时间(精确到毫秒)timediff = now_2 - now_1;   //通过上一次发射子弹时间减去当前时间计算出已发射子弹的时间switch (planeprop)            //根据不同飞机,设定飞机发射子弹后多长时间再发射一枚子弹{case 1: //小兵attack = 820; break;case 2: //大兵attack = 720; break;case 3:  //小BOSSattack = 680; break;case 4: //最终BOSSattack = 300;}if (timediff >= attack)      //发射子弹后固定时间后,再次发射子弹 攻击速度{pushlaunch();           //新建子弹timediff = 0;            //累计时间重置now_1 = clock();       //重新获取子弹发射时时间}}//子弹速度函数inline void laumoveunit(){//根据飞机属性,确定飞机子弹的xy轴每帧移动单位switch (planeprop){case 1:case 2:      //小大兵speed_x = 4, speed_y = 4; break;case 3:      //精英兵speed_x = 6, speed_y = 18; break;case 4:     //最终BOSSspeed_x = 0, speed_y = 8;}}//子弹移动方向函数inline void laudire(){//所有子弹移动//根据子弹的属性,确定不同子弹的运动方向//通过对子弹的坐标进行+= 或 -=实现int bullsizetemp = bullvec.size();for (int i = 0; i < bullsizetemp; i++)switch (bullvec[i].prop)        //判断每一个子弹的属性,根据属性决定子弹移动方向{case 1:        //子弹1运动垂直向下bullvec[i].b_y += speed_y; //垂直向下子弹仅移动y轴break;case 2:      //子弹2运动向左下bullvec[i].b_y += speed_y, bullvec[i].b_x -= speed_x;  //左下子弹y轴逐渐增加,x轴减小break;case 3:       //右下bullvec[i].b_y += speed_y, bullvec[i].b_x += speed_x;   //右下子弹y轴逐渐增加,x轴增大break;}}//显示子弹函数inline void laushow(){//遍历子弹数组,显示所有子弹//这里使用自动数据类型变量遍历结构xy属性for (auto bullvectempi : bullvec)putimage_withalpha(NULL, bulletimg, bullvectempi.b_x, bullvectempi.b_y);}//删除越界子弹函数inline void laudelete(){//删除敌人越界的子弹for (vector<bulxy>::const_iterator it = bullvec.begin(); it != bullvec.end(); it++)if (it->b_y >= 800 || it->b_x + 18 <= 0 || it->b_x >= 500){bullvec.erase(it);break;}}//封装所有子弹相关函数void planlaunch(){attackspeed();           //子弹射速函数laumoveunit();          //子弹速度函数laudire();              //子弹方向函数laushow();              //显示子弹函数laudelete();            //删除越界子弹函数}public:int& setgetm_x()      //获取和修改敌人飞机xy坐标值{return m_x;}int& setgetm_y(){return m_y;}int gethoseprop()     //获取和敌人的prop属性*****{return planeprop;}int gethealth()           //获取敌人血量值{return health;}vector<bulxy>& gethosebullvec()              //获取敌人的子弹数组{return bullvec;}//根据参数,为敌人飞机对象初始化坐标、血量、图片信息Planehose(int prop){this->planeprop = prop;       //将传进来的参数赋给类变量//根据属性获取不同的子弹图片素材,设置飞机宽高switch (prop){case 1:      case 2:     //大小兵getimage(bulletimg, "飞机大战程序素材\\敌人子弹.png");setimage(18, 18, bulletimg);width = 120, height = 90;    //飞机宽高break;case 3:     //精英飞机getimage(bulletimg, "飞机大战程序素材\\敌人子弹2.png");setimage(18, 18, bulletimg);width = 240, height = 180; //飞机宽高break;case 4:     //最终BOSSgetimage(bulletimg, "飞机大战程序素材\\敌人导弹.png");setimage(40, 81, bulletimg);//子弹图片大小width = 480, height = 360;    //飞机宽高}m_x = rand() % 380, m_y = -(rand() % 101 + 200);          //随机横纵坐标//飞机素材switch (prop){case 1:getimage(hoseimg_1, "飞机大战程序素材\\敌人飞机大兵.png");health = 150;                 //血量break;case 2:getimage(hoseimg_1, "飞机大战程序素材\\敌人飞机精英怪.png");health = 250;break;case 3:getimage(hoseimg_1, "飞机大战程序素材\\敌人飞机BOSS2.png");health = 440;break;case 4:getimage(hoseimg_1, "飞机大战程序素材\\敌人飞机BOSS.png");health = 20000;         //血量m_x = 10, m_y = -360; //BOSS从固定位置出发}setimage(width, height, hoseimg_1);           //设置图片宽高}//敌人移动void move(){planlaunch();        //发射子弹//根据不同的飞机设置不同的在没有出现时,飞机血量锁定if((m_y + height) <= 0)switch (planeprop){case 1:health = 150; break;case 2:health = 250; break;case 3:health = 440; break;case 4:health = 20000;}//根据飞机不同属性确定飞机移动速度switch (planeprop){case 1:case 2:      //大小兵m_y += 2; break;case 3:      //精英飞机m_y++; break;case 4:        //最终BOSS    仅缓慢移动一小段距离if (m_y <= -120) m_y++; }putimage_withalpha(NULL, hoseimg_1, m_x, m_y); //显示飞机图片}
};//我方飞机子类
class Planefind :public Plane
{private:const PIMAGE findplaneimg = newimage();    //我方飞机图片对象const PIMAGE bulletimg = newimage(); //子弹图片对象const PIMAGE shieldimg = newimage();   //护盾图片对象const PIMAGE shieldicon = newimage();  //护盾图标const PIMAGE unskillimg = newimage();    //必杀图片对象const PIMAGE unskillicon = newimage(); //必杀图标char key = 0;                            //接收键值int inerdis = 0;                     //飞机惯性走的距离bool sign = false;                       //是否播放爆炸效果int atemp = 0;                           //记录子弹爆炸效果的次数int btarg_x = 0, btarg_y = 0;            //记录集中敌人的子弹位置int btemp = 0;                            //记录自身爆炸效果的次数int score = 0;                            //游戏得分bool shieldsign = false;             //标记护盾开启clock_t shiledtime_1 = 0;              //记录护盾时间clock_t shiledtime_2 = 0;int shieldnum = 3;                       //护盾使用次数bool unskillsign = false;              //标记必杀开启clock_t unskilltime_1 = 0;             //记录必杀时间clock_t unskilltime_2 = 0;int unskillnum = 2;                     //必杀技使用次数bool upgrade = false;                 //飞机是否已升级int lifenum = 3;                      //我方飞机的生命数量PIMAGE explimgarr[24] = { 0 };          //爆炸效果图片对象数组int i = 0;                             //用于循环MUSIC music;                          //音乐对象//升级飞机和子弹外观void alterbullplan(){getimage(findplaneimg, "飞机大战程序素材\\己方红色飞机.png");setimage(80, 86, findplaneimg);getimage(bulletimg, "飞机大战程序素材\\我方导弹.png");setimage(17, 37, bulletimg);upgrade = true;      //是否已经升级}//新建子弹void pushlaunch(){if (upgrade)       //如果已经升级{temp.b_x = m_x - 10, temp.b_y = m_y + 40;bullvec.push_back(temp);temp.b_x = m_x + 31, temp.b_y = m_y + 40;bullvec.push_back(temp);temp.b_x = m_x + 73, temp.b_y = m_y + 40;bullvec.push_back(temp);return;}//没有升级temp.b_x = m_x + 24, temp.b_y = m_y - 20;   //确定新子弹的位置bullvec.push_back(temp);          //在子弹数组中插入新的子弹}//子弹移动inline void launmove()                     {//所有子弹移动if (upgrade)                               //如果已经升级飞机则提升弹道速度for (int i = 0; i < bullvec.size(); i++)bullvec[i].b_y -= 24;               //升级后的速度elsefor (int i = 0; i < bullvec.size(); i++)bullvec[i].b_y -= 16;                //一般速度//输出所有子弹for (int i = 0; i < bullvec.size(); i++)putimage_withalpha(NULL, bulletimg, bullvec[i].b_x, bullvec[i].b_y);}//发射子弹,参数区分不同的飞机和图片void launch(){now_2 = clock();          //精确到毫秒获取时间timediff = now_2 - now_1;   //计算子弹发射时间差int attack = 0;             //时间间隔if (upgrade)              //如果已经升级飞机则提升攻速attack = 180;           //升级后的攻速elseattack = 320;          //一般攻速if (timediff >= attack)       //发射子弹后时间大于一定数值(毫秒)则再次发射子弹{pushlaunch();          //新建子弹timediff = 0;            //累计时间重置now_1 = clock();       //重新获取子弹发射时时间}launmove();                   //子弹移动//删除我方越界的子弹for (vector<bulxy>::const_iterator it = bullvec.begin(); it != bullvec.end(); it++)if (it->b_y <= -80){bullvec.erase(it);break;}}//攻击敌人与被敌人攻击void beattack(vector<Planehose>& hoseplanevec, bool& explsign){if (!unskillsign)           //在没有释放必杀技时不停发射子弹launch();              //发射子弹int hosesizex, hosesizey; //敌人飞机宽高变量for (vector<Planehose>::iterator hoseit = hoseplanevec.begin(); hoseit != hoseplanevec.end(); hoseit++)for (vector<bulxy>::const_iterator it = bullvec.begin(); it != bullvec.end(); it++){hosesizex = hoseit->getwidth(), hosesizey = hoseit->getheight();   //敌人飞机的宽高//如果有一发子弹的坐标与敌人重合,则敌人掉血if (it->b_x + 17 >= hoseit->setgetm_x() && it->b_x + 17 <= hoseit->setgetm_x() + hosesizex &&it->b_y >= hoseit->setgetm_y() && it->b_y <= hoseit->setgetm_y() + hosesizey){hoseit->health -= 50;                 //敌人的飞机血量减少btarg_x = it->b_x, btarg_y = it->b_y;    //记录爆炸效果坐标sign = true;                         //控制爆炸效果if (hoseit->health <= 0)             //如果本次击中的敌人的血量<=0{switch (hoseit->gethoseprop())     //根据消灭的敌人,增加不同得分{case 1:score++;break;case 2:score += 2;break;case 3:score += 4;break;case 4:score += 21;}hoseplanevec.erase(hoseit);            //删除与我方子弹重合且血量为空的飞机//产生一个新的敌军飞机Planehose hoseplane(rand() % 3 + 1);//敌人hoseplanevec.push_back(hoseplane);  //插入进敌人飞机数组goto L1;                         //跳出双重循环}bullvec.erase(it);     //删除这个击中敌人的子弹break;}}L1://击中敌人时子弹处爆炸效果if (sign){if (music.GetPlayStatus() == MUSIC_MODE_STOP) //播放击中音效,必须在该音效播放完毕后播放music.Play(100, 400);putimage_withalpha(NULL, explimgarr[atemp], btarg_x - 17, btarg_y);atemp++;         //根据爆炸图片数组来显示爆炸效果if (atemp > 23)     //播放完毕停止sign = false, atemp = 0;  //关闭信号,重置数组下标}//被敌人击中时自己的爆炸效果,显示在飞机之上if (explsign){if (music.GetPlayStatus() == MUSIC_MODE_STOP)    //播放击中音效,必须在该音效播放完毕后播放music.Play(80, 450);putimage_withalpha(NULL, explimgarr[btemp], m_x + 20, m_y + 20);btemp++;           //根据爆炸图片数组来显示爆炸效果if (btemp > 23)     //播放完毕停止explsign = false, btemp = 0;} }//两个技能void tuoskill(vector<Planehose>& hoseplanevec){unskilltime_2 = clock();       //必杀开启之后的时间int temptime_1 = unskilltime_2 - unskilltime_1; //相减if (unskillsign)                //如果必杀开启{//同时使用一次护盾,不消耗次数shieldsign = true;     //护盾开启标记shiledtime_1 = clock();    //护盾开启时的时间putimage_withalpha(NULL, unskillimg, m_x - 32, m_y - 690);    //显示护盾图片health = 400;          //血量恢复且护盾时效内不会掉血if (temptime_1 >= 6000) unskillsign = false;       //必杀有效时间//必杀技攻击敌人的判定,这里只判断x轴for (vector<Planehose>::iterator hoseit = hoseplanevec.begin(); hoseit != hoseplanevec.end(); hoseit++){int hosesizex = 0;    //敌人飞机的大小xyswitch (hoseit->gethoseprop()){case 1:case 2:hosesizex = 120;break;case 3:hosesizex = 240;break;case 4:hosesizex = 480;}//根据敌机的大小判断位置,这里只判断x轴if ((m_x - 16 < hoseit->setgetm_x()) || (m_x - 16 > hoseit->setgetm_x() + hosesizex))continue;hoseit->health -= 50;           //敌人的飞机血量减少btarg_x = m_x + 30, btarg_y = hoseit->setgetm_y() + 50; //记录爆炸效果坐标,根据敌机坐标确认if(hoseit->gethoseprop() == 4)                         //如果击中的敌人是最终BOSS则单独确定爆炸位置btarg_y += 160;sign = true;                 //控制爆炸效果if (hoseit->health > 0)           //如果本次击中的敌人的血量减少后>0 结束本次循环continue;switch (hoseit->gethoseprop()) //根据消灭的敌人,增加得分{case 1:score++;break;case 2:score += 2;break;case 3:score += 4;break;case 4:score += 21;}hoseplanevec.erase(hoseit);  //删除与我方子弹重合且血量为空的飞机//产生一个新的敌军飞机Planehose hoseplane(rand() % 3 + 1);//敌人hoseplanevec.push_back(hoseplane);  //插入进敌人飞机数组break;}}shiledtime_2 = clock();     //护盾开启之后的时间int temptime_2 = shiledtime_2 - shiledtime_1;   //相减if (shieldsign)             //如果护盾开启{putimage_withalpha(NULL, shieldimg, m_x - 22, m_y - 10);health = 400;         //血量恢复且护盾时效内不会掉血if (temptime_2 >= 5000) shieldsign = false;        //护盾有效时间}}//飞机接收键值移动void controlmove(){//移动//键盘按下if (kbhit()){//接收一个键值key = getch();switch (key){case 'w':               //w飞机向上飞,并且确定一个向上滑行距离m_y -= 6;          //移动距离inerdis = m_y - 18;  //惯性距离break;case 'a':m_x -= 6;inerdis = m_x - 18;break;case 's':m_y += 6;inerdis = m_y + 18;break;case 'd':m_x += 6;inerdis = m_x + 18;break;case 'e':                //使用护盾if (shieldnum <= 0)       //没有使用次数时不可以使用护盾break;shieldsign = true;       //护盾开启标记shiledtime_1 = clock();    //护盾开启时的时间shieldnum--;break;case 'q':             //必杀技if (unskillnum <= 0)       //没有使用次数时不可以使用护盾break;unskillsign = true;          //必杀技开启标记unskilltime_1 = clock();  //必杀技开始时时间unskillnum--;             //必杀技使用次数break;case ' ':              //空格键暂停putimage_withalpha(NULL, findplaneimg, m_x, m_y);    //先显示一遍飞机getch();}}//确定飞机滑行时的速度和限制飞机移动范围switch (key){case 'w':if (m_y >= inerdis) m_y -= 2;  //飞机结束移动后向特定位置滑行一段距离if (m_y <= 0) m_y = 0;         //飞机坐标越界则重置坐标break;case 'a':if (m_x >= inerdis) m_x -= 2;if (m_x <= 0) m_x = 0;break;case 's':if (m_y <= inerdis) m_y += 2;if (m_y >= 674) m_y = 674;break;case 'd':if (m_x <= inerdis) m_x += 2;if (m_x >= 420) m_x = 420;}}//输出界面信息void putInterface(){//输出当前得分setfont(30, NULL, "黑体");xyprintf(0, 0, "得分:%d", score);setfont(24, NULL, "黑体");xyprintf(0, 50, "生命值:%d", health);xyprintf(0, 90, "生命:%d", lifenum);//图标setfont(20, NULL, "楷体");outtextxy(6, 380, "护盾E");putimage_withalpha(NULL, shieldicon, 10, 410);    //护盾图标xyprintf(24, 460, "%d", shieldnum);             //护盾剩余使用次数outtextxy(1, 510, "必杀技Q");putimage_withalpha(NULL, unskillicon, 12, 540);   //必杀图标  ++xyprintf(26, 590, "%d", unskillnum);          //必杀剩余使用次数}public://构造初始化图片和坐标等,只会执行一次Planefind(){width = 80, height = 86; //飞机宽高//获取并修改图片素材getimage(findplaneimg, "飞机大战程序素材\\己方蓝色飞机.png");setimage(width, height, findplaneimg);getimage(bulletimg, "飞机大战程序素材\\我方普通子弹.png");setimage(34, 74, bulletimg);getimage(shieldimg, "飞机大战程序素材\\护盾.png");setimage(120, 120, shieldimg);getimage(shieldicon, "飞机大战程序素材\\护盾.png");setimage(40, 40, shieldicon);getimage(unskillimg, "飞机大战程序素材\\激光.png");setimage(160, 700, unskillimg);getimage(unskillicon, "飞机大战程序素材\\激光.png");setimage(40, 40, unskillicon);for (i = 0; i < 24; i++) explimgarr[i] = newimage();   //开辟内存//数组中总共8张图片,每张图片有两张重复帧for (i = 0; i < 3; i++) getimage(explimgarr[i], "飞机大战程序素材\\爆炸1.png");for (i = 3; i < 6; i++) getimage(explimgarr[i], "飞机大战程序素材\\爆炸2.png");for (i = 6; i < 9; i++) getimage(explimgarr[i], "飞机大战程序素材\\爆炸3.png");for (i = 9; i < 12; i++) getimage(explimgarr[i], "飞机大战程序素材\\爆炸4.png");for (i = 12; i < 15; i++) getimage(explimgarr[i], "飞机大战程序素材\\爆炸5.png");for (i = 15; i < 18; i++) getimage(explimgarr[i], "飞机大战程序素材\\爆炸6.png");for (i = 18; i < 21; i++) getimage(explimgarr[i], "飞机大战程序素材\\爆炸7.png");for (i = 21; i < 24; i++) getimage(explimgarr[i], "飞机大战程序素材\\爆炸8.png");m_x = 220, m_y = 660;     //飞机初始坐标health = 400;              //血量music.OpenFile("飞机大战程序素材\\击中音效.wma");//打开音乐文件函数}//析构释放图片对象内存~Planefind(){delimage(findplaneimg);delimage(bulletimg);delimage(shieldimg);delimage(shieldicon);delimage(unskillicon);delimage(unskillimg);for (int i = 0; i < 24; i++) delimage(explimgarr[i]);   //释放爆炸效果数组}vector<bulxy> getlaunxy()      //获取我方飞机子弹的坐标数组{return bullvec;}int& setgetplane_x()        //获取或设置坐标{return m_x;}int& setgetplane_y(){return m_y;}int& setgetscore()           //获取或设置得分{return score;}char& setgetkey()           //获取或设置键值{return key;}int& setgetshieldnum()            //获取或设置护盾使用次数{return shieldnum;}int& setgetunskillnumnum()      //获取或设置必杀使用次数{return unskillnum;}int& setgetlifenum()           //获取或设置我方飞机生命数{return lifenum;}//飞机移动bool move(vector<Planehose>& hoseplanevec, bool& explsign){//升级飞机if (score >= 40)                    //如果得分大于40alterbullplan();              //升级飞机putInterface();                       //输出界面信息tuoskill(hoseplanevec);             //两个技能相关//我方飞机生命数量为0时游戏结束if (!lifenum)return true;controlmove();                        //接收键值移动飞机//在飞机坐标位置显示飞机putimage_withalpha(NULL, findplaneimg, m_x, m_y);beattack(hoseplanevec, explsign);   //攻击敌人与被敌人攻击return false;}
};//游戏开始界面
void begingame()
{initgraph(500, 760, INIT_RENDERMANUAL);    //初始化图形界面setcaption("C++ EGE飞机大战");         //设置标题PIMAGE beginimg = newimage();getimage(beginimg,"飞机大战程序素材\\游戏开始背景.jpg");    //获取图片setimage(540, 760, beginimg);         //设置大小PIMAGE planetextimg = newimage();        //获取文字图片getimage(planetextimg, "飞机大战程序素材\\飞机大战字体.png");setimage(500, 340, planetextimg);putimage(0, 0, beginimg);                     //显示背景图putimage_withalpha(NULL, planetextimg, 0, 0);    //显示文字图片setfont(26, 0, "楷体");setcolor(WHITE);                 //设置文字颜色setbkmode(1);                       //文字背景色透明outtextxy(150, 600, "请按任意键继续");mouse_msg msg = { 0 };               //接收开始游戏的鼠标信息while (true){msg = getmouse();                //获取一条鼠标信息if (msg.is_left()) break;     //左键按下delay_fps(70);}delimage(beginimg);                    //释放图片内存delimage(planetextimg);
}//游戏结束界面
void windefgame(const bool sign, Planefind &finplane)
{PIMAGE winbackimg = newimage();       //获取游戏结束背景图片getimage(winbackimg,"飞机大战程序素材\\游戏结束背景.jpg");setimage(500, 760, winbackimg);putimage(0, 0, winbackimg);setfont(64, 0, "楷体");sign ? outtextxy(186, 120, "胜利!") : outtextxy(186, 120, "失败!");setfont(36, 0, "楷体");finplane.setgetscore() += rand() % 10;xyprintf(162, 220, "最终得分:%d", finplane.setgetscore());delimage(winbackimg);while (true) delay_fps(1);
}//判断敌方子弹与我方飞机重合全局函数
void hosebullfinplan(const vector<Planehose>::iterator it, Planefind& finplane, bool& sign, int& lifenum)
{for (vector<bulxy>::const_iterator ait = it->gethosebullvec().begin(); ait != it->gethosebullvec().end(); ait++)if (ait->b_x >= finplane.setgetplane_x() && ait->b_x <= finplane.setgetplane_x() + 80 &&ait->b_y + 18 >= finplane.setgetplane_y() && ait->b_y + 18 <= finplane.setgetplane_y() + 86 ||ait->b_x + 18 >= finplane.setgetplane_x() && ait->b_x + 18 <= finplane.setgetplane_x() + 80 &&ait->b_y + 18 >= finplane.setgetplane_y() && ait->b_y + 18 <= finplane.setgetplane_y() + 86){finplane.health -= 50;             //我方飞机血量减少it->gethosebullvec().erase(ait);   //删除敌人的该子弹//如果飞机血量为空if (finplane.health <= 0 && lifenum >= 0){finplane.setgetplane_x() = 210;  //坐标重置finplane.setgetplane_y() = 660;finplane.health = 400;           //血量重置lifenum--;                        //生命-1finplane.setgetkey() = 0;        //键值重置}sign = true;    //爆炸效果标记开启break;}
}//播放音乐函数
void playmusic(MUSIC &music)
{music.OpenFile("飞机大战程序素材\\背景音乐到死.wma");//打开音乐文件函数music.Play(0);
}//主函数
int main()
{begingame();                           //游戏开始界面MUSIC music;                            //音乐对象playmusic(music);                     //播放音乐函数PIMAGE gameback = newimage();          //背景图片getimage(gameback,"飞机大战程序素材\\游戏背景.jpg");setimage(500, 800, gameback);           //设置背景图片大小Planefind finplane;                   //我方飞机对象vector<Planehose> hoseplanevec;           //敌人飞机对象数组bool sign = false;                       //标记我方爆炸效果显示srand(time(NULL));                      //随机种子,随机数用在敌人飞机xy坐标与飞机属性上bool state = false;                       //记录游戏结束时的状态bool boossign = false;                 //BOSS标记//开局产生i个敌人小兵for (int i = 0; i < 2; i++){Planehose hoseplane(rand() % 2 + 1);//敌人只可能出现小兵和精英兵hoseplanevec.push_back(hoseplane);    //插入进数组}//游戏循环while (true){putimage(0, 0, gameback);            //输出背景图片if (music.GetPlayStatus() == MUSIC_MODE_STOP) //如果背景音乐播放完毕则重新播放playmusic(music);//遍历所有敌人for (vector<Planehose>::iterator it = hoseplanevec.begin(); it != hoseplanevec.end(); it++){if (it->gethoseprop() == 4 && it->gethealth() <= 50)    //如果击败最终BOSS游戏胜利{state = true;             //游戏以胜利状态退出goto OVER;}it->move();                        //敌方飞机移动if (it->setgetm_y() >= 760)      //飞机越界则让飞机重新上去{it->setgetm_x() = rand() % 380;it->setgetm_y() = -(rand() % 101 + 200);}//判断每一个敌人的飞机的子弹是否和我方飞机坐标重合hosebullfinplan(it, finplane, sign, finplane.setgetlifenum());}if (!(finplane.setgetscore() % 4) && finplane.setgetscore())       //得分是四的倍数且不为0的时候额外增加一个敌人{Planehose hoseplane(rand() % 2 + 1);  //敌人只可能出现小兵和精英兵hoseplanevec.push_back(hoseplane);       //插入进数组finplane.setgetscore()++;              //得分额外加1finplane.setgetshieldnum() += 2;      //获得两次护盾使用次数}if (finplane.move(hoseplanevec, sign))     //我方飞机移动,参数为敌人飞机数组、标记、返回真时表示我方飞机阵亡,以失败退出游戏{//返回值为true时,以游戏失败状态退出循环state = false;break;}//得分到达上限则清空所有敌人,挑战最终BOSSif ((finplane.setgetscore()) >= 120 && (!boossign))     //得分大于一定值且标记为false时执行产生最终boss{hoseplanevec.clear();             //清空所有敌人finplane.setgetunskillnumnum()++; //必杀次数+1Planehose hoseplane(4);                //BOSShoseplanevec.push_back(hoseplane);    //将BOSS插入进敌人数组中boossign = true;                    //只执行一次这段if代码}delay_fps(60);}OVER://游戏结束标签,用于击败BOSS后跳出多重循环delimage(gameback);                        //释放背景图片对象windefgame(state, finplane);          //游戏结束界面return 0;
}

不足之处:

游戏内容不是特别丰富,因为我懒的加,而且加的内容越多程序就越容易出问题。

因为程序中子弹结构数组是跟敌人是在一起的,所以当一个敌人被消灭后他发射出去的子弹也会消失,目前还没有比较好的解决办法。

我对内存管理掌握的不好,程序有可能存在一些其他问题。

另外子弹对飞机重合的判断我也是使用的非常简陋的方法,只判断一个中心点,这样写的话图片模型之间不真实,但是如果要多加几个判断实现比较完美的功能也没那个必要,毕竟效果都是差不多的。

欢迎大家提出批评和建议。


感谢大家的支持。

C++ 飞机大战小游戏 EGE相关推荐

  1. python 飞机大战小游戏

    飞机大战小游戏,这里需要下载pygame模块 这是需要的素材,需要的自取: 上代码: import time import pygame from pygame.locals import *#检测事 ...

  2. 点击list view中一行内容可以在combox中显示_java版飞机大战小游戏详细教程(零基础小白也可以分分钟学会!)...

    一:游戏展示 飞机大战小游戏我们都玩过,通过移动飞机来打敌机,这里给大家展示一下游戏成果:呜呜呜由于gif只能上传5M大小,所以就不能给大家展示操作了,如果大家有兴趣可以自己自己做出来再玩哟. 这里面 ...

  3. 飞机大战小游戏(超详细)

    偷学Python之最后的项目二:飞机大战小游戏(超详细) 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志.--苏轼 甜甜先说 这次用Python中的pygame模块来完成一个飞机大战的小游戏:基本思 ...

  4. matlab飞机大战小游戏(第二版)

    第一版链接:https://blog.csdn.net/slandarer/article/details/88025006 游戏截图: ------------------------ 游戏动图: ...

  5. 使用小程序制作一个飞机大战小游戏

    此文主要基于微信小程序制作一个飞机大战小游戏,上手即用,操作简单. 一.创建小程序 二.页面实现 三.代码块 一.创建小程序 访问微信公众平台,点击账号注册. 选择小程序,并在表单填写所需的各项信息进 ...

  6. C语言—飞机大战小游戏

    哈工大经典C语言大作业-飞机大战小游戏,源码如下,已经通过编译获得评分19+ (满分20)当时还是太菜了呜呜呜. 可以给大家参考一下,好像本来是加了音乐的,但是你们可能没有对应的音乐MP3文件,所以如 ...

  7. 基于Java语言在窗体上实现飞机大战小游戏

    全套资料下载地址:https://download.csdn.net/download/sheziqiong/85594271 项目介绍 飞机大战:用 Java 语言在窗体上实现飞机大战小游戏,运行程 ...

  8. 【Java代码实现飞机大战小游戏】简单理解

    飞机大战 飞机大战小游戏历经10天完成,主要用到的就是我们面向对象部分的知识:类,封装,继承,多态,静态代码块等等内容+swing部分内容.所以即使你是java小白,也不用担心欧! 游戏说明:游戏有3 ...

  9. 【Java】Java基础飞机大战小游戏完整代码

    Java基础飞机大战小游戏完整代码 先来展示一下代码实现结果图 主函数ShootGame 初始化游戏原始背景图片,游戏人物图片,游戏开始结束图片:构建产生敌人算法:产生英雄机算法:发射子弹算法:判断是 ...

最新文章

  1. Debian 7(Wheezy)下配置Open×××
  2. 布加迪、劳斯莱斯和宾利零售商开始接受BTC和BCH付款
  3. 11/100. Convert BST to Greater Tree
  4. html点击按钮执行php代码,php代码在html文件里面执行的示例
  5. Drools:基于PHREAK堆栈的评估和向后链接
  6. leetcode329. 矩阵中的最长递增路径
  7. JavaScript自学笔记(1)---表单验证,let和const,JSON文件
  8. 关于ASP访问ACCESS数据的错误80004005的解决方法
  9. jpg图片使用pil的resize后_刚毕业,求解“pdf转换为jpg”的操作教程
  10. 4个Shell小技巧,帮你提高机器学习生产效率
  11. javascript学习之数组的使用一 push pop shift unshift 方法
  12. allennlp train 参数
  13. 诺基亚手机: 诺基亚N9将在下月19日开卖 售价4400元
  14. python矢量图_使用python制作矢量图
  15. Java 版本6下载大全
  16. Linux下zip文件解压乱码
  17. 由内而外全面造就自己(七)
  18. Adjoin the Networks
  19. 网络爬虫-神器fiddler抓取app数据
  20. 关于大图片裁剪在华为等手机上无法使用问题

热门文章

  1. 智慧物业小程序_智慧物业员工APP业主APP小程序报事流程
  2. RoIPooling和RoIAlign
  3. Eureka设置账号密码
  4. 来自影视中的警言:What a lie is when we see it.
  5. Java 文本检索神器 “正则表达式”
  6. Linux操作系统管理
  7. 计算机一级死都过不了怎么办,手把手教你电脑假死怎么办
  8. HTTP Host header attacks Web安全系列(一)
  9. gateway网关服务的高级配置
  10. RedissonDistributedLock(redis分布式锁工具类,笔记)