一、音乐音效的播放
- //添加SimpleaudioEngine.h
- #include "SimpleAudioEngine/SimpleAudioEngine.h"
- //播放背景音乐的代码
- SimpleAudioEngine::getSharedEngine()->playBackgroundMusic("background-music-aac.mp3");
- //播放音效的代码
- SimpleAudioEngine::getSharedEngine()->playEffect("pew-pew-lei.wav");
苹果自己音乐文件的格式caf。cocos2d-x下的SimpleAudioEngine对mp3和wav这两种大众格式都支持。
二、场景类的初始化工作
在objc的头文件中,可以不声明类成员函数,而直接在.m文件里实现。但是cpp不允许这样做。所以coco2d-x里面有一个init的方法。提供了累世的功能,所有继承自CCNODE的都有init方法。
我马上想到了,既然父类都有了,我就可以直接从父类继承下来,使用self强制转化为指向自己的对象,这样子类就不用自己实现了。
实际上是不行的,cpp没有self关键字。不能像OC那样直接从父类继承下来靠self关键字变成指向自己的对象。所以我们看到所有类都有一个node()方法,它集合了new,init,autorelease等方法,可以减少调用者的代码量。但是几乎每次都是一样的,所以我们可以使用cocos2d-x提供的一个宏来实现。
LAYER_NODE_FUNC和SCENE_NODE_FUNC。但是如果想使用这两个宏,就必须在派生类里实现bool init()方法。
三、为什么一定要在构造函数结束后调用init()
主要是因为C++构造函数有个缺陷,就是没有返回值。所以我们在C++构造函数异常时只能采取try-catch捕捉。而一般不推荐使用try-catch,主要是开启try-catch支持会使编译后的二进制程序增加不少体积,(我发现android NDK好像也不支持try-catch)。
cocos2d-x采取了现在比较流行的“二阶段构造”的方法,即使用时先调构造函数,再调用init处理初始化逻辑。这种思路不论是在苹果iOS的接口设计(比如[[NSString alloc] init],即二阶段构造)、还是在samsung bada操作系统使用C++类时都是如此。
四、set/get方法
在cocos2dx\include\Cocos2dDefine.h中实现了一系列的宏定义,可以自己看看。
比如有一个CCX_SYNTHESIZE_READONLY宏,可以用来实现了只读的类成员变量,也就是只有get方法。
五、对象释放
建议在CPP的类构造函数里,对所有成员变量初始化,并在构造函数把释放的对象指针初始化为NULL。
retain了一定记得release。对于xxxwithxxx初始化出来的对象,一般会autorelease。不需要自己release。
六、cocos2d-x Direty问题
总是在引擎源代码中遇到Direty问题,主要是因为在引擎中很多时候都会用到一些内存管理等等方面的方法,比如说TextureAtlas大批次渲染的材质类,这个类中存储了一个Texture2D纹理,与Texture2d不同的是,多了一个数组,一个用于告诉程序哪些纹理需要渲染的数组。
具体步骤:
1.首先是AtlasSpriteManager使用一张TextureAtlas初始化,并设定Quad数组的长度
2.往AtlasSpriteManager加入AtlasSprite,这个加入的过程其实只是往AtlasSpriteManager的Quad数组中更新一个Quad
3.渲染的时候使用一张Texture根据Quad数组中的不同值一个个渲染
就像计算机中的cache一样,内存数据被修改,与的地方数据不同时,在cocos2d-x TextureAtlas中的情况数组中的数据改变,与屏幕上的数据不同时,这样的数据叫做“脏数据”,需要重新加载,渲染引擎重新渲染。
direty这个bool值就是控制是否需要重新渲染。
七、update问题
不是Node节点就不能使用scheduleUpdate,并且还有一点很重要,就是node必须调用onEnter函数,使_running为true。
关于Node中update的原理,下面简洁的理顺一下。
1.首先,node注册update回调之前,node在onEnter中有一个关键的变量_running,判断节点是否被添加,在onEnter中赋值为true。
2.接下来是node的void Node::scheduleUpdate()注册回调函数,schedule.cpp中会实现调用目标的update函数。node会被当做元素添加到schedule的哈希表中。
3.director在每帧回调函数中都会去调用schedule的void Scheduler::update(float dt)函数,在Scheduler::update函数中,遍历哈希表,有比较关键的判断代码
if ((! entry->paused) && (! entry->markedForDeletion))
pause由node的_running控制,markedForDeletion为标记删除。
所以,如果只是使用一个比较独立的类,不需要node等等特性的话,自己写吧,简单直接。