0

У меня есть игра с 4 текстурными атласами. Каждый атлас 4096 x 4096 и содержит примерно 300 спрайтов, все ~ 15kb - 50kb. Unoptimised в Texture Packer, они составляют около 2 - 4 МБ каждый, а около половины - при оптимизации.Как оптимизировать рисование из больших файлов SKTextureAtlas с предварительной загрузкой?

Они содержат активы для рисования символов, но я нахожу, что очень медленно нарисовать один символ (около 24 узлов) ~ 0,5 секунды. Это связано с многочисленными вызовами на [atlas textureNamed:textureName]

Чтобы ускорить процесс, я хочу предварительно загрузить атласы. В идеале я бы сохранил их в памяти, поскольку я всегда нуждаюсь в них. Итак, мой первый вопрос: возможно ли это с атласами такого размера? Я попытался позвонить [SKTextureAtlas preloadTextureAtlases:@[MaleFeatureAtlas] withCompletionHandler...], но я получаю сбой без трассировки стека, просто потерянное соединение с устройством.

В настоящее время у меня есть класс AtlasManager, который имеет статические переменные, которые Initialise друг текстурных атласе:

static SKTextureAtlas *MaleFeatureAtlas; 
static SKTextureAtlas *MaleItemAtlas; 
static SKTextureAtlas *FemaleFeatureAtlas; 
static SKTextureAtlas *FemaleItemAtlas; 

@implementation AtlasManager 
{ 
} 

#pragma mark - Initialisation Methods 

+ (void)initialize 
{ 
    MaleFeatureAtlas = [SKTextureAtlas atlasNamed:MaleFeatures]; 
    MaleItemAtlas = [SKTextureAtlas atlasNamed:MaleItems]; 
    FemaleFeatureAtlas = [SKTextureAtlas atlasNamed:FemaleFeatures]; 
    FemaleItemAtlas = [SKTextureAtlas atlasNamed:FemaleItems]; 
} 

Каждый персонаж спрайт имеет экземпляр AtlasManager, но так как SKTextureAtlases статические переменные, я понял, они будут быстро рисовать. Но постоянные звонки на [atlas textureNamed:textureName] действительно замедляют вытягивание. Я сохраняю NSDictionary узлов после рисования, поэтому перерисовка выполняется очень быстро, но исходная ничья занимает слишком много времени. Рендеринг 8 символов, всего более 100 узлов, занимает около 5 секунд.

Таким образом, это подход с одноэлементным режимом лучше, чем использование статических переменных? И разумно ли предварительно загружать атласы такого размера?

ответ

0

Существует много места для разных мнений относительно ваших вопросов. Помня об этом, я предлагаю следующее:

