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文库

源码传到这里

相关推荐
aa324224324318 小时前
Scratch节日 | 六一儿童节抓糖果
学习·游戏·青少年编程·节日
SuperHeroWu71 天前
【HarmonyOS 5】Laya游戏如何鸿蒙构建发布详解
游戏·华为·harmonyos·laya·鸿蒙构建
是你呀1 天前
如何用鸿蒙Harmony OS 5实现 羊了个羊 小游戏
前端·游戏
AgilityBaby1 天前
UE5蓝图暴露变量,在游戏运行时修改变量实时变化、看向目标跟随目标Find Look at Rotation、修改玩家自身弹簧臂
笔记·游戏·ue5·游戏引擎·蓝图
lizz6662 天前
MAC软件游戏打开提示已损坏
游戏·macos
哥谭市情歌王2 天前
嵌入式编译工具链熟悉与游戏移植
游戏
Swift社区2 天前
AI 的早期萌芽?用 Swift 演绎约翰·康威的「生命游戏」
游戏·蓝桥杯·swift
一大Cpp2 天前
Ubuntu下编译mininim游戏全攻略
linux·ubuntu·游戏
Kim Jackson2 天前
我的世界Java版1.21.4的Fabric模组开发教程(十一)创建方块
java·游戏·fabric