当前位置: 首页 > article >正文

MFC坦克大战游戏制作

MFC坦克大战游戏制作


前言

现在的游戏制作一般是easyx,有没有直接只用mfc框架的,笔者研究了一番,做出了一个雏形,下面把遇到的问题总结出来


一、MFC框架制作游戏

初步设想,MFC可以选用 对话框 或者 单文档 结构,我们在上面画图,可以使用png的图片,这样保证能透明,然后使用鼠标和键盘操作 人物移动和子弹飞出,加上背景音乐,积分规则等等,就能制作出一份游戏来。这是游戏界面

二、遇到的技术难点

1.内存画图解决闪烁问题

MFC画图最麻烦的就是,闪烁问题,所以要尽量内存画图,然后一次性的输出。所有需要重绘的地方,使用 Invalidate(FALSE); 能保证最小程度上的闪烁

核心代码

      CPaintDC dc(this);CDC memDC;memDC.CreateCompatibleDC(&dc);CBitmap bmp;GetClientRect(&m_client);bmp.CreateCompatibleBitmap(&dc, m_client.Width(), m_client.Height());CBitmap* pOldBitmap = memDC.SelectObject(&bmp);CDC* pDC = &memDC;// 绘制到内存 DC//m_bg.Draw(memDC, m_client);//m_hero.Draw(memDC, m_heroPos);// 绘制背景pDC->FillSolidRect(m_client, RGB(0, 120, 0));  // 或用背景刷填充

注意看pDC是一个内存画图的memDC指针 

在需要画图的地方,pDC 是传递过来的 memeDC指针

	CRect rctTank(m_ptPos.x, m_ptPos.y, m_ptPos.x + 2*m_nSize, m_ptPos.y + 2*m_nSize);CImage* pImg = nullptr;pImg = m_img;pImg->Draw(pDC->GetSafeHdc(), rctTank);

 等内存画完图

      // 一次性拷贝到屏幕dc.BitBlt(0, 0, m_client.Width(), m_client.Height(), &memDC, 0, 0, SRCCOPY);//清理资源memDC.SelectObject(pOldBitmap);bmp.DeleteObject();

2.设定timer保持界面更新

设置了三个timer,一个界面更新,二是判断是否碰撞(包括坦克、地方坦克、子弹之间的碰撞)

	int nTimerID1 = 1;int nTimerID2 = 2;int nTimerID3 = 3;SetTimer(nTimerID1, 4, NULL);//一号定时器,4ms,全体发送 增加SetTimer(nTimerID2, 2, NULL);//判断是否重叠(相撞)SetTimer(nTimerID3, 2000, NULL);//自动开火

 第三个是 让地方坦克自己运动、开火

