cocos 框架之-Cocos2d-x 的“HelloWorld” 细节分析

来源:互联网 发布:手机宽带拨号软件 编辑:程序博客网 时间:2024/06/05 16:03

打开 HelloWorld 工程 , 里面有两个文件目录 Classes 和 win32 。 

Classes 下有 HelloWorldScene.h/cpp ,AppDelegate.h/cpp. 

win32 下有 main.h/cpp 

首先看一下 win32 目录下的 main.h, 其中定义了使用 win32 平台进行编译的宏和一些 Windows 编程头文件。 

 

#ifndef __MAIN_H__

#define __MAIN_H__

//定义使用WIN32平台进行编译的宏

#define WIN32_LEAN_AND_MEAN            

// 所用到的Windows编程所用头文件

#include <windows.h>

#include <tchar.h>

// CocosC语言头文件

#include "CCStdC.h"

#endif // __MAIN_H__

 

再打开 main.cpp. 

 

//加入main.h头文件

#include "main.h"

//加入使用的AppDelegate类头文件

#include "../Classes/AppDelegate.h"

//WinMain主函数

int APIENTRY _tWinMain(HINSTANCE hInstance,

   HINSTANCE hPrevInstance,

   LPTSTR    lpCmdLine,

   int       nCmdShow)

{

   //UNREFERENCED_PARAMETER用于在VC编译器下告知编译器,不必检测改变量是 否使用的警告。

   UNREFERENCED_PARAMETER(hPrevInstance);

   UNREFERENCED_PARAMETER(lpCmdLine);

   // 创建一个Cocos2d-x程序实例

AppDelegate app;

   // 运行程序实例

   return cocos2d::CCApplication::sharedApplication().run();

}


 

代码看着就这么几行,好像非常简单。那是因为 Cocos2d-x 把很多 WINDOWS 窗口程序的代码都封装到了内部。这也使得它更加简单易学。但我们也应该明白这里面是怎么一回事。 

             

咱们转到AppDelegate.h ,可以看到 AppDelegate 类是一个私有继承 Cocos2d 命名空间中的 CCApplication 类。它的成员函数均是重载了 CCApplication 类的成员函数。顾名思义, CCApplication 代表了程序类。我们打开它的声明文件(CCApplication_win32.h)看一下: 

 

#ifndef __CC_APPLICATION_WIN32_H__

#define __CC_APPLICATION_WIN32_H__

//Windows头文件

#include <Windows.h> 

//Cocos2d-x公共头文件,声明了一些公共函数以及语言类型枚举ccLanguageType

#include "CCCommon.h"

//使用cocos2d的命名空间来包括后面的代码

NS_CC_BEGIN;

//声明一下CCRect类,在CCApplication中会用到CCRect类指针

class CCRect;

class CC_DLL CCApplication

{

public:

//构造

CCApplication();

    //析构

    virtual ~CCApplication();

    //初始化

    virtual bool initInstance() = 0;

//程序启动后调用的函数,在这里创建设备与场景

    virtual bool applicationDidFinishLaunching() = 0;

//当程序转入后台,如电话打入时调用

    virtual void applicationDidEnterBackground() = 0;

//当程序转入前台,再次恢复时调用

    virtual void applicationWillEnterForeground() = 0;

//设备设置FPS时调用的函数,设置帧间隔时间

void setAnimationInterval(double interval);

//声明一个枚举,列出当前设备的摆放方向

    typedef enum

    {

        /// 垂直方向, home 键在下面

        kOrientationPortrait = 0,

        /// 垂直方向, home 键在上面

        kOrientationPortraitUpsideDown = 1,

        /// 水平方向,home键在右边

        kOrientationLandscapeLeft = 2,

        /// 水平方向,home健在左边

        kOrientationLandscapeRight = 3,

    } Orientation;

    

 

//设备改变了摆放方向后调用的函数,设置设备摆放方向

    Orientation setOrientation(Orientation orientation);

//取得窗口的状态栏所在的矩形位置

    void    statusBarFrame(CCRect * rect);

    //运行程序

    int run();

//取得当前的程序实例,这种用法可参考C++模式设计中的单件模式

    static CCApplication& sharedApplication();

//取得当前的语言类型

