Работа с текстурами — Часть 5

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

— Использовать одну и ту же текстуру для множества спрайтов.
— Изменение текстуры спрайта после его создания.
— Анимация спрайта из серии текстур.
— Создание текстуры из данных, которые не хранятся в приложении.
— Создание текстуры из узлов. Например, вы можете сделать скриншот вашего экрана, чтобы показать игроку, после того как он завершил уровень.
— Предварительная загрузка текстур в память, прежде чем показать на сцене.

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

Создание текстуры из изображения которое хранится в приложении
Это очень просто. Код явно создает объект текстуры. Затем создает много ракет с той же текстурой.

SKTexture *rocketTexture = [SKTexture textureWithImageNamed:@"rocket.png"];
for (int i= 0; i< 10; i++)
{
    SKSpriteNode *rocket = [SKSpriteNode spriteNodeWithTexture:rocketTexture];
    rocket.position = [self randomRocketLocation];
    [self addChild: rocket];
}

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

Использование Атласов текстур
Некоторые изображения текстур связаны между собой в программе, но находятся в разных файлах. Например:
Кадры для анимации персонажа
Плитки которыми необходимо замостить уровень
Элементы пользовательского интерфейса - кнопки, переключатели и пр.

Если каждую текстуру рассматривать как отдельный объект, то Sprite Kit и графическое оборудование начинают «напрягаться» и от этого может пострадать производительность вашего игры. В частности, Sprite Kit должен сделать хотя бы одну прорисовку каждой текстуры. Чтобы избежать нескольких лишних прорисовок, Sprite Kit использует атласы текстур в которые собираются связанные между собой текстуры. Вы указываете , какие изображения должны быть собраны вместе, и Xcode строит атлас текстуры автоматически. Затем, когда ваша игра загружает атлас текстуры, Sprite Kit управляет всеми изображениями внутри атласа, как если бы они были одной текстурой. В тоже время вы продолжаете использовать объекты SKTexture для доступа к элементам, содержащимся в атласе.

Создание Атласов текстур
Xcode может автоматически построить атласы текстур для вас из коллекции изображений. При создании атласов текстур, вам надо найти баланс между сбором слишком большого количества текстур или слишком малого. Если включить в атлас слишком много изображений, то большие объемы текстурных данных сразу загрузятся в память, это может отразится быстродействии приложения. Вы можете легко переключаться между различными конфигурациями атласов. Так что экспериментируйте с различными конфигурациями ваших атласов текстур и выбрайте комбинацию, которая дает вам лучшую производительность.

Загрузка текстуры из атласа текстур
Для того чтобы работать с атласами текстур, используется класс SKTextureAtlas. Используйте имена файлов изображений, хранящихся в атласе для просмотра отдельных текстур. Код ниже показывает пример этого. Он использует атлас текстур, который содержит несколько кадров анимации для монстра. Код загружает эти кадры и сохраняет их в массиве . В реальном проекте, необходимо добавить папку monster.atlas с четырьмя файлами изображений.

SKTextureAtlas *atlas = [ SKTextureAtlas atlasNamed:@"monstr"];
SKTexture *f1 = [atlas textureNamed:@"monstr-walk1.png"];
SKTexture *f2 = [atlas textureNamed:@"monstr-walk2.png"];
SKTexture *f3 = [atlas textureNamed:@"monstr-walk3.png"];
SKTexture *f4 = [atlas textureNamed:@"monstr-walk4.png"];
NSArray *monsterWalkTextures=@[f1, f2, f3 , f4 ] ;


Создание текстуры из части текстуры
Если у вас уже есть объект SKTexture, вы можете создавать новые текстуры, которые ссылаются на часть первой текстуры. Такой подход является эффективным, потому что новые текстурные объекты ссылаются на одни и те же данные текстуры в памяти. Как правило, этот подход используется, если ваша игра уже имеет свой собственный формат атласа текстур. В этом случае , вы несете ответственность за хранения координат для отдельных изображений, хранящихся на таможенных атласа текстур. Этот код показывает, как извлечь часть текстуры.
img8

