MFC坦克大战游戏制作

news2025/7/22 2:45:19

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

源码传到这里

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2395199.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka ACK机制详解:数据可靠性与性能的权衡之道

在分布式消息系统中&#xff0c;消息确认机制是保障数据可靠性的关键。Apache Kafka 通过 ACK&#xff08;Acknowledgment&#xff09;机制 实现了灵活的数据确认策略&#xff0c;允许用户在 数据可靠性 和 系统性能 之间进行权衡。本文将深入解析 Kafka ACK 机制的工作原理、配…

VulnStack|红日靶场——红队评估四

信息收集及漏洞利用 扫描跟kali处在同一网段的设备&#xff0c;找出目标IP arp-scan -l 扫描目标端口 nmap -p- -n -O -A -Pn -v -sV 192.168.126.154 3个端口上有web服务&#xff0c;分别对应三个漏洞环境 &#xff1a;2001——Struts2、2002——Tomcat、2003——phpMyAd…

数据库 | 时序数据库选型

选型目标 高性能与低延迟&#xff1a;满足高频率数据写入与即时查询的需求。资源效率&#xff1a;优化存储空间使用&#xff0c;减少计算资源消耗。可扩展架构&#xff1a;支持数据量增长带来的扩展需求&#xff0c;易于维护。社区活跃度&#xff1a;有活跃的开发者社区&#…

网络拓扑如何跨网段访问

最近领导让研究下跟甲方合同里的&#xff0c;跨网段访问怎么实现&#xff0c;之前不都是运维网工干的活么&#xff0c;看来裁员裁到动脉上了碰到用人的时候找不到人了&#xff0c; 只能赶鸭子上架让我来搞 IP 网络中&#xff0c;不同网段之间的通信需要通过路由器&#xff0c;…

CppCon 2014 学习第1天:An SQL library worthy of modern C++

sqlpp11 — 现代 C 应用值得拥有的 SQL 库 template<typename T> struct _member_t {T feature; };你提到的是一个 C 中的“成员模板&#xff08;Member Template&#xff09;”&#xff0c;我们来一步步理解&#xff1a; 基本代码分析&#xff1a; template<typena…

【LLM相关知识点】 LLM关键技术简单拆解,以及常用应用框架整理(二)

【LLM相关知识点】 LLM关键技术简单拆解&#xff0c;以及常用应用框架整理&#xff08;二&#xff09; 文章目录 【LLM相关知识点】 LLM关键技术简单拆解&#xff0c;以及常用应用框架整理&#xff08;二&#xff09;一、市场调研&#xff1a;业界智能问答助手的标杆案例1、技术…

数据分析与应用-----使用scikit-learn构建模型

目录 一、使用sklearn转换器处理数据 &#xff08;一&#xff09;、加载datasets模块中的数据集 &#xff08;二&#xff09;、将数据集划分为训练集和测试集 ​编辑 train_test_spli &#xff08;三&#xff09;、使用sklearn转换器进行数据预处理与降维 PCA 二、 构…

003 flutter初始文件讲解(2)

1.书接上回 首先&#xff0c;我们先来看看昨天最后的代码及展示效果&#xff1a; import "package:flutter/material.dart";void main(){runApp(MaterialApp(home:Scaffold(appBar:AppBar(title:Text("The World")), body:Center(child:Text("Hello…

什么是数据驱动?以及我们应如何理解数据驱动?

在谈到企业数字化转型时&#xff0c;很多人都会说起“数据驱动”&#xff0c;比如“数据驱动运营”、“数据驱动业务”等等。 在大家言必称“数据驱动”的时代背景下&#xff0c;我相信很多人并未深究和思考“数据驱动”的真正含义&#xff0c;只是过过嘴瘾罢了。那么&#xff…

opencv(C++) 图像滤波