    static ccLanguageType getCurrentLanguage();

protected:

//程序实例句柄

HINSTANCE           m_hInstance;

//加速键句柄

HACCEL              m_hAccelTable;

//声明为帧间隔,实际上是每两帧之间的频率次数

    LARGE_INTEGER       m_nAnimationInterval;

//单件的程序实例指针

    static CCApplication * sm_pSharedApplication;

};

NS_CC_END;

#endif// __CC_APPLICATION_WIN32_H__


通过对于 CCApplication_win32.h 的代码分析,我们可以清楚 CCApplication 的功能是对于程序的控制。 

我们转到 CCApplication 类的 cpp 文件 CCApplication_win32.cpp 再来分析一下。 

读前小提示 :  

CCDirector 代表显示设备管理器。也是一个单件类。通过其静态函数 CCDirector::sharedDirector() 来访问唯一的显示设备。 

         

重点关注函数:CCApplication(), run() 。 (在CCApplication_win32.cpp)

 

#include "CCApplication.h"

//设备头文件

#include "CCDirector.h"

//在注册表中写入对于PVRFrame的显示和隐藏的设置

static void PVRFrameEnableControlWindow(bool bEnable);

//使用cocos2d的命名空间来包括后面的代码

NS_CC_BEGIN;

// CCApplication的静态成员指针变量单件对象指针

CCApplication * CCApplication::sm_pSharedApplication = 0;

//构造函数

CCApplication::CCApplication()

: m_hInstance(NULL)

, m_hAccelTable(NULL)

{

//获取当前程序句柄

m_hInstance= GetModuleHandle(NULL);

//初始化

m_nAnimationIntervalm_nAnimationInterval.QuadPart = 0;

//断言程序中只有一个sm_pSharedApplication。确保当前类只有一个实例对象

CC_ASSERT(! sm_pSharedApplication);

//设置单件对象指针指向当前类对象实例    

sm_pSharedApplication = this;

}

//析构

CCApplication::~CCApplication()

{

//断言程序只有一个sm_pSharedApplication就是指向当前类的实例对象    

CC_ASSERT(this == sm_pSharedApplication);    

sm_pSharedApplication = NULL;

}

//程序运行

int CCApplication::run()

{    

//设置注册表PVRFrame隐藏    

PVRFrameEnableControlWindow(false);    

//主消息循环    

MSG msg;    

LARGE_INTEGER nFreq;    

LARGE_INTEGER nLast;    

LARGE_INTEGER nNow;

//WINDOWS高精度定时器的用法,先获取频率

QueryPerformanceFrequency(&nFreq);

//获取当前的计数值,即频率x当前时间    

QueryPerformanceCounter(&nLast);

//initInstance函数为虚函数,由派生类AppDelegate进行了重载。此段代码在调用

    AppDelegate重载的initInstance函数之后调用applicationDidFinishLaunching函数完成一

    些初始化处理。

    //:AppDelegate重载initInstance函数做了什么我们暂且只先认为它如平时我们

    WINDOWS基本框架程序一样创建了一个Windows窗口。【伏笔1后面会有讲解】。    

if (! initInstance() || ! applicationDidFinishLaunching())    

{        

return 0;    

}

//取得当前使用的OPENGL窗口管理实例对象

CCEGLView& mainWnd = CCEGLView::sharedOpenGLView();

//将窗口居中显示    

mainWnd.centerWindow();    

ShowWindow(mainWnd.getHWnd(), SW_SHOW);

//非常熟悉!进入WINDOWS消息循环    

while (1)

{   

//如果没有获取到WINDOWS消息        

if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))        

{            

// 取得当前的计数值,即频率x当前时间            

QueryPerformanceCounter(&nNow);            

            //m_nAnimationInterval.QuadPart的值 为setAnimationInterval函数进行设置的     

            固定值。此处是为了判断时间流逝了多久,是否应该更新显示设备            

if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)            

{  

//如果时间流逝达到了设定的FPS时间差,则更新计数值。                

nLast.QuadPart = nNow.QuadPart;  

//这里是设备渲染场景的函数,【伏笔2后面会有讲解】                 

CCDirector::sharedDirector()->mainLoop();            

}            

