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 - 1
int 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,子弹属性为1
temp.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: //小BOSS
attack = 680; break;
case 4: //最终BOSS
attack = 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: //最终BOSS
speed_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;
}