#iphone #performance #cocos2d-iphone #ccsprite
#iPhone #Производительность #cocos2d-iphone #ccsprite
Вопрос:
В настоящее время я создаю игру для iPhone с cocos2d и сталкиваюсь со следующей проблемой:
У меня есть одноэлементный класс GameHUD, который отображает HUD перед сценой текущего уровня. Время от времени я хочу, чтобы HUD перерисовывался, чтобы он менялся в соответствии с текущим статусом игры. Проблема в том, что чем чаще я перерисовываю HUD, тем больше падает частота кадров.
Я предполагаю, что мне не удается освободить некоторые ресурсы, но не могу понять, какие из них я должен освободить. (Я довольно новичок в управлении памятью.. Я понимаю, что мне нужно освободить объекты, созданные с одним из следующих ключевых слов: «создать», «выделить», «скопировать» или «сохранить». Но 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];
}
}
Поэтому при каждом вызове этого метода частота кадров немного падает и остается низкой.. Может кто-нибудь, пожалуйста, скажите мне, что я делаю не так? Спасибо.
Комментарии:
1. Вы используете разные изображения каждый раз при перерисовке? Можете ли вы точно объяснить, что вы пытаетесь сделать с HUD? Что именно меняется при перерисовке?
Ответ №1:
Старайтесь не создавать и не удалять спрайты во время выполнения, т.Е. старайтесь избегать частого выполнения:
[CCSprite spriteWithFile:@"background.png"];
Это выделяет новую память для спрайта, и при создании нового спрайта за кулисами происходит немало событий. И, конечно же, вы выпускаете уже существующие спрайты. Во всем этом нет необходимости.
В вашем методе redrawGameHUD я не вижу никаких указаний на то, почему вы на самом деле хотите создать спрайты заново. Спрайты каждый раз используют одни и те же изображения. Так почему бы просто не сохранить старые? Если вы не отредактировали код до того, как опубликовали его в вопросах, нет необходимости удалять и заново создавать спрайты HUD.
Вы также можете создать атлас текстур для всех изображений спрайтов HUD. Во-первых, затем вы можете визуализировать все HUD-спрайты одним вызовом draw, используя 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 в «сборном» массиве. Почему бы не использовать уже существующий дочерний массив, который использует 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 ...
}
}
Опять же, это позволяет избежать ненужного добавления, сохранения, удаления и освобождения объектов в сборном массиве. И вы можете быть уверены, что случайно не удалите спрайты из иерархии узлов, но не из сборного массива, или наоборот.
В заключение я хотел бы сделать предположение: в вашем коде я увидел общую тенденцию к тому, что вы делаете много лишних вещей без необходимости. Так что я предполагаю, что это имеет место во всем проекте. Возможно, вы захотите вернуться назад и спросить себя (лучше: выяснить), какие другие функции, которые выполняет устройство, вам не нужны.
Комментарии:
1. спасибо, это отличный совет! Я понимаю, что в этом разделе кода (и, вероятно, во всем проекте) есть что улучшить.. Я не помню, где я получил вызов [GameHUD class].. Я думаю, что я рассматривал это как единственный способ получить доступ к статическому методу из его класса .. отличная идея с тегами, не подумал о них в данном случае..
Ответ №2:
Я на 90% уверен, что вы тестируете это на симуляторе iPhone, я прав?
Если да, то имейте в виду, что вы не можете правильно профилировать приложение OpenGL в симуляторе.. Производительность слишком изменчива.
Протестируйте его на реальном устройстве и еще раз проверьте частоту кадров.
Если нет, то у вас проблема в другом месте. Вся обработка, выполняемая этим методом, тривиальна, если только ваши изображения не имеют размер 5000×5000 пикселей или что-то в этом роде..