【问题标题】:Redrawing GameHUD multiple times causes cocos2d frame rates to drop significantly多次重绘GameHUD导致cocos2d帧率明显下降
【发布时间】:2011-10-31 16:28:12
【问题描述】:

我目前正在用cocos2d为iPhone构建一个游戏,遇到以下问题:

我有一个名为 GameHUD 的单例类,它在当前关卡场景前显示一个 HUD。偶尔我希望重新绘制 HUD,因此它会根据当前游戏状态进行相应更改。问题是我重绘 HUD 越频繁,帧速率下降得越多。

我猜我未能发布一些资源,但无法弄清楚我必须发布哪些资源。 (我对内存管理很陌生。我知道我必须释放使用以下关键字之一创建的对象:“new”、“alloc”、“copy”或“retain”。但 cocos2d 主要生成自动释放对象,因此我不能手动释放它们。如果我错了,请纠正我;))

//static, so it can be called from other classes
+(void)redrawGameHUD{

CGSize winSize = [CCDirector sharedDirector].winSize;

//get reference to background-sprite
CCSprite *background = [[[GameHUD class] sharedHUD] towerBackground];

//remove the child from the HUD, if it exists
[[[GameHUD class] sharedHUD] removeChild:background cleanup:YES];

//create sprite containing the background-image
background = [CCSprite spriteWithFile:@"background.png"];

//add background image to HUD
[[[GameHUD class] sharedHUD] addChild:background];

//load images that should be displayed into an array
NSArray *images = [NSArray arrayWithObjects:@"image1.png", @"image2.png", @"image3.png", @"image4.png", nil];

//remove sprites from HUD before drawing them again.
//the "buildable" array contains all those already drawn sprites
for (CCSprite *entity in [[[GameHUD class] sharedHUD] buildable]) {
    [[[GameHUD class] sharedHUD] removeChild:entity cleanup:YES];
}
[[[[GameHUD class] sharedHUD] buildable] removeAllObjects];

//loop over sprites, initialize them and add them to the HUD
for(int i = 0; i < images.count; ++i) {

    NSString *image = [images objectAtIndex:i];
    CCSprite *sprite = [CCSprite spriteWithFile:image];

    //add sprite to HUD and memorize them in the "buildable" array
    [[[GameHUD class] sharedHUD] addChild:sprite];
    [[[[GameHUD class] sharedHUD] buildable] addObject:sprite];
}   

}

所以每次调用此方法时,帧速率都会下降一点并保持下降..有人可以告诉我,我做错了什么吗?谢谢。

【问题讨论】:

  • 每次重绘时是否使用不同的图像?你能准确解释一下你想对 HUD 做什么吗?重绘时到底发生了什么变化?

标签: iphone performance cocos2d-iphone ccsprite


【解决方案1】:

尽量不要在运行时创建和删除精灵,即尽量避免频繁这样做:

[CCSprite spriteWithFile:@"background.png"];

这为精灵分配了新的内存,当你创建一个新的精灵时,会有很多事情发生在幕后。当然,您正在发布已经存在的精灵。所有这些都是不必要的。

在您的 redrawGameHUD 方法中,我看不出您为什么要重新创建精灵。精灵每次都使用相同的图像。那么为什么不保留旧的呢?除非您在将代码发布到问题中之前对其进行了编辑,否则无需删除并重新创建 HUD 精灵。

您可能还想为所有 HUD 精灵图像创建纹理图集。其一,您可以使用 CCSpriteBatchNode 通过一次绘制调用渲染所有 HUD 精灵。其次,当您确实想为现有精灵分配新纹理时,您只需更改该精灵的 CCSpriteFrame,而不是丢弃该精灵并重新创建它。

还有什么困扰我的,你继续写这个:

[[[GameHUD class] sharedHUD] addChild:sprite];

首先,这与编写以下内容相同,绝对不需要向班级发送消息(让我想知道您是从哪里找到的?):

[[GameHUD sharedHUD] addChild:sprite];

由于您多次执行此操作,您应该保留 GameHUD 的临时本地副本,这再次删除了一些不必要的 Objective-C 消息:

GameHUD* gameHUD = [GameHUD sharedHUD];
// from now on use gameHUD instead of [GameHUD sharedHUD]
[gameHUD addChild:sprite];

这是对循环特别好的建议,因为这样做:

for (CCSprite *entity in [[[GameHUD class] sharedHUD] buildable])

将为可构建数组中的每个实体发送两条额外的消息(class 和 sharedHUD)。这些额外的调用很快就会增加,尽管它们肯定不足以解决您正在经历的帧速率下降。

您还不必要地将所有 HUD 精灵保留在“可构建”数组中。为什么不使用 cocos2d 使用的已经存在的 children 数组呢?只需使用相同的标签添加每个“可构建”的 HUD 精灵,例如 123。

[gameHUD addChild:sprite z:0 tag:123];

如果您需要对所有“可构建”精灵做一些事情,您可以像这样迭代孩子:

CCNode* node;
CCARRAY_FOREACH([gameHUD children], node)
{
   if (node.tag == 123)
   {
      CCSprite* buildable = (CCSprite*)node;
      // do stuff with buildable sprite ...
   }
}

再次,这避免了可构建数组中不必要的添加、保留、删除和释放对象。而且您可以确保不会意外从节点层次结构中删除精灵,但不会从可构建数组中删除,反之亦然。

我想以一个假设作为结尾:在您的代码中,我看到了一种普遍趋势,即您做了许多不必要的额外事情。所以我猜这在整个项目中都是如此。您可能想回去问问自己(最好:找出)您让设备执行的其他一些不必要的事情。

【讨论】:

  • 谢谢,这是一些很棒的建议!我意识到该代码部分(可能还有整个项目)还有很多需要改进的地方。我不记得我在哪里拿起了 [GameHUD class] 调用。我认为我认为这是访问类中的静态方法..标签的好主意,在这种情况下没有想到它们..
【解决方案2】:

我 90% 确定您正在 iPhone 模拟器上进行测试,对吗?

如果是,请记住,您无法在模拟器上正确分析 OpenGL 应用程序。性能变化太大。

在真机上测试,再次检查帧率。

如果没有,那么您在其他地方遇到了问题。除非您的图像是 5000x5000 像素之类的,否则在此方法中完成的所有处理都是微不足道的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-04
    相关资源
    最近更新 更多