小鱼习惯直接从代码实例来学习一套成型的引擎库。

运行cpp-empty-test

一个典型的HelloWorld程序翻看代码结构

看到了 main.h与main.cpp文件就从这里开始

#ifndef __MAIN_H__
#define __MAIN_H__ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files:
#include <windows.h>
#include <tchar.h> // C RunTime Header Files
#include "CCStdC.h" #endif // __MAIN_H__

从这个头文件中没有得到什么有价值的信息,包含了一些库文件,还有一个就是引入了 CCStdC.h 这个文件,从命名上来看应该是Cocos2d-x的标准库头文件,打开来看了几眼,都是一些常用的宏定义,还有就是平台定义,先忽略掉这些信息,继续向下看。

main.cpp

#include "main.h"
#include "../Classes/AppDelegate.h" USING_NS_CC; int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine); // create the application instance
AppDelegate app;
return Application::getInstance()->run();
}

  打开了main.cpp文件我立刻石化了,竟然就有这么几行代码,看来cocos2d-x封装的很牛X啊

这个helloWorld的核心代码就一句 Application::getInstance()->run();

刨根问底我们去了解一下 Application类, 从在这里的调用上来看,整个cocox2d-x都封装在了Application这个类里面每一个应用程序都有唯一的一个Application对象,这种调用明显采用了单例的设计模式,我们跟一下代码,追踪线索。

打开Application.h文件发现

class CC_DLL Application : public ApplicationProtocol

  Applilcation类继承了 ApplicationProtocol类, 继续看 ApplicationProtocol.h

CCApplicationProtocol.h

#ifndef __CC_APPLICATION_PROTOCOL_H__
#define __CC_APPLICATION_PROTOCOL_H__ #include "CCPlatformMacros.h" NS_CC_BEGIN class CC_DLL ApplicationProtocol
{
public: // Since WINDOWS and ANDROID are defined as macros, we could not just use these keywords in enumeration(Platform).
// Therefore, 'OS_' prefix is added to avoid conflicts with the definitions of system macros.
enum class Platform<span style="white-space:pre"> </span>// 平台种类的一个枚举
{
OS_WINDOWS,
OS_LINUX,
OS_MAC,
OS_ANDROID,
OS_IPHONE,
OS_IPAD,
OS_BLACKBERRY,
OS_NACL,
OS_EMSCRIPTEN,
OS_TIZEN,
OS_WINRT,
OS_WP8
};
virtual ~ApplicationProtocol() {} virtual bool applicationDidFinishLaunching() = ;// 程序启动后的一个回调,应该在这里可以放置一些初始化的操作 virtual void applicationDidEnterBackground() = ;// 程序进入后台时的回调函数,pc中的最小化,手机中的程序转入后台的这个时机调用。 virtual void applicationWillEnterForeground() = ;// 程序又重回前台时的回调 virtual void setAnimationInterval(double interval) = ;// 设置动画两帧之间的时间间隔,也就是常说的帧速度之类的参数 virtual LanguageType getCurrentLanguage() = ;// 应该是和语种相关的,用来做多语言版本时得到当前语言类型参数 可以打开LanguageType看看 virtual const char * getCurrentLanguageCode() = ;// 得到当前语言的编码,返回的是一个字符串,可能是 utf8 gb2312(这里是推测) virtual Platform getTargetPlatform() = ;// 得到当前平台类型 也就是上面定义的枚举,
}; // end of platform group
/// @} NS_CC_END #endif // __CC_APPLICATION_PROTOCOL_H__

这里我把这个文件精简了一下去掉了注释

可以看到ApplicationProtocol是一个抽象类,提供了很多抽象方法,有一个平台类型的定义

enum class Platform

通过这个枚举里面的定义可以了解cocos2d-x所支持的平台各类,还是很全面的,很多小鱼都没用到过。

从纯虚函数的名称上我可以大致猜到这些函数的作用,以注释的形式写到上面代码的后面。

这个类并不复杂,都是定义了一些接口,可以推断,不同平台下的App都要分别继承这个接口来实现不同的处理。

下面我回到 Application 类 一点一点的看,确定Application这个类继承了ApplicationProtocol类

并且在这个头文件上面我看到了这样的一个宏定义

#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32

