cocos2d-x学习笔记01——初识

时间:2023-02-06 19:54:26

     下学期要专心学习cocos2d-x开发cdio,还有unix socket,为了不那么累,先提前感悟感悟cocos2d-x。况且学习cocos2d-x,可以提高自己的面向对象封装能力,学习良好的代码风格,跨平台处理,游戏开发等。把这学期学的C++理论,比如虚函数,多继承,单例模式,内存池,自定义命名空间等平常不太常用的都能在cocos2d-x里随处可见,完全告诉你它们怎么整成一体,可见语言基础的重要,这样肯定可以加深C++理解和使用。不多说了,开始吧。


       1.首先C++不同于as3.0和java,它有头文件,头文件往往可以声明多个类,在cocos2d-x里,往往把多个类似的类声明放同一个头文件中,如CCDirector类声明和CCDisplayLinkDirector,而CCDisplayLinkDirector继承自CCDirector。这样的代码设计值得学习,因为一个引擎类实在很多种,把类似的,或者说是有血缘关系的放在同一个文件中,方便查找。而且往往子类的声明代码已经很少了,因为父类已经做了大部分的工作。同样地,父类和子类的实现代码也都放在了同一个cpp文件中,原因很简单,假如把有血缘关系的这2个类放在不同地方去实现,那么由于这2个类往往都要include很多相同的外部头文件,造成预编译展开时扩大了代码的行数。如果放在同一个文件,则减少了一半的展开量,当然如果有#ifndef之类的则可避免展开,但仍然需要写同样的很多include的包含。另外,往往文件名.h和文件名.cpp和父类的名字一样。


      2.从解决方案资源管理器结构学习引擎(2.0.4版),游戏逻辑核心文件都在libcocosd工程内(实际对应于I:\cocos2d-2.0-x-2.0.4\cocos2d-2.0-x-2.0.4\cocos2dx文件夹内,里面又有很多个子文件,用于分开不同用途的游戏引擎逻辑带按摩)。里面有个include子文件夹,里面有个cocos2d.h,要知道的是,C++里的头文件和源文件,并不是非得头文件就得声明类,源文件就是用于实现类,这是错误的。比如这个cocos2d.h,就是专门用于包含所有常用游戏引擎逻辑的代码的(把需要的都给include进来),这样以后我们就可以直接包含cocos2d.h一个文件,而无需每次都包含那么一堆逻辑的东西进我们的代码了。cocos2d.cpp文件在include的上层目录里,并无太多实现,只有一个函数cocos2dVersion(),用于return "cocos2d-2.0-x-2.0.4";  的版本号。有的文件只是专门只用于定义宏,include下的ccConfig.h配置文件。都是为了其他文件服务的。其实可以想象一下,游戏编程里常常独立出一个头文件来写一些代码,这些代码是整个工程通用的,也就是说让别的一个活多个文件都能共享它。


       3.学习Hello World!一种是通过引擎自带的helloworld项目,另一种是自己用模板新建一个cocos2d-x项目。然后学习它。值得注意的是:cocos2d-x一般都用vs打开,每个工程(项目)里面有个win32文件夹,里面放了main.cpp和main.h.

cocos2d-x学习笔记01——初识

看来,这里这里是windows系统上运行时的入口,平台相关的代码,而main.h里可以看到它include<windows.h>。

这里可以改变设置open gl 的视口大小。默认是480*320.

令人疑惑的是app这个自动变量并没有app->run() ;   而是通过单例模式的CCApplication:sharedApplication()->run();于是我注释掉AppDelegate app;试试看,居然崩溃了。难道CCApplication:sharedApplication()->run();这个调用可以取得app对象的地址????答案是是的。

经过不断地f12进入定义,原来CCAplication的定义里有个static CCApplication * sm_pSharedApplication;静态成员变量。而CCApplication构造函数里有个sm_pSharedApplication = this;语句。CCApplication:sharedApplication()函数正是返回sm_pSharedApplication。果然单例模式是很常用的。


       4.简单运行看过HelloWorld项目后,看完后依然发现还是不知怎么进一步学习的感觉,于是把TestCpp项目设置成启动项目,然后运行它,发现里面有菜单,体验使用引擎支持的不同的功能,无疑是初学者最好的学习方式了,学习使用中熟悉引擎的实现。所以接下来就是学习TestCpp项目里的源码了。

从上到下分析:

main.h和main.cpp刚才已经看过了,它是初始化app对象的地方,同时也是设置open gl 的视口的地方。

AppDelegate类是应用程序类,启动类(呵呵,越来越面向对象的感觉了)

其中的AppDelegate::applicationDidFinishLaunching() 函数的部分实现即可看出总体逻辑了,如下:

cocos2d-x学习笔记01——初识

pScene场景addChild(菜单层)。记住:pScene并没有成为AppDelegate类的成员变量,而是把它放到runWithScene函数里,我估计这样导演类就记下了这个场景在堆中的地址,而pDirector更无须成为AppDelegate类的成员变量,因为它是全局的单例对象。

TestController类是主菜单层(继承自CLayer),包括了主菜单的控制,和启动正式的测试效果场景。

TestScene类是基础场景类(public继承于CCScene),实现了一些基本功能,之后的场景类继承与此,是为了方便后面的演示例子使用。

tests.h文件里是枚举和数组的配合,枚举做数组的下标,数组值是菜单选项显示的字符串。

testResource.h则当做本TestCpp项目的配置文件,引入所有图片的资源的相对路径。
看下面的部分代码,即可知道这个TestCpp的能演示不同功能的整体设计:

