4
votes

I have a sprite that moves from point A to B. Moving could cause the sprite to go around an object, which means the sprite will go from facing west to north to east.

I store the current facing direction in _facing. I use the A* pathfinding algorithm to build an NSArray of CGPoints. Then I walk the sprite through the points, while changing the texture from a static (standing still) texture to an animated texture. Ultimately this will be more complex, as the sprite "turns" from direction-to-direction, but while I'm learning Objective-C / SpriteKit I'm trying to keep it simple.

Anyways, the problem is that I need to change the animation from walking west/north/east as those points are hit, but when I queue up SKAction objects they of course run in sequence, which means when the "west" animation is playing the sprite isn't moving at all. How can I have some SKAction's run in parallel with another sequence of SKAction's? Are using blocks a potential solution?

Here's the code where I check if a "turn" is happening at the given point and respond accordingly:

// Set direction facing.
if (curCGPoint.x > prevCGPoint.x && [_facing isEqualToString:@"left"]) {
    [self setDirectionFacing:@"right"];

    // Add action to change direction.
    SKAction *changeDir = [SKAction repeatActionForever:[SKAction animateWithTextures:walkRightFrames timePerFrame:0.1f resize:NO restore:YES]];
    [walkActions addObject:changeDir];

} else if (curCGPoint.x < prevCGPoint.x && [_facing isEqualToString:@"right"]) {
    [self setDirectionFacing:@"left"];

    // Add action to change direction.
    SKAction *changeDir = [SKAction repeatActionForever:[SKAction animateWithTextures:walkLeftFrames timePerFrame:0.1f resize:NO restore:YES]];
    [walkActions addObject:changeDir];
}

// Build SKAction to walk hero to the current point.
SKAction *walkAction = [SKAction moveTo:curCGPoint duration:0.1];

// Add to our array of walk SKAction's.
[walkActions addObject:walkAction];

The previous code is in a for() where I run through all points – subsequently I do something like this to actually run the actions:

SKAction *sequence = [SKAction sequence:walkActions];
[_sprite runAction:sequence withKey:@"Move_Hero"];

Update: For those that run into this trying to do the same thing, you can use a combination of SKAction sequences, SKAction groups, and blocks (via SKAction:runBlock) to get your parallel and successive actions going. Using SKAction:runBlock you can fire off actions from specific "group" entries that should only run at that particular moment but should not block successive actions. This is a very flexible route to take.

1
Why don't you stop old action and start new action based on current events using the removeAction command? - sangony
That's a pretty good route to go. I'll try that. - Charlie Schliesser

1 Answers

5
votes

Yes SKAction has a method called group:

[SKAction group:@[SKAction1, SKAction2, SKAction3]];

It runs a lot like sequence but all the SKActions inside the group array runs together.

For more details I advise reading the docs.