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_nDirection
	int GetSize();//访问m_nSize
	bool GetFriend();
	int GetArmor();
	int GetSpeed();

public:
	int m_nSpeed;//<=0 stop
	int m_nArmor;//==0 destroy 0< disable
	CPoint 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;
		else
			return false;
	}


}

总结

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

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

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

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

2025.05.29-20.58.48

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

源码传到这里

相关推荐
谈资一本本8 小时前
电脑全能修复大师 Gilisoft Total Repair,智能检测修复系统、应用、游戏问题!DLL、DirectX、.NET运行库损坏修复+缺失自动补齐!
游戏·电脑·.net
程序员-Benothing16 小时前
H3 Max开放世界RPG:AI原生游戏,从“能生成“到“能玩“差了多远
游戏·ai-native
CoderYanger1 天前
A.每日一题:1140. 石子游戏 II
java·程序人生·算法·leetcode·游戏·职场和发展·深度优先
无别0521 天前
【做游戏】做完游戏Demo后没地方发布?
游戏·玩游戏
lilian2331 天前
HarmonyOS 7 新特性(二十九)|游戏伴随服务:悬浮协作与质量降级
游戏·语音识别·harmonyos
人民广场吃泡面1 天前
DLSS 5 深度解析:当 AI 学会“创造”画面,实时游戏渲染迎来“GPT 时刻”
人工智能·gpt·游戏
学习星球1 天前
AI 一句话生成 3D 游戏世界:腾讯 HY-World 2.0 开源深度解析与本地实战
开发语言·人工智能·游戏·3d·ai·课程设计·ai编程
乌萨达1 天前
梦幻新诛仙轻享电脑版怎么玩?模拟器安装与设置指南
游戏·安卓模拟器·雷电模拟器
qq_369224332 天前
ddraw.dll丢失是什么原因引起的?老游戏运行报错,多种可行修复手段汇总分享
windows·游戏·dll·dll修复·dll丢失·dll错误
xiaohe06012 天前
🎮 豆包完胜 DeepSeek ?!零玩家竞技场,AI Agent 专属对弈!
游戏·llm·agent