cocos2d-x学习笔记01——初识

cocos2d-x学习笔记01——初识

返回的pScene,其类型是正是TestScene类,基础场景类。每个功能需要一个继承自TestScene的场景类。

      5.从DrawPrimitivesTest 那个文件夹下的测试实例学习到:

基本图元的绘制,是通过封装open gl 的api。基本图元绘制文件在libcocos2d项目的root目录下CCDrawingPrimitives.h和CCDrawingPrimitives.cpp 里。引擎的作者他们通过启动libcocos2d项目先生成libcocos2d.lib和libcocos2d.dll到发布版I:\cocos2d-2.0-x-2.0.4\cocos2d-2.0-x-2.0.4\Release.win32或者调试版I:\cocos2d-2.0-x-2.0.4\cocos2d-2.0-x-2.0.4\Debug.win32。。而剩下的各种无用的obj就放到I:\cocos2d-2.0-x-2.0.4\cocos2d-2.0-x-2.0.4\cocos2dx\proj.win32\Debug.win32或者I:\cocos2d-2.0-x-2.0.4\cocos2d-2.0-x-2.0.4\cocos2dx\proj.win32\Release.win32 。

至于其他os平台, 只有对应os的开发工具的工程文件,而无obj文件,因为并没有把其他平台编译后的obj都放到目录里。作者只编译了这个libcocos2d工程在windows上的。

DrawPrimitivesTest.cpp 里可以用ccDrawLine() 等外部函数,是因为DrawPrimitivesTest.cpp包含了DrawPrimitivesTest.h,DrawPrimitivesTest.h又去包含了"../testBasic.h",而testBasic.h又去包含了cocos2d.h

,好了,cocos2d.h,是一个大杂烩头文件。几乎把libcocos2d里的所有文件从root到所有子文件夹里的文件都给包含了。而CCDrawingPrimitives.h正是在root里,即libcocos2d里。

void CC_DLL ccDrawLine( const CCPoint& origin, const CCPoint& destination );

CC_DLL是个宏,#define CC_DLL     __declspec(dllimport)

也就是说告诉编译器,这个函数的实现应当通过dll动态导入。。哪里导入呢,自然是上面说的libcocos2d.dll咯,一来这样就做到了模块化,二来是隐藏图元绘制的具体实现,只提供接口。但是作者还是给出了DrawPrimitivesTest.cpp 文件,其好处是让我们可以看到它的具体实现,有朝一日让用户修改它,然后重新生成功能更多更好的dll,这就是开源嘛。


        6.节点CCNode 有成员函数OnEnter,OnExit,后续的子类都会继承这一特性。它们分别是进入到舞台时,和切换出舞台时自动被调用的函数。


        7.场景CCScene

       在场景类的构造函数里先调用基类场景的初始化,然后自己再初始化。假如不需要有自己的操作,那么甚至可以无需声明构造函数(直接交给父类了)。

       在场景的OnEnter里先调用父类场景的OnEnter,再做一些本类定制的操作,比如往里面加一个菜单。

场景是可以让切换的,CCDirector随叫随到(通过CCDirector::sharedDirector()函数),你不叫,他不来,所以可以定义类似这样的操作virtual void runThisTest(); 该函数里面定义是:

    CCLayer* pLayer = new DrawPrimitivesTest();
    addChild(pLayer);
    pLayer->release();

    CCDirector::sharedDirector()->replaceScene(this);

       8.布景层CCLayer

       往往我们绘画操作,还有精灵布置操作,可以在CCLayer类里(或者我们自定义的继承自CClayer的类)里操作,把它们分别写在一个绘画函数里,如绘画操作virtual void draw();  精灵布置操作 void centerSprites(unsigned int numberOfSprites);     之类的。当然布景层也可以添加菜单CCMenu,菜单再添加各个菜单项CMenuItem。

        setTouchEnabled(true);可以控制响应是否触屏事件。 默认是m_bIsTouchEnabled = false。这些和触屏相关的代码都实现在CCLayer类中,还有它的其中一个父类CCTouchDelegate里。。。CCLayer对CCTouchDelegate改写了不少触屏相关的函数。

          9.学习一个新建工程,首先要理解新建工程的classes目录里只有那么几个头文件和源文件,却能运行用上引擎的所有功能,因为这些文件包括了其他工程(用于生成dll,lib的工程)的头文件,经过vs编译器展开后,自然就相当于写进了这些头文件了。但是实现去哪找呢,所以新建工程的libs目录会有如此多的dll(新建工程时从其他地方拷贝过来的),所以在libs里找实现。这样一个工程就串起来了,表面上那么微小,就4个文件,但是却能实现引擎所有功能。也就是说,如果自己写一个工具类,比如SpriteHelper,最好放到所用工程里去,如果放到外面的工程,那么会找不到实现。要么就写一个函数好了,放弃写工具类。

        10.差不多该动手实践了,先实现一个 “人物走动+场景移动”的动画。

参考地球人阻止不了程序猿学习了系列http://www.baidu.com/s?word=%E5%9C%B0%E7%90%83%E4%BA%BA%E5%B7%B1%E9%98%BB%E6%AD%A2%E4%B8%8D%E4%BA%86%E7%A8%8B%E5%BA%8F%E7%8C%BF%E4%BB%AC%E5%AD%A6%E4%B9%A0cocos2d-x%E4%BA%86&tn=sitehao123&ie=utf-8

老G的经典博客http://4137613.blog.51cto.com/4127613/759610