else           

{  

            //sleep0秒的意义是让CPU做下时间片切换,防止死循环而使系统其它程序得

            不到响应。                

Sleep(0);            

}            

continue;        

}   

//有消息获取到        

if (WM_QUIT == msg.message)        

{   

// 如果获取的消息是退出则退出循环。            

break;        

}        

// 如果没有定义加速键或者处理完加速键信息        

if (! m_hAccelTable || ! TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))        

{   

//处理Windows消息            

TranslateMessage(&msg);            

DispatchMessage(&msg);        

}    

}    

return (int) msg.wParam;

//外部调用的设置帧间隔时间

void CCApplication::setAnimationInterval(double interval){    

//获取高精度定时器的频率    

LARGE_INTEGER nFreq;

QueryPerformanceFrequency(&nFreq);

//计算出频率X帧间隔时差的值存入m_nAnimationInterval用做比较值    

m_nAnimationInterval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart);

}

//摆放方向变化时外部自动调用的设置摆放方向

CCApplication::Orientation CCApplication::setOrientation(Orientation orientation){    

//切换OPENGL视窗的宽高    

CCEGLView * pView = CCDirector::sharedDirector()->getOpenGLView();    

if (pView)    {        

return (Orientation)pView->setDeviceOrientation(orientation);    

}    

return (Orientation)CCDirector::sharedDirector()->getDeviceOrientation();

}

//获取状态栏的位置矩形

void CCApplication::statusBarFrame(CCRect * rect){    

if (rect)    {        

// WINDOWS系统没有状态栏,所以返回的矩形各位置都是0        

*rect = CCRectMake(0, 0, 0, 0);    

}

}

// 静态成员函数,获取单件指针

CCApplication& CCApplication::sharedApplication(){    

    CC_ASSERT(sm_pSharedApplication);    

    return *sm_pSharedApplication;

}

//静态成员函数,获取当前系统的语言类型

ccLanguageType CCApplication::getCurrentLanguage(){

//默认为英语    

ccLanguageType ret = kLanguageEnglish;

//

LCID localeID = GetUserDefaultLCID();

unsigned short primaryLanguageID = localeID & 0xFF;

switch (primaryLanguageID){

case LANG_CHINESE:

//中文

ret = kLanguageChinese;

break;

case LANG_FRENCH:

//法文

ret = kLanguageFrench;

break;

case LANG_ITALIAN:

//意文

ret = kLanguageItalian;

break;

case LANG_GERMAN:

//德文

ret = kLanguageGerman;

break;

case LANG_SPANISH:

//西班牙文

ret = kLanguageSpanish;

break;

case LANG_RUSSIAN:

//俄文

ret = kLanguageRussian;

break;

}    

return ret;

}

NS_CC_END;

//在注册表中写入对于PVRFrame的显示和隐藏的设置

static void PVRFrameEnableControlWindow(bool bEnable){    

HKEY hKey = 0;    

// 打开注册表的 PVRFrame 项    

    if(ERROR_SUCCESS != RegCreateKeyExW(HKEY_CURRENT_USER,        

L"Software\\Imagination Technologies\\PVRVFRame\\STARTUP\\",        

0,        

0,        

REG_OPTION_NON_VOLATILE,        

KEY_ALL_ACCESS,        

0,        

&hKey,        

NULL))    

{        

return;    

}   

const wchar_t * wszValue = L"hide_gui";    

const wchar_t * wszNewData = (bEnable) ? L"NO" : L"YES";    

wchar_t wszOldData[256] = {0};

DWORD  dwSize = sizeof(wszOldData);

//读取相应的键值

LSTATUS status = RegQueryValueExW(hKey, wszValue, 0, NULL, (LPBYTE)wszOldData,   

&dwSize);

//如果键值不存在,或者键值存在但与当前值不同,重设键值    

if (ERROR_FILE_NOT_FOUND == status              

      || (ERROR_SUCCESS == status                 

      && 0 != wcscmp(wszNewData, wszOldData)))    

{        

dwSize = sizeof(wchar_t) * (wcslen(wszNewData) + 1);        

RegSetValueEx(hKey, wszValue, 0, REG_SZ, (const BYTE *)wszNewData, dwSize);    

}

//关闭注册表    

RegCloseKey(hKey);

}


