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指针
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());
}
//敌方坦克与墙碰撞
//敌方坦克与我方坦克碰撞
//敌方坦克与敌方坦克碰撞
}
总结
游戏视频如下,简陋了点,但是能用
2025.05.29-20.58.48
源码传到这里