Перерисовка GameHUD несколько раз приводит к значительному падению частоты кадров cocos2d - PullRequest
0 голосов
/ 31 октября 2011

В настоящее время я создаю игру для iPhone с cocos2d и имею следующую проблему:

У меня есть одноэлементный класс GameHUD, который отображает HUD перед сценой текущего уровня. Время от времени я хочу, чтобы HUD перерисовывался, поэтому он меняется в соответствии с текущим состоянием игры. Проблема в том, что чем чаще я перерисовываю HUD, тем больше падает частота кадров.

Я предполагаю, что мне не удалось выпустить некоторые ресурсы, но я не могу понять, какие из них мне нужно выпустить. (Я довольно новичок в управлении памятью. Я понимаю, что мне нужно освобождать объекты, созданные с одним из следующих ключевых слов: «новый», «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];
}   

}

Так что каждый раз, когда вызывается этот метод, частота кадров немного падает и остается на низком уровне. Может кто-нибудь сказать, пожалуйста, что я делаю не так? Благодаря.

Ответы [ 2 ]

2 голосов
/ 01 ноября 2011

Старайтесь не создавать и не удалять спрайты во время выполнения, т. Е. Стараться избегать этого часто:

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

Это выделяет новую память для спрайта, и при создании нового спрайта происходит довольно много событий. И конечно вы выпускаете уже существующие спрайты. Все это не нужно.

В вашем методе redrawGameHUD я не вижу признаков того, почему вы действительно хотите создавать спрайты заново. Спрайты используют одни и те же изображения каждый раз. Так почему бы просто не оставить старые? Если вы не редактировали код до того, как опубликовали его в вопросах, нет необходимости удалять и заново создавать спрайты HUD.

Вы также можете создать атлас текстуры для всех изображений спрайтов HUD. Например, вы можете отобразить все спрайты HUD одним вызовом отрисовки, используя CCSpriteBatchNode. Во-вторых, всякий раз, когда вы хотите назначить новую текстуру существующему спрайту, вы просто изменили бы 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 в массиве "buildable". Почему бы не использовать уже существующий дочерний массив, который использует cocos2d? Просто добавьте каждый 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 ...
   }
}

Опять же, это позволяет избежать ненужного добавления, сохранения, удаления и освобождения объектов в создаваемом массиве. И вы можете быть уверены, что вы случайно не удалите спрайты из иерархии узлов, но не создаете массив или наоборот.

Я хотел бы закончить с предположением: в вашем коде я увидел общую тенденцию, что вы делаете много лишних вещей без необходимости. Я предполагаю, что это так на протяжении всего проекта. Возможно, вы захотите вернуться и спросить себя (лучше: выяснить), какие еще вещи, которые вы выполняете на устройстве, являются довольно ненужными.

0 голосов
/ 01 ноября 2011

Я на 90% уверен, что вы тестируете это на симуляторе iPhone, не так ли?

Если да, то имейте в виду, что вы не можете правильно профилировать приложение OpenGL на симуляторе.Производительность слишком переменная.

Протестируйте ее на реальном устройстве и проверьте частоту кадров еще раз.

Если нет, значит, у вас проблема в другом месте.Вся обработка, выполняемая в этом методе, тривиальна, если только ваши изображения не имеют разрешение 5000x5000 пикселей или что-то в этом роде.

...