switch (nIDEvent)
{
case 1:Invalidate(FALSE);break;
case 2://碰撞测试
{m_mtxJudgy.try_lock();std::thread Overlay(Judgy, this);Overlay.detach();m_mtxJudgy.unlock();
}
break;
case 3://自动开火
{

3.设计合适母类解决互动问题

我方坦克、地方坦克、子弹、都从一个母类派生来,母类的一些方法如下:

class MyObject
{
public:MyObject() { m_nSize = 32; };~MyObject() {};void Draw(CDC* pDC);void Move(int nDirection) {};//设置运动方向or方向bool IsOverlap(MyObject& obj);//判断两个物体是否碰撞bool IsFriend(MyObject& OBJ);void SetSize(int nSize);//设置外形尺寸void SetDirection(int nDir);void SetFriend(bool bFriend);void SetArmor(int nArmor);void SetSpeed(int nSpeed);int GetDirection();//访问m_nDirectionint GetSize();//访问m_nSizebool GetFriend();int GetArmor();int GetSpeed();public:int m_nSpeed;//<=0 stopint m_nArmor;//==0 destroy 0< disableCPoint m_ptPos;//当前坐标
protected:bool m_bFriend;int m_nSize;//外形范围int m_nDirection;//1234 上下左右 方向
};

4.多线程解决 子弹、坦克相遇问题

把判断每个物体之间的相遇都写到进程里面,可以使得游戏流畅,因为子弹不停地在飞,不能为了两个物体的碰撞就卡住其他进程

		m_mtxJudgy.try_lock();std::thread Overlay(Judgy, this);Overlay.detach();m_mtxJudgy.unlock();

判断的种类很多,有: 

//敌方坦克与墙壁、我方坦克、敌方坦克的碰撞测试及自动追踪我方坦克
for (i = 0; i < vecEnemyTank.size(); i++)
{//自动追踪if (!vecEnemyTank[i].m_nArmor)continue;vecEnemyTank[i].pre_pt = vecEnemyTank[i].m_ptPos;if (end != false){vecEnemyTank[i].ChangeDirection(MyTank);if (vecEnemyTank[i].m_dDis <= 1000)vecEnemyTank[i].Move(vecEnemyTank[i].GetDirection());}//敌方坦克与墙碰撞//敌方坦克与我方坦克碰撞//敌方坦克与敌方坦克碰撞}

碰撞就是几何学上判断是否相交

我这里处理简单了些,如果是方形物体【坦克,地方坦克,墙】这些相交,因为是正方形的相交,所有需要用ABBA判断一下,但其他物体,比如其中有个圆(炮弹),炮弹和墙,或者炮弹和坦克,敌我之间的炮弹判断就直接用圆来粗略的来算了。

bool MyObject::IsOverlap(MyObject& obj)
{// 情况1:双方都是正方形if ((GetSize() == 32) && (obj.GetSize() == 32)){// 获取两个矩形的边界double left1 = m_ptPos.x;double right1 = m_ptPos.x + 2 * m_nSize;double top1 = m_ptPos.y;double bottom1 = m_ptPos.y + 2 * m_nSize;double left2 = obj.m_ptPos.x;double right2 = obj.m_ptPos.x + 2 * obj.GetSize();double top2 = obj.m_ptPos.y;double bottom2 = obj.m_ptPos.y + 2 * obj.GetSize();// AABB碰撞检测if (left1 > right2 || left2 > right1 ||top1 > bottom2 || top2 > bottom1) {return false;}return true;}// 情况2:其他各种情况都粗略搞成两个圆心else{double dx = m_ptPos.x - obj.m_ptPos.x;double dy = m_ptPos.y - obj.m_ptPos.y;double dDis = sqrt(dx * dx + dy * dy);if (obj.GetSize() + m_nSize >= dDis)return true;elsereturn false;}}

总结

1、给坦克设定一定的Armor,也就是血,受到子弹的撞击就减一,Armor减完就死了

2、给四周的墙体设定的Armor是999,所以是打不透的,给中间的障碍设定的是1,打完就没了

3、子弹的速度和伤害可以改,在界面最上面的button里面

游戏视频如下,简陋了点,但是能用

2025.05.29-20.58.48

MFC坦克大战源码没有用任何第三方库资源-CSDN文库

源码传到这里

http://www.lryc.cn/news/2395199.html

相关文章:

  • Kafka ACK机制详解:数据可靠性与性能的权衡之道
  • VulnStack|红日靶场——红队评估四
  • 数据库 | 时序数据库选型
  • 网络拓扑如何跨网段访问
  • CppCon 2014 学习第1天:An SQL library worthy of modern C++
  • 【LLM相关知识点】 LLM关键技术简单拆解,以及常用应用框架整理(二)
  • 数据分析与应用-----使用scikit-learn构建模型
  • 003 flutter初始文件讲解(2)
  • Windows系统下 NVM 安装 Node.js 及版本切换实战指南
  • 基于热力学熵增原理的EM-GAM
  • 2025.05.28-华为暑期实习第一题-100分
  • 鸿蒙OSUniApp滑动锁屏实战:打造流畅优雅的移动端解锁体验#三方框架 #Uniapp
  • 数据库中 用一个值实现类似linux中的读 写执行以及理解安卓杂用的按位或运算
  • 什么是数据驱动?以及我们应如何理解数据驱动?
  • opencv(C++) 图像滤波
  • 【线上故障排查】缓存热点Key导致Redis性能下降的排查与优化(面试题 + 3 步追问应对 + 案例分析)
  • cuda_fp8.h错误
  • Java设计模式从基础到实际运用
  • 网络安全基础--第九天
  • 鸿蒙如何引入crypto-js
  • 通过HIVE SQL获取每个用户的最大连续登录时常
  • 如何轻松将 iPhone 备份到外部硬盘
  • Matlab数据类型
  • 痉挛性斜颈带来的困扰
  • AI觉醒前兆,ChatGPT o3模型存在抗拒关闭行为
  • Flask项目进管理后台之后自动跳回登录页面,后台接口报错422,权限问题
  • HarmonyOS如何优化鸿蒙Uniapp的性能?
  • 使用逆强化学习对网络攻击者的行为偏好进行建模
  • 青少年编程与数学 02-020 C#程序设计基础 12课题、使用控件
  • 一文认识并学会c++模板初阶