代码看完之后,我们来做一下 CCApplication 类的总结: 

在 CCApplication 的构造函数中可以看到这里定义了一个静态指针 sm_pShareApplication; 它在 CCApplication 实例化时指定为实例化单件对象的指针。在 sharedApplication 函数中返回实例化的单件对象引用。重点函数是 run 函数。在 run 函数开始调用了 initInstance 函数进行程序的初始化 , 调用返回为 true 后再调用 applicationDidFinishLaunching 函数完成一些逻辑的初始化工作 , 完成初始化后会进入 WINDOWS 消息循环,并通过高精度定时器进行 FPS 判断什么时候调用 CCDirector::sharedDirector()->mainLoop()。直待收到窗口关闭的消息退出消息循环并返回。 

好了,我们理解了 CCApplication 之后,我们再来看一下它的派生类 AppDelegate ,了解一下它都重载了哪些函数。 

读前小提示 :  CCEGLView 代表 OpenGL 显示窗口。封装了使用 OpengGL 做为显示底层 API 的一个基本的 WINDOWS 窗体的创建与控制。 

读前小提示 :  CCDirector 类中有一个函数 enableRetianDisplay 函数。这个函数主要是影响到 IOS 平台上支持高清显示的设备如 iphone4 , iphone4s 等。 如果设置enableRetinaDisplay(false), 则在iphone4平台上运行的结果是游戏的图片分辨率降低为原来的一半,因为宽高都被拉伸了一倍。如果设置enableRetinaDisplay(true), 则在iphone4平台上运行的结果是游戏的图片分辨率正常,但是放置的位置的水平方向和垂直方向都拉伸了两倍。要记住在cocos2d里面设置精灵坐标时,使用的是点,而不是像素,在普通的iphone上,一个点就等于一个像素,而在高清显示设备中,默认一个点等于二个像素。在IOS SDK 4.0及以后的SDK中支持不同的分辨率。并提供了相应的函数对逻辑点与像素的对应比例值做设置。 

重点关注函数: initInstance ()。 (AppDelegate.h)

 

#ifndef  _APP_DELEGATE_H_

#define  _APP_DELEGATE_H_

#include "CCApplication.h"

class  AppDelegate : private cocos2d::CCApplication

{

public:

//构造函数

AppDelegate();

//析构函数

virtual ~AppDelegate();    

//重载初始化函数    

virtual bool initInstance();    

//重载应用程序启动后调用的处理函数    

virtual bool applicationDidFinishLaunching();    

//重载应用程序转入后台时调用的函数    

virtual void applicationDidEnterBackground();    

//重载应用程序恢复前台时调用的函数    

virtual void applicationWillEnterForeground();

};

#endif // _APP_DELEGATE_H_

再来看AppDelegate.cpp文件

#include "AppDelegate.h"

//加入cocos2d头文件

#include "cocos2d.h"

#include "HelloWorldScene.h"

//加入OpenGL窗口类

#include "CCEGLView.h"

//使用cocos2d命名空间

USING_NS_CC;

//构造函数

AppDelegate::AppDelegate() {

}

//析构函数

AppDelegate::~AppDelegate() {

}

//初始化函数,解答伏笔1

bool AppDelegate::initInstance() 

{

//定义一个bool返回值用于判断是否正常初始化

bool bRet = false;

do {

//通过对宏定义的匹配来判断当前编译的代码的目标平台是什么,在这里可以知道Cocos2d-x的跨平台都支持哪些平台。我们的教程只针对WIN32平台部分做讲解,其它平台大家可以自行参考WIN32平台部分进行学习。

//第一种平台类型,WIN32系统

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)

// 创建并初始化OpenGL窗口管理实例对象,注意这里使用的是new来动态实例化的。 

当程序退出时会通过显示设备的release函数进行对窗口的释放。【伏笔3后面会有讲解】。

CCEGLView * pMainWnd = new CCEGLView();

    //CC_BREAK_IF宏的意思是如果括号中的语句为否则中断循环。配合do_while流程使

用。

//可以看到这里的意思是,如果pMainWnd实例化失败或者pMainWnd创建窗口失

    败则中断循环。在这里硬性的设定了窗口的标题和窗口的宽度高度。

CC_BREAK_IF(!pMainWnd || !pMainWnd->Create(TEXT("cocos2d: Hello World"), 480, 

320));

#endif  // CC_PLATFORM_WIN32   

//第二种平台类型,IOS类型

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)

