SKAction — динамика в игре — Часть 7

Использование имен SKAction
Как правило, вы не можете видеть, какие SKAction выполняет узел и если вы хотите удалить действия, необходимо удалить их все. Поэтому SKAction можно задать имя. И с помощью имени вы можете посмотреть выполняется ли действие или нет, а также по имени вы можете удалить действие. Также вы можете найти и заменить SKAction в узле по имени. Следующий кусок кода показывает как добавлять SKAction с именем-ключом. Все просто.

[SKAction *moveNodeRight = [SKAction moveByX:100.0 y:0.0 duration:1.0];
[spaceship runAction: moveNodeRight withKey:@"ignition"];

runAction: withKey: метод для запуска действия с именем-ключом. Если действие с тем же ключом уже выполняется, он удаляется перед добавлением нового действия.
Также есть еще полезные методы:
actionForKey: метод запускает действие по имени, если оно уже запущено, убивает запущенное и запускает.
removeActionForKey : метод удаляет действие по имени

Создание SKAction, которые выполняются другие SKAction
Sprite Kit предоставляет множество стандартных типов SKAction, которые изменяют свойства узлов в вашей сцене. С их помощью реально можно сделать многое, НО действия показывают свою реальную силу, когда вы объедините их. Комбинируя SKAction, можно создавать сложные и выразительные эффекты анимации. Итак:
— Sequence action, это действие имеет несколько дочерних действий. Каждое действие в последовательности начинается после окончания предыдущего действия.
— Group action, также имеет несколько дочерних действий. Все действия, хранимые в группе начают выполнение одновременно.
— Repeating action, повторяет действие после завершения.

Теперь о каждой группе подробнее:
Sequence action
Все очень просто, действия которые надо выполнить задаются массивом, и выполняются друг за другом, вот код:

SKAction *moveUp = [SKAction moveByX:0 y:100.0 duration:1.0];
SKAction *zoom = [SKAction scaleTo:2.0 duration:0.25];
SKAction *wait = [SKAction waitForDuration: 0.5];
SKAction *fadeAway = [SKAction fadeOutWithDuration:0.25];
SKAction *removeNode = [SKAction removeFromParent];

SKAction *sequence = [SKAction sequence:@[moveUp, zoom, wait, fadeAway, removeNode]]; [node runAction: sequence];

Как видите ничего сложного. Далее параллельное выполнение )

Group action
Группы действий используют когда надо синхронизировать несколько действий и выполнять их одновременно. Следующий код делает эффект колеса которое катится. Т.е. колесо перемещается и вращается.

SKSpriteNode *wheel = (SKSpriteNode *)[self childNodeWithName:@"wheel"];
CGFloat circumference = wheel.size.height * M_PI;
SKAction *oneRevolution = [SKAction rotateByAngle:-M_PI*2 duration:2.0];
SKAction *moveRight = [SKAction moveByX:circumference y:0 duration:2.0];
SKAction *group = [SKAction group:@[oneRevolution, moveRight]]; [wheel
runAction:group];

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

[sprite setScale: 0];
  SKAction *animate = [SKAction animateWithTextures:textures
  timePerFrame:2.0/numberOfTextures];
  SKAction *moveDown = [SKAction moveByX:0 y:-200 duration:2.0];
  SKAction *scale = [SKAction scaleTo:1.0 duration:1.0];
  SKAction *fadeIn = [SKAction fadeInWithDuration: 1.0];
  SKAction *group = [SKAction group:@[animate, moveDown, scale, fadeIn]];

Тут ничего сложного нет, действия scale и fadeIn закончатся через 1 секунду, а moveDown через 2 секунды и соответственно вся группа закончит выполнение через 2 секунды. Далее репиты.

Repeating action
И здесь все просто. Любой SKAction можно запустить единоразово, как выше в коде было — runAction:, а можно запустить энное количество раз, т.е. при завершении действия оно будет запускаться заново и так заданное количество раз. И еще один вариант запуска действий — запуск безлимитное количество раз (пока узел в котором запускается действие на сцене). И вот код:

SKAction *fadeOut = [SKAction fadeOutWithDuration: 1];
SKAction *fadeIn = [SKAction fadeInWithDuration: 1];
SKAction *pulse = [SKAction sequence:@[fadeOut,fadeIn]];

SKAction *pulseThreeTimes = [SKAction repeatAction:pulse count:3];
SKAction *pulseForever = [SKAction repeatActionForever:pulse];

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

И последний совет по SKAction — создавайте SKAction один раз и применяйте несколько раз. Так вы будете сильно экономить ресурсы )

Далее будет большая глава о правильном построении сцены и работающий код.

Если у вас есть вопросы или что-то не получается, пишите в комментариях — отвечу.

  • devacc

    Привет, Николай! Все получается и работает. Будет ли продолжение, а то Wenderlich вечно какие-то либы подключает?

    • floMaster

      Привет! Продолжение делаем, но к сожадению только в свободное время ( В эти выхи еще сделаю пару статей по спрайткиту

  • erboluz

    вот так я добавляю новый спрайт

    NSMutableArray *carAnimation = [NSMutableArray array];
    SKTextureAtlas *carAtlas = [SKTextureAtlas atlasNamed:name];

    int numImages = carAtlas.textureNames.count;

    for (int i = 1; i <= numImages; i++) {
    NSString *textureName = [NSString stringWithFormat:@"%@_%d", name, i];
    SKTexture *frame = [carAtlas textureNamed:textureName];
    [carAnimation addObject:frame];
    }

    carAnimationFrames = carAnimation;
    SKTexture *temp = carAnimationFrames[0];
    car = [SKSpriteNode spriteNodeWithTexture:temp];
    car.position = position;
    [scene addChild:car];

    а потом вот так вызываю анимацию

    [car runAction:[SKAction repeatActionForever:
    [SKAction animateWithTextures:carAnimationFrames timePerFrame:0.1f resize:NO restore:YES]] withKey:[NSString stringWithFormat:@"%@_animation", name]];

    затем отменяю ее так

    [car removeAllAction];

    но проблема в том что вообще все пропадет и становиться пусто — хотелось что бы спрайт первый с картинкой оставался.
    что я делаю не так?

    • floMaster

      Надо смотреть больше кода. Попробовал твой кусок и после removeAllAction спрайт остается на месте и замирает.