zoukankan      html  css  js  c++  java
  • SDUST 小学期飞机大战简述

    2020-07-28

    • 版权声明:原创文章,未经博主允许不得转载

    这章主要描述下飞机大战的整体架构。这章开始,内容将基于我的 V2.0.0

    大体的认识

    这里所阐述的过程是通用的,是和老师提供的模板程序一样的,但是代码会有些许不同。

    产生一个MFC窗口很容易,先从CWinApp派生一个应用程序类,然后再从这个应用程序类建立应用程序对象(theApp)。两个过程可以容易地在源码中找到:

    /*PlaneGame.h line16*/
    class CPlaneGameApp : public CWinApp
    {
    public:
    	CPlaneGameApp();
    
    // 重写
    public:
    	virtual BOOL InitInstance();
    
    // 实现
    	afx_msg void OnAppAbout();
    	DECLARE_MESSAGE_MAP()
    	afx_msg void OnHowto();
    	afx_msg void OnScore();
    };
    
    
    /*PlaneGame.cpp line67*/
    CPlaneGameApp theApp;
    

    随后从CView派生CPlaneGameView,并调用OnInitialUpdate()方法:

    /*PlaneGameView.cpp line125*/
    void CPlaneGameView::OnInitialUpdate()
    {
    	CView::OnInitialUpdate();
    	// TODO: 在此添加专用代码和/或调用基类
    	//初始化游戏
    	InitGame();
    }
    

    可以看到,我们在这里调用了 InitGame() 函数。你会发现正是这个函数,创建了很多游戏所需的对象,并启动了游戏。

    MFC程序是由事件驱动的。当一个事件产生,程序将调用相对应的事件处理函数;而没有事件产生时,它将不会做任何额外的事情。我们知道,飞机大战需要不断自动移动飞机和子弹,也就是说我们需要不断产生一个事件,使画面刷新、对象移动。所以我们需要启动一个定时器,不断产生一个 WM_TIMER 事件,并使它不断调用 OnTimer()函数。

    /*PlaneGameView.cpp line795*/
    //它本来在InitGame()中,需要实现其他功能而移动了位置
    SetTimer(1, 30, NULL);
    
    /*PlaneGameView.cpp line710*/
    void CPlaneGameView::OnTimer(UINT_PTR nIDEvent)
    {
    	//刷新游戏帧画面: 在内存DC上绘图
    	UpdateFrame(m_pMemDC);
    	AI();
    
    	CView::OnTimer(nIDEvent);
    }
    

    UpdateFrame() 用于刷新图像,而 AI() 用于响应键盘事件和处理各种乱七八糟的事情。整个程序在定时器的作用下不断重复调用这两个函数,使整个游戏运行起来,直到游戏结束,程序被退出。退出时会产生 WM_DESTROY 事件,并调用 OnDestry() 函数:

    /*PlaneGameView.cpp line719*/
    void CPlaneGameView::OnDestroy()
    {
    	CView::OnDestroy();
    	this->StopGame();
    	// TODO: 在此处添加消息处理程序代码
    }
    
    /*PlaneGameView.cpp line132*/
    void CPlaneGameView::StopGame()
    {
    	delete m_pMe;
    	delete m_pFriend;
    	delete m_pMemDC;
    	delete m_pDC;
    	delete m_pMemBitmap;
    }
    

    InitGame() 函数中被创建的对象都将在 StopGame() 函数中被释放。这里需要注意的是, delete 一个空指针并不会产生错误。通读程序后可以发现, m_pMe 和 m_pFriend 大部分时候都被 delete 了两遍,因此在第一次 delete 时,我们需要将它置为 NULL ,否则会成为野指针并在第二次 delete 时产生段错误。

    几点不同

    由于我的修改,整个程序的运行和老师提供的模板程序有几点不同。

    • OnCreate() 函数

    为了在游戏开始之前有一个界面,供玩家选择模式,我为 WM_CREATE 事件添加了事件处理函数。这主要是指导程序产生窗口用的,动态创建了按钮。代码比较长便不全粘贴:

    /*PlaneGameView.cpp line726*/
    int CPlaneGameView::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {...}
    

    通过消息映射(作用是将各个控件产生的事件和与之对应的消息处理函数绑定),映射到 OnButtonClick() 函数,对不同的模式初始化一些变量,并释放这些不再需要的按钮:

    /*PlaneGameView.cpp line751*/
    void CPlaneGameView::OnButtonClick(UINT uID)
    {
    	switch (uID) {
    	case ...: {
    		...
    	}
    	default:
    		break;
    	}
    
    	//启动游戏
    	SetTimer(1, 30, NULL);
    
    	delete button1;
    	delete button2;
    	delete button3;
    	delete button4;
    	button1 = button2 = button3 = button4 = NULL;
    }
    

    容易发现,我是在按钮被按下后再启动游戏的。

    • pauseGame() 函数

    我们能启动一个定时器,当然也能停止一个计时器。 KillTimer() 就是用来停止一个计时器。 SetTimer(1, 30, NULL); 中,第一个参数是定时器的标识,我们用 KillTimer(<标识>) 即可停止这个计时器:

    /*PlaneGameView.cpp line804*/
    void CPlaneGameView::pauseGame()
    {
    	KillTimer(1);
    	CPauseDlg pauseDlg;
    	pauseDlg.DoModal();
    }
    

    pauseDlg 是一个对话框,提示游戏已经暂停是否继续。这里需要注意的是, SetTimer() 并不是任何地方都可以调用的,它更像是 CPlaneGameView 的一个方法。所以我在某个合适的时候存储了 CView 对象的指针,通过指针来调用 SetTimer() 以实现游戏的继续。

    本章完

    by SDUST weilinfox

    本文地址 https://www.cnblogs.com/weilinfox/p/13390862.html

    前章 https://www.cnblogs.com/weilinfox/p/13229805.html

    续章 https://www.cnblogs.com/weilinfox/p/13391352.html

  • 相关阅读:
    Python3+Selenium3自动化测试-(四)
    Python3+Selenium3自动化测试-(三)
    Python3+Selenium3自动化测试-(二)
    Python3+Selenium3自动化测试-(一)
    Python3+Selenium3自动化测试-(准备)
    mysql报错MySQLSyntaxErrorException: Specified key was too long; max key length is 767 byte
    C# 基础Array
    c# 基础之方法
    c#之初识结构(Struct)
    c# 之Enum--枚举
  • 原文地址:https://www.cnblogs.com/weilinfox/p/13390862.html
Copyright © 2011-2022 走看看