#endif  // CC_PLATFORM_IOS

//第三种平台类型,ANDORID类型

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

#endif  // CC_PLATFORM_ANDROID    

//第四种平台,WOPHONE平台

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WOPHONE)

#endif  // CC_PLATFORM_WOPHONE

//第五种平台,MARMALADE

#if (CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE)

#endif

//第六种平台,LINUX

#if (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)

#endif  // CC_PLATFORM_LINUX

//第七种平台,BADA

#if (CC_TARGET_PLATFORM == CC_PLATFORM_BADA)

#endif  // CC_PLATFORM_BADA

//第八种平台,QNX

#if (CC_TARGET_PLATFORM == CC_PLATFORM_QNX)

#endif // CC_PLATFORM_QNX

//如果没有被中断,则成功完成初始化。

bRet = true;

//退出循环

} while (0);

return bRet;

}    

//重载应用程序启动后调用的处理函数

bool AppDelegate::applicationDidFinishLaunching() {

//通过CCDirector的静态函数sharedDirector来获取单件显示设备管理器指针

CCDirector *pDirector = CCDirector::sharedDirector();

    //通过CCEGLView的静态函数sharedOpenGLView来获取单件管理实例对象并将其地址

    通过CCDirector的成员函数setOpenGLView传递给显示设备管理器。

pDirector->setOpenGLView(&CCEGLView::sharedOpenGLView());

    //打开使用高清模式,这里给屏蔽了,如未来有需要可以打开。但是在设计程序时需要

    考虑到打开后对于位置的影响并提前制定相应的设计方案。

//pDirector->enableRetinaDisplay(true);

// 打开显示

FPSpDirector->setDisplayFPS(true);

// 设置当前屏幕的摆放方向,这里给屏蔽了。

// pDirector->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft);

// 设置FPS的帧间隔时间差为60分之一秒,从而期望FPS60帧。

pDirector->setAnimationInterval(1.0 / 60);

//通过HelloWorld的静态函数scene()创建返回一个场景实例

CCScene *pScene = HelloWorld::scene();

//运行这个场景

pDirector->runWithScene(pScene);

return true;

}

//重载应用程序转入后台时调用的函数,如电话打进来 

void AppDelegate::applicationDidEnterBackground() {

//暂停显示设备的渲染处理

CCDirector::sharedDirector()->pause();

// 如果使用了声音引擎,这里进行暂停设置。否则会影响到通话,因为暂时没用到,所以屏蔽

// SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();

}

//重载应用程序恢复前台时调用的函数

void AppDelegate::applicationWillEnterForeground() {

//恢复显示设备的渲染处理

CCDirector::sharedDirector()->resume();

//如果使用了声音引擎,这里进行恢复设置

// SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();

}


在 InitInstance 函数中,我们看到 Cocos2d-x 将 Windows 窗口的创建与控制都封装到了 CCEGLView 类中。它已经暴露出一个 Create 函数,做为一个求知者,我们应该迫不及待的想要看到它在哪里创建窗口。继续追进去吧! GoGoGo! 

我们进入了 CCEGLView_win32.cpp ,通过文件名可以知道 CCEGLView 类应该有多个平台的版本。我们暂不理它。看一下 Create 函数。 (在CCEGLView_win32.cpp )

//我们先从bool CCEGLView::Create(LPCTSTR pTitle, int w, int h)开始