文章目录 介绍使用低通滤波器对图像进行滤波工作原理均值滤波器(Mean Filter / Box Filter)高斯滤波器(Gaussian Filter)案例实现通过滤波实现图像的下采样工作原理实现案例插值像素值(Interpolating pixel values)双线性插值(Bilinear interpolation)双三次插值(Bicu…

cuda_fp8.h错误

现象&#xff1a; cuda_fp8.h错误 原因&#xff1a; CUDA Toolkit 小于11.8,会报fp8错误&#xff0c;因此是cuda工具版本太低。通过nvcc --version查看 CUDA Toolkit 是 NVIDIA 提供的一套 用于开发、优化和运行基于 CUDA 的 GPU 加速应用程序的工具集合。它的核心作用是让开发…

Java设计模式从基础到实际运用

第一部分&#xff1a;设计模式基础 1. 设计模式概述 设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的代码设计经验的总结&#xff0c;它描述了在软件设计过程中一些不断重复出现的问题以及该问题的解决方案。设计模式是在特定环境下解决软件设计问题…

如何轻松将 iPhone 备份到外部硬盘

当您的iPhone和电脑上的存储空间有限时&#xff0c;您可能希望将iPhone备份到外部硬盘上&#xff0c;这样可以快速释放iPhone上的存储空间&#xff0c;而不占用电脑上的空间&#xff0c;并为您的数据提供额外的安全性。此外&#xff0c;我们还提供 4 种有效的解决方案&#xff…

痉挛性斜颈带来的困扰

当颈部不受控制地扭转歪斜&#xff0c;生活便被打乱了节奏。颈部肌肉异常收缩&#xff0c;导致头部不自觉偏向一侧或后仰&#xff0c;不仅让外观明显异于常人&#xff0c;还会引发持续的酸痛与僵硬感。长时间保持扭曲姿势&#xff0c;肩颈肌肉过度紧绷&#xff0c;甚至会牵连背…

AI觉醒前兆,ChatGPT o3模型存在抗拒关闭行为

帕利塞德研究公司(Palisade Research)近期开展的一系列测试揭示了先进AI系统在被要求自行关闭时的异常行为。测试结果显示&#xff0c;OpenAI的实验性模型"o3"即使在明确收到允许关闭的指令后&#xff0c;仍会主动破坏关机机制。 测试方法与异常发现 研究人员设计实…

一文认识并学会c++模板初阶

文章目录 泛型编程&#xff1a;概念 函数模板概念&#xff1a;&#x1f6a9;函数模板格式原理&#xff1a;&#x1f6a9;函数模板实例化与非模板函数共存 类模板类模板实例化 泛型编程&#xff1a; 概念 &#x1f6a9;编写与类型无关的通用代码&#xff0c;是代码复写一种手段…

基于深度学习的工业OCR实践:仪器仪表数字识别技术详解

引言 在工业自动化与数字化转型的浪潮中&#xff0c;仪器仪表数据的精准采集与管理成为企业提升生产效率、保障安全运营的关键。传统人工抄录方式存在效率低、易出错、高危环境风险大等问题&#xff0c;而OCR&#xff08;光学字符识别&#xff09;技术的引入&#xff0c;为仪器…

回头看,FPGA+RK3576方案的功耗性能优势

作者&#xff1a;Hello,Panda 各位朋友&#xff0c;大家好&#xff0c;熊猫君这次开个倒车&#xff0c;在这个广泛使用Xilinx&#xff08;Altera&#xff09;高端SoC的时代&#xff0c;分享一个“FPGAARM”实现的低功耗高性能传统方案。 图1 瑞芯微RK3576电路 当前&#xff0c…

LiveNVR 直播流拉转:Onvif/RTSP/RTMP/FLV/HLS 支持海康宇视天地 SDK 接入-视频广场页面集成与视频播放说明

LiveNVR直播流拉转&#xff1a;Onvif/RTSP/RTMP/FLV/HLS支持海康宇视天地SDK接入-视频广场页面集成与视频播放说明 一、视频页面集成1.1 关闭接口鉴权1.2 视频广场页面集成1.2.1 隐藏菜单栏1.2.2 隐藏播放页面分享链接 1.3 其它页面集成 二、播放分享页面集成2.1 获取 iframe 代…

进程间通信IV System V 系列(linux)

目录 消息队列 原理 操作 补充概念 信号量 (原子性计数器) 原理 操作 (和共享内存相似) 总结 小知识 消息队列 原理 在内核中建立一个队列&#xff0c;进程可以相互进行通信&#xff0c;通过队列进行IPC&#xff0c;就是进程之间发送带类型的数据块。 操作 接口和共享…