c++使用Easyx图形库是怎么实现飞机大战
发表于:2025-01-22 作者:千家信息网编辑
千家信息网最后更新 2025年01月22日,这期内容当中小编将会给大家带来有关c++使用Easyx图形库是怎么实现飞机大战,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。公共的头文件 common.h#prag
千家信息网最后更新 2025年01月22日c++使用Easyx图形库是怎么实现飞机大战
这期内容当中小编将会给大家带来有关c++使用Easyx图形库是怎么实现飞机大战,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
公共的头文件 common.h
#pragma once#include#include #include #include
管理资源 res.h --- 单例设计模式
#pragma once#include "common.h"class Res {private: Res(); //构造函数私有化public: //提供公有接口 static int WIDTH(string name); //通过图片的键,获取资源宽度 static int HEIGHT(string name); static Res* GetInstance(); //获取资源(类)的对象---唯一的对象 static void DrawIMG(int x, int y, string name);//画图片的位置,通过键去找画哪张图片//画角色---位置,通过姓名的方式去找 不同类型的角色,用preIndex去做标识 static void DrawRole(int x, int y, string name, int preIndex);//播放音乐---windows多线程 DWORD类型,WINAPI修饰 static DWORD WINAPI PlayMusic(LPVOID lparame); ~Res();public: static mapimg; //图片资源---图片存在map中 static map music; //音乐资源};
res.cpp
#include "res.h"mapRes::img; //图片资源 静态数据成员在类外初始化,类名限定map Res::music; //音乐资源Res::Res() //构造函数为数据成员初始化---路径下处理{//背景 string background = "./res/background.jpg";//角色---4张---背景图+掩码图 string roleImg[4] = { "./res/planeNormal_1.jpg","./res/planeNormal_2.jpg", "./res/planeExplode_1.jpg","./res/planeExplode_2.jpg" };//子弹 string ballImg[2] = { "./res/bullet1.jpg","./res/bullet2.jpg" };//敌机 string enemyImg[4] = { "./res/enemy_1.jpg","./res/enemy_2.jpg","./res/enemyPlane1.jpg","./res/enemyPlane2.jpg" }; //string --->IMAGE* 本来就是指针,不需要取地址 img["背景"] = new IMAGE; img["角色"] = new IMAGE[4]; img["子弹"] = new IMAGE[2]; img["敌机"] = new IMAGE[4]; loadimage(img["背景"], background.c_str()); //加载图片 路径 项目属性多字节 for (int i = 0; i < 4; i++) {/*假设img["角色"]为p,则p=new IMAGE [4];则img["角色"]+i 等效: p+i*/ loadimage(img["角色"] + i, roleImg[i].data()); //用.data或.cst()转换为字符串 loadimage(img["敌机"] + i, enemyImg[i].data()); } for (int i = 0; i < 2; i++) { loadimage(img["子弹"] + i, ballImg[i].c_str()); } }//获取图片的宽度---碰撞的时候需要---返回对象指针,对象指针调用(img类型)数据成员,有一个成员函数int Res::WIDTH(string name){//获取对象,获取什么样的属性,(img类型)数据成员有一个getwidth()成员函数---是库中的成员函数 return GetInstance()->img[name]->getwidth(); }//获取图片的高度int Res::HEIGHT(string name){ return GetInstance()->img[name]->getheight();}Res* Res::GetInstance(){ static Res* res = new Res; return res;}//只有一张图片的贴图: 背景图贴图void Res::DrawIMG(int x, int y, string name){ putimage(x, y, GetInstance()->img[name]); //贴图 在x,y位置贴对象里面的图片}void Res::DrawRole(int x, int y, string name, int preIndex){//多张图片贴图---透明贴图---去背景 putimage(x, y, GetInstance()->img[name] + preIndex, NOTSRCERASE);//贴第几张---帧数 putimage(x, y, GetInstance()->img[name] + preIndex+1, SRCINVERT);}DWORD __stdcall Res::PlayMusic(LPVOID lparame){ int key = (int)lparame; //线程处理函数的参数---强转为int switch (key) //不同的音乐,类型不一样 { case 1: mciSendString("close ./res/f_gun.mp3", 0, 0, 0); //播放前先关闭 mciSendString("open ./res/f_gun.mp3", 0, 0, 0); //先打开,后播放 mciSendString("play ./res/f_gun.mp3", 0, 0, 0); break; case 2: mciSendString("close ./res/5.mp3", 0, 0, 0); mciSendString("open ./res/5.mp3", 0, 0, 0); mciSendString("play ./res/5.mp3", 0, 0, 0); break; case 3: mciSendString("close ./res/10.mp3", 0, 0, 0); mciSendString("open ./res/10.mp3", 0, 0, 0); mciSendString("play ./res/10.mp3", 0, 0, 0); break; } return 0;}Res::~Res(){ delete img["背景"]; delete[] img["角色"]; delete[] img["敌机"]; delete[] img["子弹"];}
打飞机游戏.cpp 主函数部分
#include "control.h"#include "graph.h"#include "role.h"#include "enemy.h"int main() { srand((unsigned int)time(NULL)); //随机函数种子---位置不同 Graph* pMap = new Graph; Role* pRole = new Role; Enemy* pEnemy = new Enemy; Control* pControl = new Control(pMap, pRole, pEnemy); BeginBatchDraw(); //双缓冲绘图 while (1) { cleardevice(); //清屏 pControl->DrawMap(); //画地图 pControl->DrawRole(); //画角色 pControl->DrawEnemy();//打敌机前画敌机 pControl->PlayEemey(); FlushBatchDraw(); //显示 执行未完成的绘制任务 } EndBatchDraw(); return 0;}
point.h 无论是飞机移动还是子弹移动,本质都是坐标的改变 - - - 处理点的变化
#pragma once#include "common.h"class Point {public: enum Dir {left,right,down,up}; //枚举点移动的方向,不同的移动方向点的改变是不一样的 Point(int x = 0, int y = 0); Point(const Point& point); //拷贝构造---点与点之间的赋值 int& getX(); //外部接口,获取点的坐标 int& getY(); //移动点 void move(int speed, Dir dir); //移动速度 方向---决定坐标如何变化 protected: int x; int y;};/* 敌机从上往下移动 角色可以上下左右移动 s形敌机可以增加x方向增量,增加y方向增量 */
point.cpp
#include "point.h"Point::Point(int x, int y):x(x),y(y){}Point::Point(const Point& point){ this->x = point.x; this->y = point.y;}int& Point::getX(){ // TODO: 在此处插入 return 语句 return x;}int& Point::getY(){ // TODO: 在此处插入 return 语句 return y;}void Point::move(int speed, Dir dir) //根据方向移动{ switch (dir) { case Point::left: this->x -= speed; break; case Point::right: this->x += speed; break; case Point::up: this->y -= speed; break; case Point::down: this->y += speed; break; }}
element.h 敌机和飞机方向不同,其他基本相同 - - - 抽象元素类
#pragma once#include "common.h"#include "point.h"//所有的敌机和角色 都是由这个类进行派生的class Element {public: virtual ~Element(); //子类对象初始化父类指针 Element(); Element(int x, int y, string name, bool live, int hp = 0); int& GetX(); int& GetY(); bool& GetLive(); int& GetHp(); int GetWidth(); //获取宽度,高度 int GetHeight(); void DrawElement(int pre); //画元素---画第几张 void MoveElement(int speed, Point::Dir dir); //移动元素 protected: Point point; //元素在窗口上的位置 string name; //元素的名字 bool live; //存在的标记---敌机/子弹会消失 int hp; //血量};
element.cpp
#include "element.h"#include "res.h"int Element::GetWidth(){ return Res::GetInstance()->WIDTH(name);// return Res::GetInstance()->img[name]->getwidth(); 在类IMAGE中为公有属性}int Element::GetHeight(){ return Res::GetInstance()->HEIGHT(name);}//在资源文件中封装了移动过程,调用资源中的函数即可---画角色void Element::DrawElement(int pre){ Res::GetInstance()->DrawRole(point.getX(), point.getY(), name, pre);}//点的移动void Element::MoveElement(int speed, Point::Dir dir) { point.move(speed, dir);}Element::~Element(){}Element::Element(){ }//类的组合必须采用初始化参数列表Element::Element(int x, int y, string name, bool live, int hp):point(x,y),name(name){ this->live = live; this->hp = hp;}int& Element::GetX(){ // TODO: 在此处插入 return 语句 return point.getX(); //用point存放这个点,获取这个点应返回point里面的x坐标}int& Element::GetY(){ // TODO: 在此处插入 return 语句 return point.getY();}bool& Element::GetLive(){ // TODO: 在此处插入 return 语句 return live;}int& Element::GetHp(){ // TODO: 在此处插入 return 语句 return hp;}
role.h - - - 角色移动、角色发射子弹
#pragma once#include "common.h"class Element;class Role {public: Role(); ~Role(); void DrawPlane(int preIndex); //第几帧 void MovePlane(int speed); //速度 void DrawBullet(); //画子弹 void MoveBullet(int speed); //移动子弹---移动速度 Element*& GetPlane(); //外部做按键操作,需要访问飞机和子弹 list& GetBullet(); protected: Element* plane; //角色---用元素实例化一个角色---角色也是元素之一 list bullet; //子弹---一个飞机有多个子弹(包含多个元素的对象)子弹也是元素};
role.cpp
#include "role.h"#include "res.h"#include "element.h"#include "Timer.hpp"Role::Role() //new一个元素类即可---把飞机放窗口正中间{ plane = new Element( Res::GetInstance()->WIDTH("背景") / 2 - Res::GetInstance()->WIDTH("角色") / 2 //x , Res::GetInstance()->HEIGHT("背景") - Res::GetInstance()->HEIGHT("角色"), //y "角色", //name true, //live 100); //hp}Role::~Role(){ }void Role::DrawPlane(int preIndex) //画飞机{ plane->DrawElement(preIndex);}void Role::MovePlane(int speed) //移动飞机---结合按键控制 异步处理的按键操作{ if (GetAsyncKeyState(VK_UP) && plane->GetY() >= 0) //往上走Y不能超过上边界 { plane->MoveElement(speed, Point::up); //改变飞机的点---移动元素 } //往下走<=(背景高度-角色高度) if (GetAsyncKeyState(VK_DOWN) && plane->GetY()<=Res::GetInstance()->HEIGHT("背景")-Res::GetInstance()->HEIGHT("角色")) { plane->MoveElement(speed, Point::down); } //往右走<=(背景宽度-角色宽度) if (GetAsyncKeyState(VK_RIGHT) && plane->GetX() <= Res::GetInstance()->WIDTH("背景") - Res::GetInstance()->WIDTH("角色")) { plane->MoveElement(speed, Point::right); } //往左走X不能小于左边界 if (GetAsyncKeyState(VK_LEFT) && plane->GetX() >= 0) { plane->MoveElement(speed, Point::left); } //子弹产生---按空格发射子弹---用定时器控制速度---100毫秒产生1颗子弹 if (GetAsyncKeyState(VK_SPACE)&&MyTimer::Timer(100,0)) {//添加音乐 调用Windows中的创建线程函数---函数指针 传入线程处理函数---播放第一个音乐 HANDLE threadID = CreateThread(NULL, 0, Res::PlayMusic, (int*)1, 0, 0); bullet.push_back(new Element(plane->GetX() + 45, plane->GetY() - 10, "子弹", 1)); //尾插法 按一下空格new一个子弹 子弹的坐标在飞机坐标的正上方的中间 CloseHandle(threadID); //通过返回值关闭线程 } MoveBullet(1); //移动子弹 DrawBullet(); //画子弹 }void Role::DrawBullet() //子弹存在容器中,每颗子弹都要画出来{ for (auto v : bullet) //迭代器遍历 { if (v->GetLive()) //判断子弹能否画出来 { v->DrawElement(0); //序号0,子弹只有2张 } }}void Role::MoveBullet(int speed) //每颗子弹都要移动---从下往上走{ for (auto v : bullet) { v->GetY() -= speed; }}Element*& Role::GetPlane(){ // TODO: 在此处插入 return 语句 return plane;}list& Role::GetBullet(){ // TODO: 在此处插入 return 语句 return bullet;}//每产生一个子弹就播放音乐,返回值为HANDLE类型
control.h 控制整个游戏的运行 - - - 中驱
#pragma onceclass Graph;class Role;class Enemy;class Control {public: Control(Graph* pMap = nullptr, Role* pRole = nullptr,Enemy* pEnemy=nullptr); ~Control(); void DrawMap(); void DrawRole(); void DrawEnemy(); //画敌机 void PlayEemey(); //打敌机 protected: //所有组成部分 Role* pRole; //角色 Graph* pMap; //地图 Enemy* pEnemy; //敌机};
control.cpp - - - 封装实现细节 - - - 主函数中调用控制类对象即可
#include "control.h"#include "role.h"#include "graph.h" //地图#include "timer.hpp"#include "enemy.h"#include "element.h"#include "res.h" Control::Control(Graph* pMap, Role* pRole, Enemy* pEnemy ){ this->pMap = pMap; this->pRole = pRole; this->pEnemy = pEnemy;}Control::~Control(){ }void Control::DrawMap(){ pMap->DrawMap();} void Control::DrawRole(){ pRole->DrawPlane(0); //第0帧 pRole->MovePlane(1); //速度}//每一秒产生一个敌机(产生不能过于频繁)---产生一个敌机就把它放到容器中void Control::DrawEnemy(){ if (MyTimer::Timer(1000, 1)) { pEnemy->GetEnemy().push_back(pEnemy->createEnemy()); } if (MyTimer::Timer(10, 2)) //十毫秒移动一个飞机 2号定时器 { pEnemy->MoveEnemy(1); //速度 } pEnemy->DrawEnemy(0); //只画1种敌机} void Control::PlayEemey() //矩形与矩形的判断{ //1.碰撞处理: 碰到子弹,把子弹的live置为0---只处理标记 for (auto bullet : pRole->GetBullet()) //获取子弹的信息 { if (bullet->GetLive() == 0) //如果子弹标记==0继续往下找 continue; if (bullet->GetY() < 0) //如果超出窗口边界,把标记置为false bullet->GetLive() = false; for (auto enemy : pEnemy->GetEnemy()) //与子弹的碰撞处理 大前提---敌机存在 { if(enemy->GetLive()&& bullet->GetX()>enemy->GetX()&& bullet->GetX()GetX()+Res::WIDTH("敌机")&& bullet->GetY() > enemy->GetY() && bullet->GetY() < enemy->GetY() + Res::HEIGHT("敌机")) { enemy->GetHp()--; //相交,血量减少 if (enemy->GetHp() <= 0) { enemy->GetLive() = false; //把敌机标记置为false---不做消失处理 } bullet->GetLive() = false; //碰到敌机后子弹要消失 } //敌机出了窗口边界要消失 if (enemy->GetY() >= Res::HEIGHT("背景")) { enemy->GetLive() = false; } } } //2.通过标记去删除相应的数据--->内存管理 遍历敌机 for (auto iterE = pEnemy->GetEnemy().begin(); iterE != pEnemy->GetEnemy().end();) { if ((*iterE)->GetLive() == false) //当前敌机标记为false--->删除敌机 { iterE = pEnemy->GetEnemy().erase(iterE); } else { iterE++; //++不要写在for循环中 } }//遍历子弹---子弹删除 for (auto iterB = pRole->GetBullet().begin(); iterB != pRole->GetBullet().end();) { if ((*iterB)->GetLive() == false) { iterB = pRole->GetBullet().erase(iterB); } else { iterB++; } }}
graph.h - - - 地图(窗口类)
#pragma onceclass Graph {public: Graph(); ~Graph(); void DrawMap();};
graph.cpp
#include "graph.h"#include "res.h"Graph::Graph(){ initgraph(Res::GetInstance()->img["背景"]->getwidth(), Res::GetInstance()->img["背景"]->getheight()); mciSendString("open ./res/game_music.mp3", 0, 0, 0); //在窗口创建出来后添加音乐 mciSendString("play ./res/game_music.mp3 repeat", 0, 0, 0); //重复播放} Graph::~Graph(){ closegraph(); //对象没了就关闭窗口} void Graph::DrawMap(){ Res::DrawIMG(0, 0, "背景");}
time.hpp - - - 定义和实现写一起,用hpp做结尾 用时间控制子弹的发射 - - - 定时器
#pragma once#include "common.h"class MyTimer {public: static bool Timer(int duration, int id) //时间间隔 id { static int startTime[10]; //开始时间---静态变量自动初始化为0 int endTime = clock(); //结束时间 if (endTime - startTime[id] >= duration)//结束时间-开始时间>=时间间隔 { startTime[id] = endTime; //把原来的结束时间改为新的开始时间 return true; } return false; } };
enemy.h 敌机
#pragma once#include "common.h"class Element;class Enemy{public: Enemy(); ~Enemy(); void DrawEnemy(int preIndex); //画第几张 void MoveEnemy(int speed); Element* createEnemy(); //创建敌机 list& GetEnemy(); //访问敌机---需要做碰撞检测protected: list enemyPlane; //(存储)多个敌机};
enemy.cpp
#include "enemy.h"#include "element.h"#include "res.h"Enemy::Enemy(){ }Enemy::~Enemy(){ }void Enemy::DrawEnemy(int preIndex){ for (auto v : enemyPlane) //画元素 { if (v->GetLive()) //判断敌机是否存在 { v->DrawElement(preIndex); } }}void Enemy::MoveEnemy(int speed){ for (auto v : enemyPlane) { v->MoveElement(speed, Point::down); //速度 方向 }}Element* Enemy::createEnemy() //获取窗口宽高---随机x,y坐标 从窗口上边界出来 速度 血量{ return new Element(rand()%Res::GetInstance()->WIDTH("背景"), -1*Res::GetInstance()->HEIGHT("敌机"),"敌机",1, 3); }list& Enemy::GetEnemy(){ // TODO: 在此处插入 return 语句 return enemyPlane; //返回一个容器}
上述就是小编为大家分享的c++使用Easyx图形库是怎么实现飞机大战了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注行业资讯频道。
子弹
敌机
角色
移动
背景
飞机
元素
图片
函数
语句
资源
处理
方向
时间
速度
音乐
坐标
对象
标记
不同
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网络安全信息化标志
软件开发英语怎么学
安徽电商平台软件开发公司
数据库原理第三章作业答案
做软件开发公司 找聚顶科技在线
网络安全法从哪一年开始实行
网络技术分享公众号
网络安全不要转发
iis数据库权限配置文件
深圳软件开发张超
青岛公安局网络安全管理待遇如何
余姚盖促网络技术有限公司
网络安全大赛和射击手游的融合
网络安全明星代言
徐汇区口碑好的软件开发是真的吗
网络安全人人有责绘画作品
数据库中的事件怎么打开
华为网络技术之bgp配置
技术开放日数据库展板
数据库怎么分离
腾讯云原生数据库超出连接数
泉州网络安全特训营朝阳行业
唐山汇龙网络技术有限公司
服务器怎么知道是二级域名
三情数据库是哪三情
gt无法与服务器建立连接
北京软件开发服务单位
焦作东驰网络技术招聘
战舰少女r服务器如何删档
学生安全网络安全