Animation—movement, scaling, and rotation
Before we dive back in to sprite theory, we should have some fun with our blue square. SpriteKit uses action objects to move sprites around the screen. Consider this example: if our goal is to move the square across the screen, we must first create a new action object to describe the animation. Then, we instruct our sprite node to execute the action. I will illustrate this concept with many examples in the chapter. For now, add this code in the didMove
function, below the self.addChild(mySprite)
line:
// Create a new constant for our action instance // Use the move action to provide a goal position for a node // SpriteKit will tween to the new position over the course of the // duration, in this case 5 seconds let demoAction = SKAction.move(to: CGPoint(x: 300, y: 150), duration: 3) // Tell our square node to execute the action! mySprite.run(demoAction)
Run the project. You will see our blue square slide across the screen toward the (300
, 150
) position. This action is reusable—any node in your scene can execute this action to move to the (300
, 150
) position. As you can see, SpriteKit does a lot of the heavy lifting for us when we need to animate node properties.
Tip
Inbetweening, or tweening, uses the engine to animate smoothly between a start frame and an end frame. Our SKAction.move
animation is a tween; we provide the start frame (the sprite's original position) and the end frame (the new destination position). SpriteKit generates the smooth transition between our values.
Let's try some other actions. The SKAction.move
function is only one of many options. Try replacing the demoAction
line with this code:
letdemoAction = SKAction.scale(to: 4, duration: 5)
Run the project. You will see our blue square grow to four times its original size.
Sequencing multiple animations
We can execute actions together simultaneously, or one after the other, with action groups and sequences. For instance, we can easily make our sprite larger and spin it at the same time. Delete all of our animation code so far and replace it with this code:
// Scale up to 4X initial scale let demoAction1 = SKAction.scale(to: 4, duration: 5) // Rotate 5 radians let demoAction2 = SKAction.rotate(byAngle: 5, duration: 5) // Group the actions let actionGroup = SKAction.group([demoAction1, demoAction2]) // Execute the group! mySprite.run(actionGroup)
When you run the project, you will see a spinning, growing square. Terrific! If you want to run these actions in sequence (rather than at the same time) change SKAction.group
to SKAction.sequence
:
// Group the actions into a sequence let actionSequence = SKAction.sequence([demoAction1, demoAction2]) // Execute the sequence! mySprite.run(actionSequence)
Run the code and watch as your square first grows and then spins. Good. We are not limited to two actions; we can group or sequence as many actions together as we need.
We have only used a few actions so far; feel free to explore the SKAction
class and try out different action combinations before moving on. You can find a full list of actions in Apple's SKAction Class Reference at https://developer.apple.com/library/mac/documentation/SpriteKit/Reference/SKAction_Ref/.
Recapping your first sprite
Congratulations, you have learned to draw a non-textured sprite and animate it with SpriteKit actions. Next, we will explore some important positioning concepts and then add game art to our sprites.
Before you move on, make sure that your didMove
function matches mine and that your sequenced animation is firing properly. Here is my code up to this point:
override func didMove(to view: SKView) { // Make the scene position from its lower left // corner, regardless of any other settings: self.anchorPoint = .zero // Instantiate a constant, mySprite, instance of SKSpriteNode let mySprite = SKSpriteNode(color: .blue, size: CGSize(width: 50, height: 50)) // Assign our sprite a position mySprite.position = CGPoint(x: 150, y: 150) // Add our sprite node into the node tree self.addChild(mySprite) // Scale up to 4X initial scale let demoAction1 = SKAction.scale(to: 4, duration: 5) // Rotate 5 radians let demoAction2 = SKAction.rotate(byAngle: 5, duration: 5) // Group the actions let actionSequence = SKAction.sequence([demoAction1, demoAction2]) // Execute the group! mySprite.run(actionSequence) }