明显这个Application类是为了 Windows平台准备的

下面列出部分代码来分析

NS_CC_BEGIN

class Rect;

class CC_DLL Application : public ApplicationProtocol
{
public:
Application(); virtual ~Application(); int run(); static Application* getInstance(); CC_DEPRECATED_ATTRIBUTE static Application* sharedApplication(); virtual void setAnimationInterval(double interval);
virtual LanguageType getCurrentLanguage(); virtual const char * getCurrentLanguageCode(); virtual Platform getTargetPlatform(); /**
* Sets the Resource root path.
* @deprecated Please use FileUtils::getInstance()->setSearchPaths() instead.
*/
CC_DEPRECATED_ATTRIBUTE void setResourceRootPath(const std::string& rootResDir); CC_DEPRECATED_ATTRIBUTE const std::string& getResourceRootPath(void); void setStartupScriptFilename(const std::string& startupScriptFile); const std::string& getStartupScriptFilename(void)
{
return _startupScriptFilename;
} protected:
HINSTANCE _instance;
HACCEL _accelTable;
LARGE_INTEGER _animationInterval;
std::string _resourceRootPath;
std::string _startupScriptFilename; static Application * sm_pSharedApplication;
}; NS_CC_END

实现父类的几个虚函数我们就不讨论了。

static Application* getInstance(); 

App是个单例,这是得到app对象的静态方法,不用多说。

int run();

游戏启动及游戏循环肯定在这里了。

我们稍后再进入到run里面看个究竟,先把Application看完整

CC_DEPRECATED_ATTRIBUTE void setResourceRootPath(const std::string& rootResDir);

这个函数肯定是设置资源文件的路径地址的。

 void setStartupScriptFilename(const std::string& startupScriptFile);

设置启动脚本,这个肯定是设置启动Lua或者js脚本的地方

Application类小鱼总结一下,这个类也是一个抽象类,因为有些父类的虚函数并没有实现,是针对win32平台下的,如果 想在自己的平台使用应该仿照定义自己的Application类,主要负责启动Cocos2d-x 开发人员应该继承 Application类来定制自己的应用程序。值得学习的是这块Application的封装应用了抽象工厂的设计模式,来满足不同平台的整合

这个HelloWorld示例程序中私人订制的App类为AppDelegate类,我们打开看一下,实现了三个抽象方法.

    virtual bool applicationDidFinishLaunching();

    virtual void applicationDidEnterBackground();

    virtual void applicationWillEnterForeground();

后两个函数主要是在程序前后台运行的时候进行了暂停和恢复暂停的操作,

第一个函数 applicationdidFinishLaunching 进行了一系列初始化。稍后我们再分析它。

至此我们大致分析了Application这个类,看了源码,了解了这个类的作用,那么具体是怎么驱动的呢,我们回过头来看 Application:run()这个函数,这也是helloworld里调用 的唯一一个方法。程序从这个run开始运行。我将分析写入到代码间,这样能方便大家阅读。

int Application::run()
{
PVRFrameEnableControlWindow(false); //跟进函数看到了一些注册表的操作,操作了窗口信息的变量。先过,可以了解到如果自己有些平台性质的全局数据交互可以扩展这里面的代码。 // Main message loop:
LARGE_INTEGER nFreq;
LARGE_INTEGER nLast;
LARGE_INTEGER nNow; QueryPerformanceFrequency(&nFreq);// windows平台得到硬件时钟的频率
QueryPerformanceCounter(&nLast);//记录上一次计时的时间 // Initialize instance and cocos2d.
if (!applicationDidFinishLaunching())//调用上面提到过的私人定制的初始化过程。这也是虚函数的一个应用
{
return ;
} auto director = Director::getInstance();//得到Director类的单例对象,Director类是干什么的先不管,从字面上理解是导演的意思,肯定是一个很重要的类
auto glview = director->getOpenGLView();//可以看出 Director类里封装了关于OPENGL的操作,这里是得到opengl对象 // Retain glview to avoid glview being released in the while loop
glview->retain();//从上面的注释可以了解到在这里为了防止glview这个opengl对象在下面的循环中被释放,增加了一次引用。 while(!glview->windowShouldClose())// 游戏主循环
{
QueryPerformanceCounter(&nNow);
if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)// 计算是否达到设置的游戏帧频的时间
{
nLast.QuadPart = nNow.QuadPart; director->mainLoop();
glview->pollEvents();
}
else
{
Sleep();
}
} // Director should still do a cleanup if the window was closed manually.
if (glview->isOpenGLReady())//释放opengl
{
director->end();
director->mainLoop();
director = nullptr;
}
glview->release();
return true;
}