bool CCEGLView::Create(LPCTSTR pTitle, int w, int h){

//定义一个bool型返回值

bool bRet = false;

do 

{

//检测窗口句柄是否已经存在。确保只创建一个窗口

CC_BREAK_IF(m_hWnd);

//进入到这里,我们应该很高兴了。没错,终于找到了创建窗口的代码。

HINSTANCE hInstance = GetModuleHandle( NULL );

WNDCLASS  wc;

// 窗口类

// 设置相关参数

wc.style           = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;  

wc.lpfnWndProc    = _WindowProc;

// 本窗口使用的WINDOWS消息处理函数

wc.cbClsExtra      = 0;                              

wc.cbWndExtra     = 0;

wc.hInstance       = hInstance;

wc.hIcon          = LoadIcon( NULL, IDI_WINLOGO );

wc.hCursor        = LoadCursor( NULL, IDC_ARROW );

wc.hbrBackground  = NULL;                           

wc.lpszMenuName  = NULL;                           

wc.lpszClassName  = kWindowClassName;               

        //注册窗口类,如果失败则判断失败原因是否是此类别已存在(错误码1410),如果

        因为此类存在而导致失败,则仍然可以继续。

CC_BREAK_IF(! RegisterClass(&wc) && 1410 != GetLastError());

// 取得窗口的窗体矩形

RECT rcDesktop;

GetWindowRect(GetDesktopWindow(), &rcDesktop);

// 调用创建口函数

m_hWnd = CreateWindowEx(

WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,kWindowClassName,

// 之前注册的窗口类

pTitle,

// 窗口标题

WS_CAPTION | WS_POPUPWINDOW | WS_MINIMIZEBOX,

// 窗体样式

0, 0,              

// 窗体位置

0,                                                  

// 窗体宽度

0,                                                  

// 窗体高度

NULL,

// 无父窗口

NULL,

// 无菜单

hInstance,

// 程序句柄

NULL );

//判断窗口是否创建成功

CC_BREAK_IF(! m_hWnd);   

//取得显示设备的摆放方向        

m_eInitOrientation = CCDirector::sharedDirector()->getDeviceOrientation();   

//通过对摆放方向的判断得出水平还是垂直        

m_bOrientationInitVertical = (CCDeviceOrientationPortrait == m_eInitOrientation

           || kCCDeviceOrientationPortraitUpsideDown == m_eInitOrientation) ? true : false;        

m_tSizeInPoints.cx = w;        

m_tSizeInPoints.cy = h;   

//设置窗口大小        

resize(w, h);

// 使用此窗口进行OpenGL的设置

m_pEGL = CCEGL::create(this);

// 如果OpenGL创建失败,销毁窗体并中断

if (! m_pEGL){

DestroyWindow(m_hWnd);

m_hWnd = NULL;

break;

}

//将静态指针设置为当前实例对象。

s_pMainWindow = this;

bRet = true;

} while (0);

return bRet;

}


 

在注册类时,设定了窗口的消息处理回调函数为_WinDowProc,我们继续追入看一下程序退出时在哪里释放了Opengl窗口实例对象。呵呵,还记得前面我们埋下的伏笔3,它是用new创建出来的。而new出来的内存必须释放。程序退出会销毁窗体,消息处理函数会先后收到WM_CLOSEWM_DESTROY。我们找一下。(还是CCEGLView_win32.cpp,bool CCEGLView::Create()函数上面)

 

static LRESULT CALLBACK _WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, 

  LPARAM lParam){

//如果OpenGL窗体初始化完成,则由OpenGL窗体进行消息处理,否则由WINDOWS

系统进行默认处理

    if (s_pMainWindow && s_pMainWindow->getHWnd() == hWnd){

        return s_pMainWindow->WindowProc(uMsg, wParam, lParam);

    }else{

        return DefWindowProc(hWnd, uMsg, wParam, lParam);

    }

}


继续。(在CCEGLView_win32.cpp,bool CCEGLView::Create()函数下面)

LRESULT CCEGLView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){

PAINTSTRUCT ps;

switch (message){

//以上消息暂不理,可自行分析

case WM_PAINT:

//这里是刷新屏幕,因为使用了OpenGL来进行绘制,所以这里不作任何处理。

BeginPaint(m_hWnd, &ps);

EndPaint(m_hWnd, &ps);

break;

case WM_CLOSE:

//调用单件显示设备管理器的end函数关闭窗口

CCDirector::sharedDirector()->end();

break;

case WM_DESTROY:

//向消息循环发送WM_QUIT消息退出程序

PostQuitMessage(0);

break;

    default:

return DefWindowProc(m_hWnd, message, wParam, lParam);

}return 0;

}