При создании атласа текстуры вы всегда должны планировать заранее то, что действительно необходимо. Например, у вас есть 5 разных видов врагов, но на первом уровне вашей игры только враги №1 и №2. В этом случае вы должны создать атлас текстуры, который содержит только необходимые ресурсы для вашего первого уровня (враг №1 & # 2).

Singleton Плюсы: Централизация всего вашего кода на один класс. Вам нужно всего 1 экземпляр класса. Предотвращает двойную загрузку некоторых активов.

Singleton Cons: Сумма кода может быть подавляющим, если есть много активов для управления.

подклассы Плюсы: Имея весь коду & активов, обрабатываемых в одном классе, характерного для нужд спрайта.

Недостатки подкласса: В некоторых случаях у вас может быть одна и та же анимация или изображение, загруженное несколько раз разными классами. Например, определенный вид взрыва может быть использован одним или несколькими подклассами.

Я предпочитаю использовать одноэлементный подход, потому что мне нравится централизовать мой код. Ниже приведен упрощенный пример того, как я это делаю. Я также использую TexturePacker и использую параметр файла заголовка при создании атласа текстуры. Мой одноэлементный класс называется Animations.

В файле заголовка Animations У меня есть это:

-(void)loadPlayer0Atlas; 
@property (strong) SKTexture *player0_startLeft; 
@property (strong) SKAction *player0_idleLeft; 
@property (strong) SKAction *player0_idleRight; 
@property (strong) SKAction *player0_walkLeft; 
@property (strong) SKAction *player0_walkRight; 

В файле реализации Animations:

-(void)loadPlayer0Atlas { 
    if(self.player0Atlas == nil) { 
     self.player0Atlas = [SKTextureAtlas atlasNamed:PLAYER0ATLAS_ATLAS_NAME]; 
     [SKTextureAtlas preloadTextureAtlases:[NSArray arrayWithObject:self.player0Atlas] withCompletionHandler:^{ 
      [self loadPlayer0Assets]; 
     }]; 
    } else { 
     [[NSNotificationCenter defaultCenter]postNotificationName:@"player0AtlasLoaded" object:self]; 
    } 
} 

-(void)loadPlayer0Assets { 
    self.player0_startLeft = PLAYER0ATLAS_TEX_PLAYERIDLEL__000; 
    self.player0_idleLeft = [SKAction repeatActionForever:[SKAction animateWithTextures:PLAYER0ATLAS_ANIM_PLAYERIDLEL timePerFrame:0.2]]; 
    self.player0_idleRight = [SKAction repeatActionForever:[SKAction animateWithTextures:PLAYER0ATLAS_ANIM_PLAYERIDLE timePerFrame:0.2]]; 
    self.player0_walkLeft = [SKAction repeatActionForever:[SKAction animateWithTextures:PLAYER0ATLAS_ANIM_PLAYERWALKL timePerFrame:0.1]]; 
    self.player0_walkRight = [SKAction repeatActionForever:[SKAction animateWithTextures:PLAYER0ATLAS_ANIM_PLAYERWALK timePerFrame:0.1]]; 

    [[NSNotificationCenter defaultCenter]postNotificationName:@"player0AtlasLoaded" object:self]; 
} 

Приведенный выше код позволяет мне загрузить активы игрока путем вызова метода loadPlayer0Atlas. Этот метод проверяет, был ли атлас уже создан. Если да, в нем указано NSNotification, указывающее это. Если нет, он загружает атлас, присваивает активы свойствам класса, а затем публикует NSNotification.

Назад в класс, который называется loadPlayer0Atlas, вам необходимо зарегистрироваться для NSNotification в методах init или didMoveToView.

[[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(myMethod) 
              name:@"player0AtlasLoaded" 
              object:nil]; 

После того, как уведомление было получено, myMethod может продолжить код зная игрок атлас теперь загружается.

Для хорошего ведения хозяйства не забудьте удалить класс вызова из NSNotifications так:

-(void)willMoveFromView:(SKView *)view { 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
} 

Чтобы ответить на ваш последний вопрос о поджимать атлас. Да, всегда разумно предварительно загружать свой атлас, потому что он обеспечивает более плавную игру. При загрузке активов средняя игра потенциально может привести к задержкам. Просто не забудьте загрузить только те ресурсы, которые вам нужны для сцены, в которой вы сейчас находитесь. Хорошее планирование даст вам хорошие результаты.

+0

Спасибо за подробный ответ. Моя проблема заключается в том, что мои атласы содержат все спрайты, необходимые для создания пользовательских аватаров, и есть потенциально миллионы комбинаций, поэтому в любой момент мне, вероятно, понадобятся все атласы (особенно, если у меня есть более двух символов на экране). С их размером в уме, насколько вы знаете, это должно быть что-то, что можно предварительно загрузить? Или он будет потреблять слишком много памяти? – Smikey

+0

@Smikey - Если у вас есть большое количество возможных комбинаций, значит ли это, что у вас есть текстура для каждой возможной комбинации или у вас есть какой-то другой механизм, который вы используете для этого? – sangony