这里面Director这个类出镜率很高,之后我们单独分析这个类。

下面我们分析一下私人定制的applicationDidFinishLaunching函数在程序启动中都干了些什么。

bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
auto director = Director::getInstance();//获取director对象,具体Director类是什么玩意,下文分析,目前可以知道这是个大管家
auto glview = director->getOpenGLView();//获取opengl渲染对象,注意这里的 auto用法,这是c++11的新特性,大家可以去百度,就是根据后面的初始化来自动识别变量类型,真是方便啊。
if(!glview) {
glview = GLView::create("Cpp Empty Test");
director->setOpenGLView(glview);
}//如果获取opengl失败那么重新创建一个opengl对象。 director->setOpenGLView(glview);// 将opengl对象绑定到大管家,大导演身上。 // Set the design resolution
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
// a bug in DirectX 11 level9-x on the device prevents ResolutionPolicy::NO_BORDER from working correctly
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::SHOW_ALL);
#else
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
#endif
//这段代码是判断平台来设置此app的长宽及边框模式。还有一些预定义在AppMacros.h里面定义的,可以翻看一下。
Size frameSize = glview->getFrameSize();
vector<string> searchPath;
// In this demo, we select resource according to the frame's height.
// If the resource size is different from design resolution size, you need to set contentScaleFactor.
// We use the ratio of resource's height to the height of design resolution,
// this can make sure that the resource's height could fit for the height of design resolution.
// if the frame's height is larger than the height of medium resource size, select large resource.
if (frameSize.height > mediumResource.size.height){ searchPath.push_back(largeResource.directory);
director->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width));}
// if the frame's height is larger than the height of small resource size, select medium resource.
else if (frameSize.height > smallResource.size.height)
{
searchPath.push_back(mediumResource.directory);
director->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width));
}
// if the frame's height is smaller than the height of medium resource size, select small resource.
else
{
searchPath.push_back(smallResource.directory);
director->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width));
} // set searching path
FileUtils::getInstance()->setSearchPaths(searchPath);
// 上面的那几段代码是针对不同分辨率读取不同的资源,并且计算了缩放比例,设置了资源路径。
// turn on display FPS 设置帧速率的显示
director->setDisplayStats(true);
// set FPS. the default value is 1.0/60 if you don't call this
director->setAnimationInterval(1.0 / );
//这里设置了帧速率,回想上面我们看Application::run代码里面while循环就是依据这块设置的速率来实现的。
// create a scene. it's an autorelease object
auto scene = HelloWorld::scene();//这里又出现了一个新的类 HelloWorld 这是什么玩意?后面再说。肯定是定义了一个场景。
// run
director->runWithScene(scene);//最后一行代码是让大总管,大导演,run这个HelloWorld场景。
return true;
}
总结:到这里我们通过HelloWorld及跟踪代码,了解了cocos2d-x的启动流程每个平台都要有一个Application类继承自ApplicationProtocol来驱动整个程序。
每个项目都要有一个自己的App类继承自相应平台的Application调用Application::run方法来实现程序的启动。
在run里面可以定制自己的启动初始化 用Application::applicationDidFinishLaunching来实现 还涉及到了几个重要的类   Director, HelloWorld里面的Layer,Scene这几个类.
下章我们来继续刨根问底从 Director  Layer  Scene这几个类开始小鱼看代码喜欢一层一层的看,也就是广度优先,而不是一个类看到底的方式。 备注:此系列文章为小鱼自己学习cocos2d-x源码的一个过程,并非教程,有些内容在前面可能在前面章节说的不准确(因小鱼也不知道),但后面涉及到后肯定会给出明确的解释。

  

