[译]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: A Sequence of a Spawn with a RotateBy with a another Sequence, 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/

posted @ 2010-02-05 21:49  AlexLiu  阅读(2973)  评论(1编辑  收藏  举报