SKTexture *texture1 = [SKTexture textureWithRect:CGRectMake(0.0,0.0,0.5,0.5) inTexture:cornerTextures];

Другие способы создания текстур
В дополнение к уже показанным способам создания текстур, их можно создавать из других источников :
Используйте методы SKTexture init.. для создания текстур из различных источников.
Используйте метод SKView textureFromNode для создания текстуры из SKNode и всех его видимых потомков-узлов.

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

SKAction *walkAnimation = [SKAction animateWithTextures:monsterWalkTextures timePerFrame:0.1];
[monster runAction:walkAnimation];

Sprite Kit обеспечивает возможности, которые позволяют анимировать или изменять текстуру спрайта. Это не накладывает специфических требований на дизайн. Это означает, что вы должны определить, какие виды анимации будут у вашего спрайта, затем создать свои собственные SKAction каждой анимации и затемпереключаться между этими SKAction во время выполнения. Например для монстра можно сделать анимации прогулки, ожидания, боя, смерти и победы. И во время игры переключаться между этими анимациями.

Предварительная загрузка текстур в память
Основным преимуществом Sprite Kit является то, что он выполняет почти все управление памятью за вас, автоматически. При подготовке нового кадра анимации, Sprite Kit определяет, необходима ли текстура для визуализации текущего кадра. Если текстура необходима, но не готова к показу, Sprite Kit загружает текстуру из файла и готовит для передачи в графическое «железо». Этот процесс происходит автоматически в фоновом режиме, но на это тратятся ресурсы. Если сразу слишком много текстур необходимо загрузить и преобразовать, то возможно это не удастся сделать в одном кадре, поэтому ваша анимация начнет дергаться. Чтобы избежать этой проблемы, необходимо предварительно загрузить текстуры в памяти, особенно в больших или сложных играх.

Код ниже показывает как работает предварительная загрузка массива объектов SKTexture. Метод
 preloadTextures : withCompletionHandler :  вызывает обработчик завершения после загрузки текстур в память. Это создает сцену и показывает ее. В реальном проекте вам необходимо будет добавить код, для отправки текстур в новую сцену.

[SKTexture preloadTextures:textureArrayForLevel1 withCompletionHandler:^
      {
          GamePlayScene* gameScene = [[GamePlayScene alloc] initWithSize:CGSizeMake(768,1024)];
          SKView *spriteView = (SKView *) self.view;
          [spriteView presentScene: gameScene];
}];

Поскольку вы пишите игру, вы должны знать когда вам понадобятся новые текстуры. Вот несколько небольших советов:
В небольшой игре, вы сможете предварительно загрузить все свои текстуры, во время запуска приложения, а затем сохранить их в памяти.
Для большой игры, вам может потребоваться разделить текстуры на уровни или темы. Когда игрок начинает новый уровень, вы предварительно загружаете все текстуры для этого уровня. Когда игрок заканчивает уровень, текстуры не нужные для следующего уровня выгружаются из памяти. Во время загрузки текстур для уровня вы можете вывести на экран отвлекающую заставку с надписью Loading...
Если игра нуждается в бОльшем количестве текстур, чем может поместиться в память, необходимо загружать текстуры динамически. Например, в гоночной игре можно загружать текстуры в фоновом режиме, вытесняя самые старые текстуры для трека.

Удаление текстур из памяти
После того как текстура загружается в память графического оборудования, она остается в памяти до тех пор, пока объект SKTexture не будет удален. Это означает, что между уровнями, вам может потребоваться убедиться в том что объект удаляется. Удаление объекта SKTexture возможно при удалении всех ссылок на него, в том числе :
Все ссылки на текстуры из SKSpriteNode и SKEffectNode в вашей игре.
Любые ссылки в собственном коде
Объект SKTextureAtlas, который был использован для создания объекта текстуры.

Про текстуры вообщем все. Главное грузите их заранее, чтобы не лагала ваша игра. Дальше расскажу более подробно про SKAction, с помощью них в игру приходит движуха и разные эффекты.