Cocos2d-X3.0 刨根问底(二)----- 从HelloWorld开始的更多相关文章

  1. Cocos2D v2.0至v3.x简洁转换指南(二)

    触摸处理 我们在稍后将完成Cocos2d 3.0中触摸处理的完整教程.而现在最重要的是知道如何去启用触摸处理在你的CCNode中: self.userInteractionEnabled = TRUE ...

  2. 如何在Cocos2D 1.0 中掩饰一个精灵(六)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 掩饰一个精灵:实现代码 打开HelloWorldLayer.m并 ...

  3. 如何在Cocos2D 1.0 中掩饰一个精灵(一)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 原帖来自Ray Wunderlich写的精彩的文章 How To ...

  4. Cocos2D v2.0至v3.x简洁转换指南(三)

    Cocos2D 3.3中的注意事项 如果你在使用Cocos2D 3.3+(是SpriteBuilder 1.3+的一部分)你将不得不替分别的换所有存在的UITouch和UITouchEvent为CCT ...

  5. 如何将各种低版本的discuz版本升级到discuz x3.0

    最近在做discuz改版的项目,遇到了很多问题,相信很多拥有discuz论坛的版主,站长和程序猿在升级或改版discuz的过程中遇到过和我一样的问题,所以我开了一个discuz专栏,为大家讲解一下di ...

  6. cocos2d 2.0和UIKit混合编程, Push CCDirector的时候出现黑屏的天坑

    症状 使用cocos2d 2.0和UIKit混合编程, 有一块用cocos2d编写的小程序, 将CCDirector push到一个UINavigationController里面. 虽然事先在后台初 ...

  7. 探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs

    原文:探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs 前言:.NET Core 3.0 SDK包含比以前版本更多的现成模板. 在本文中,我将 ...

  8. 如何在Cocos2D 1.0 中掩饰一个精灵(二)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 让我们开始吧 打开Xcode,从New Project中选择co ...

  9. cocos2d-x3.0创建第一个jsb游戏

    第一步: 最新的cocos2d-x.下载地址https://github.com/cocos2d/cocos2d-x github上最新的引擎,值得注意的是官网上发布的引擎是稳定版.选择哪种就看个人喜 ...

随机推荐

  1. vmware12安装vmtools

    一. 1. 机器要开启支持BIOS的选项. 二. 1. 点击vmware 应用 vmware install 2. 虚拟机: tar  xvf vmtools-distb.tgr.gz 3. 虚拟机: ...

  2. android窗口泄漏,isInEditMode解决可视化编辑器无法识别自定义控件的问题

    android窗口泄漏 在做项目是遇到这个错误:google:WindowManager: Activity has leaked window. 产 生原因:我们知道Android的每一个Activ ...

  3. Android Handler处理机制 ( 二 ) ——Handler,Message,Looper,MessageQueue

    Android是消息驱动的,实现消息驱动有几个要素: 消息的表示:Message 消息队列:MessageQueue 消息循环,用于循环取出消息进行处理:Looper 消息处理,消息循环从消息队列中取 ...

  4. Masonry

    Autolayout就像一个知情达理,善解人意的好姑娘,可惜长相有点不堪入目,所以追求者寥寥无几.所幸遇到了化妆大师cloudkite,给她来了一个完美的化妆,从此丑小鸭Autolayout变成了美天 ...

  5. StackBlur.js

    StackBlur.js 是 Mario Klingemann 创建的一个快速的.接近高斯模糊的效果库. 更多信息: http://incubator.quasimondo.com/processin ...

  6. scroll滚动条插件初始化问题

    一种特殊场景下是滚动条容器先隐藏,点击某个东西后显示出来.然后实例化滚动条.实例 js: var flag = true; document.getElementById('btn1').onclic ...

  7. WPF RadioButton 转换

    模型 public class people { public string name{get;set;} public bool? sex{get;set;} } 转换器 namespace Hel ...

  8. 加密方式&数字签名

    1,对称加密 2,混合加密 3.数字签名 4,带加密的数字签名

  9. C语言 简单的队列(数组队列)

    //简单的队列 #include<stdio.h> #include<stdlib.h> #define datatype int #define N 10 //定义队列结构体 ...

  10. 多个相同jar存在时的引用顺序

    起因:今天一个aar包在测试环境中正常运行,使用soapui测试正常返回,在本地环境中运行则老是报数据库连接异常,经检查,是因为在运行时环境中缺少ojdbc相关的jar包引起的. 重新打了一个aar包 ...