进入显示设备管理器 CCDirector 的 end 函数。(在CCDirector.cpp) 

void CCDirector::end(){

    //是否在下一个循环时清除显示设备

    m_bPurgeDirecotorInNextLoop = true;

}


倒 这里只是设置成员变量 m_bPurgeDirecotorInNextLoop为 true, 没有什么 delete 。怎么回事呢? 

好吧,继续分析,成员变量的名字意思是是否在下一个循环时清除显示设备。哦。也就是说这只是一个开关。在循环函数中判断它是否为 true 来清除显示设备。打开 mainLoop 函数。解答 伏笔 (在CCDirector.cpp)

void CCDisplayLinkDirector::mainLoop(void){

//如果清除显示设备开关为true

if (m_bPurgeDirecotorInNextLoop){

//清除设备

purgeDirector();          

m_bPurgeDirecotorInNextLoop = false;

}//否则判断显示设备是否有效

else if (! m_bInvalid) {

//如果有效,绘制场景 

drawScene(); 

 //调用内存管理器释放其管理的内存 

CCPoolManager::getInstance()->pop(); 

}

}


马上要接晓答案了(在CCDirector.cpp)

void CCDirector::purgeDirector(){

//以上暂不理。有兴趣的朋友请自行分析

// 调用Opengl窗口管理实例对象的release函数进行释放。

m_pobOpenGLView->release();

m_pobOpenGLView = NULL;

}


进入 OpenGL 窗口管理类的 release 函数 (在CCEGLView_win32.cpp

void CCEGLView::release(){

//销毁窗体

if (m_hWnd){

DestroyWindow(m_hWnd);

m_hWnd = NULL;

}

s_pMainWindow = NULL;

//注销所使用的窗口类

UnregisterClass(kWindowClassName, GetModuleHandle(NULL));    

//释放使用到的指针    

CC_SAFE_DELETE(m_pSet);    

CC_SAFE_DELETE(m_pTouch);    

CC_SAFE_DELETE(m_pDelegate);

CC_SAFE_DELETE(m_pEGL);

//关键点:在最后释放了自已在AppDelegate::initInstance()中通过new创建对象而占用

的内存。    

delete this;

}


现在我们了解了 Cocos2d-x 是如何将 WINDOWS 程序基本框架封装在自已的类之中的。运行一下程序,可们可以看到弹出的窗口显示出 HelloWorld 的画面。而当初复杂的 WINDOWS 程序基本框架。在这里只化为简单的一句 run() 。非常简洁! 

这个运行中的窗口,没有最大化系统按钮,窗体大小也被固定在 480x320 。我们希望能够更灵活的设置窗口的标题和大小。那我们必须要做一些改动。即然已经看懂了代码,下面就亲自实习一下吧。 

打开 AppDelegate  initInstance 函数,增加相应的参数。 (AppDelegate.cpp中的bool AppDelegate::initInstance()函数)

 

bool AppDelegate::initInstance(LPCTSTR szTitle,UINT wWidth,UINT wHeight)

 

并改动下面一句

CC_BREAK_IF(! pMainWnd

  //改成由函数参数来创建OpenGL窗体

  || ! pMainWnd->Create(szTitle, wWidth, wHeight));

 //|| ! pMainWnd->Create(TEXT("cocos2d: Hello World"), 480, 320));

 

然后我们打开 CCApplication_win32.cpp ,找到 run 函数。做同样的修改。 

int CCApplication::run(LPCTSTR szTitle,UINT wWidth,UINT wHeight)

 

并改动下面一句

if (! initInstance(szTitle,wWidth,wHeight) || ! applicationDidFinishLaunching())

// if (! initInstance() || ! applicationDidFinishLaunching())


之后我们将头文件所需要改动的函数声明也一一改动。保存,重新编译 libcocos2d 工程。再打开 HelloWorld 中的 main.cpp 修改这一句: 

 

// 我们可以在这里自已设定窗口标题和窗口大小 

return cocos2d::CCApplication::sharedApplication().run(TEXT("第一个Cocos2d-x程序"),800,600);

//return cocos2d::CCApplication::sharedApplication().run();


编译 HelloWorld 。运行一下。享受一下成果! 

0 0
原创粉丝点击