[译]cocos2d Best Practices 最佳实践
cocos2d Best Practices
Improving performance 提高性能
-
使用这个向导: performance tests
-
在Xcode中关闭thumb编辑
-
Thumb 代码要比non-thumb代码慢很多
-
-
Director:
-
使用
FastDirector
.FastDirector
不需要垂直同步. 要比普通的Director快很多
-
// must be called before any other call to the director [Director useFastDirector];
-
-
如果使用
Director
会有一个1/240的等待
-
// If you are using "Normal" Director you could set a very low interval [[Director sharedDirector] setAnimationInterval:1/240.0];
-
如何可能的话如下使用:
-
使用
AtlasSprite
替换Sprite
-
使用
BitmapFontAtlas
或者LabelAtlas
替代Label
-
使用
TileMapAtlas
而放弃tiles
-
Atlas这个版本提供的更快的实现,减少的代码的开销和复杂度。Atlas版本使用AtlasManager保存一个很大的图片在一个Frame里面,每一个在Fram框架里面的对象,是框架里面大的图片的引用。它保存了纹理的个数和OpenGLES加速的调用。
Atlas是一本说明书或者是表格,在这个内容里面,意味着它有一个很大的图片,可以读取到openGL的纹理里面,实际上保存了一系列的小图片。
-
如果可能的话使用4-bit 或者是 16-bit 纹理
-
16-bit textures for PNG/GIF/BMP/TIFF images
-
[Texture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA4444]; // add this line at the very beginning
-
-
4-bit 或者 2-bit纹理: 使用PVRTC纹理.
-
Sprite *sprite = [Sprite spriteWithFile: @"sprite.pvr"];
-
-
使用32-bit 纹理当作最后选择
-
Reducing Memory 减少内存开销
-
使用16-bit or 4-bit 纹理
-
使用
TextureMgr
-
TextureMgr
缓存所有的图片 -
Even when the image is not used anymore, it will remain in memory
-
从内存中移除的话有以下几种方法:
-
// textures with retain count 1 will be removed // 在Sence的最后使用这个方法消除没用的对象#dealloc method [[TextureMgr sharedTextureMgr] removeUnusedTextures]; // since v0.8 // 从一个特定的texture清空缓存 Texture2D *texture = [sprite texture]; [[TextureMgr sharedTextureMgr] removeTexture: texture]]; // available in v0.7 too // 移除所有的texture... 当收到一个内存的警告的时候 [[TextureMgr sharedTextureMgr] removeAllTextures]; // available in v0.7 too
Timers 计时器
-
尽量别去使用COCOS里面的
NSTimer
. 而使用cocos2d自带的scheduler. -
如果你使用了scheduler, 你将会有:
-
自动暂停和恢复.
-
when the Layer (Scene, Sprite, CocosNode) enters the stage the timer will be automatically activated, and when it leaves the stage it will be automatically deactivated.
-
Your target/selector will be called with a delta time
-
/**********************************************************/ //接下来这个做法是OK的
/**********************************************************/ -(id) init { if( (self=[super init] ) ) { // schedule timer [self schedule: @selector(tick:)]; [self schedule: @selector(tick2:) interval:0.5]; } return self; } -(void) tick: (ccTime) dt { // bla bla bla } -(void) tick2: (ccTime) dt { // bla bla bla } /**********************************************************/ // 以下是最好不要用的方式
/**********************************************************/ // Why BAD ? // 为什么不好?因为你不能让它自动停止. -(void) onEnter { [super onEnter]; timer1 = [NSTimer scheduledTimerWithTimeInterval:1/FPS target:self selector:@selector(tick1) userInfo:nil repeats:YES]; timer2 = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(tick2) userInfo:nil repeats:YES]; } -(void) onExit { [timer1 invalidate]; [timer2 invalidate]; [super onExit]; } -(void) tick { // bla bla bla } -(void) tick2 { // bla bla bla }
draw vs update 绘制和更新
-
try not to update any state variable inside the draw selector. 不要在draw selector里面更新变量的状态
-
try not to draw anything inside a scheduled selector 不要在scheduled selector 里面绘制任何东西
-
Instead update the state variables inside a scheduled selector. 最好在scheduled selector进行状态变量的更新
-
Instead draw everything inside the draw selector 在 draw selector 里面绘制
-
If you update state variables inside the draw selector, the pause/resume won’t work as expected.
-
If you draw something inside a scheduled selector, it can’t be transformed 如果你在scheduled selector里面绘制,那么他不能被转变
-
draw is called every frame
-
scheduled selectors can be called with any frame rate, but no more frequently than the application’s FPS rate.scheduled selectors可以被任何一个frame调用,但是没有应用的FPS 调用率高。
/**********************************************************/ // 以下这代码很OK /**********************************************************/ -(void) draw { [item draw]; // OK: DRAW INSIDE DRAW } -(void) tick:(ccTime) dt { item.position = dt * finalPosition; // OK, UPDATE STATE IN SCHEDULED SELECTOR } 译者总结:最好在draw方法里面调用draw
在Scheduled Selector里面使用Update
/**********************************************************/ // 以下代码很查BAD 1 /**********************************************************/ -(void) draw { dt = [self calculateDelta]; // DONT UPDATE STATE IN DRAW. item.position = dt * finalPosition; // Pause won't work [item draw]; } 译者总结:不要在Draw里面调用update
而停止不会工作
/**********************************************************/ // 又是一段烂代码 2 /**********************************************************/ -(void) tick:(ccTime) dt { item.position = dt * finalPosition; [item draw]; // <--- DON'T DRAW IN SCHEDULED SELECTOR // because transformations won't alter your image }
译者总结:不要在SCHEDULED SELECTOR里面使用draw方法
因为transformations不会改变图片
Director flow control
-
使用
replaceScene
而不是pushScene
-
pushScene
很方便但是会把scene 推到内存, iPhone里面,内存是在是太宝贵了.
// 减少把SCENES推向内存堆栈
-(void) mainMenu() { // etc [[Director sharedDirector] pushScene: gameScene]; } // 堆栈: // . game <-- running scene // . mainMenu -(void) game { [[Director sharedDirector] pushScene: gameOverScene]; } // stack: // . gameOver <-- running scene // . game // . mainMenu -(void) showGameOver { [[Director sharedDirector] pushScene: hiScoreScene]; } // stack: // . scores <-- running scene (4 pushed scenes... expensive) // . gameOver // . game // . mainMenu
Creating Nodes (Sprites, Labels, etc..) 创建节点(精灵,标签等)
-
如果可能的话,在selector里面创建CocosNode 对象(精灵,标签,层等)或者任何其他一种对象,尽量不要在Draw函数和里面初始化
-
节点的创建会有非常大的开销,尽量进行预创建
-
另一方面,对内存小心操作,不要造成里面有很多没必要的对象
/**********************************************************/ // OK, 很多时候如此使用 /**********************************************************/ -(id) init { // etc... sprite1 = [Sprite1 create]; // <-- 通常情况下如此创建 // etc... } -(void) tick: (ccTime) dt { // etc... if( someThing ) { [sprite1 show]; // <--- 如果你并不经常使用的话,那么内存就浪费了 } } /**********************************************************/ // BAD, 这样的话很不好 /**********************************************************/ -(void) tick: (ccTime) dt { // etc... if( someThing ) { sprite = [Sprite1 create]; // <--- 我们昂贵的内存开销啊 [sprite1 show]; //... [sprite1 release]; // <- 至少内存被释放了 } }
Hierarchy of Layers 层的阶级
-
千万别创建一个有很多阶的层,尽量少如此创建
Actions
-
It is expensive to create certain actions, since it might require a lot of
malloc()
. For example: ASequence
of aSpawn
with aRotateBy
with a anotherSequence
, etc… is very expensive. -
So try to reuse actions.
-
Once the action is used, save it for later if you know you will execute that type of action again. Then, instead of allocing a new action, you can just initialize it.
这个放在末尾:省的爬虫盗了没出处。
译者:Alexliu(alex dotNet Learning)
:http://alexliu.cnblogs.com/
作者:Alexliu(alex dotNet Learning)
出处:http://alexliu.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,转载请注明。并且保留文章链接。否则保留追究法律责任的权利。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步