Organizing art into texture atlases
We will quickly overrun our project navigator with image files if we add all our textures like we did with our bee. Luckily, Xcode provides several solutions.
Exploring Assets.xcassets
We can store images in an .xcassets
file and refer to them easily from our code. Follow these steps to prepare our .xcassets
file:
- Open
Assets.xcassets
from your project navigator. - You will see an empty
AppIcon
entry. You can leave it there for now; we will revisit theAppIcon
later.
Collecting art into texture atlases
We will use texture atlases for most of our in-game art. Texture atlases organize assets by collecting related artwork together. They also increase performance by optimizing all of the images inside each atlas as if they were one texture. SpriteKit only needs one draw call to render multiple images out of the same texture atlas. Plus, they are very easy to use! Follow these steps to build your bee texture atlas:
- First, we need to remove our old bee texture. Right-click on
bee@3x.png
in the project navigator and choose Delete, then Move to Trash. - In
Assets.xcassets
, right-click in the left panel and select New Sprite Atlas. - You should see a new folder in the left panel called
Sprites
. This is our new texture atlas. Double-click it, or select it, and press your Enter key to rename it, then name itEnemies
(the bee will eventually be an enemy in our game). - Inside this atlas, you will see a demo entry, called
Sprite
. We can delete this demo sprite; we will create our own entries for our game. Right-clickSprite
and selectRemove Selected Items
. - Open the asset bundle that you downloaded and locate the
bee@2x.png
andbee@3x.png
images inside theEnemies
folder. - There are several ways to import files into a texture atlas. The easiest way is to select all sizes of the image in the
Finder
and then drag and drop them onto theEnemies
texture atlas icon in the left panel of Xcode. You can do this now, and you should see a new sprite created insideEnemies
, calledbee
, as shown in this screenshot: - We also want to create another sprite in this atlas for the second frame of our bee's flying animation. Repeat this drag and drop exercise by selecting the asset files named
bee-fly@2x.png
andbee-fly@3x.png
, and dragging them onto theEnemies
texture atlas in Xcode.ss
You should now have a texture atlas named Enemies that contains two sprites: bee
and bee-fly
. Each of these sprites has both a 2X and 3X version to take full advantage of retina screens. Good work; we have organized our bee assets into one collection. Xcode will now automatically create performance optimizations and select the best size for each device.
Updating our bee node to use the texture atlas
We can actually run our project right now and see the same bee as before. Our old bee texture was bee
, and a new bee
sprite exists in the texture atlas. Although we deleted the standalone bee@3x.png
, SpriteKit is smart enough to find the new bee
in the texture atlas.
We should make sure that our texture atlas is working and that we successfully deleted the old individual bee@3x.png
. In GameScene.swift
, change our SKSpriteNode
instantiation line to use the new bee-fly
graphic from the texture atlas:
// create our bee sprite // notice the new image name: bee-fly let bee = SKSpriteNode(imageNamed: "bee-fly")
Run the project again. You should see a different bee image, its wings held lower than before. This is the second frame of the bee animation. Next, we will learn how to animate between the two frames to create an animated sprite.
Iterating through texture atlas frames
We need to study one more texture atlas technique: we can quickly flip through multiple sprite frames to make our bee come alive with motion. We now have two frames of our bee in flight; it should appear to hover in place if we switch back and forth between these frames.
Our node will run a new SKAction
to animate between the two frames. Update your didMove
function to match mine (I removed some older comments to save space):
Override func didMove(to view: SKView) { self.anchorPoint = .zero self.backgroundColor = UIColor(red: 0.4, green: 0.6, blue: 0.95, alpha: 1.0) // create our bee sprite // Note: Remove all prior arguments from this line: let bee = SKSpriteNode() bee.position = CGPoint(x: 250, y: 250) bee.size = CGSize(width: 28, height: 24) self.addChild(bee) // Find our new bee texture atlas let beeAtlas = SKTextureAtlas(named:"Enemies") // Grab the two bee frames from the texture atlas in an array // Note: Check out the syntax explicitly declaring beeFrames // as an array of SKTextures. This is not strictly necessary, // but it makes the intent of the code more readable, so I // chose to include the explicit type declaration here: let beeFrames:[SKTexture] = [ beeAtlas.textureNamed("bee"), beeAtlas.textureNamed("bee-fly")] // Create a new SKAction to animate between the frames once let flyAction = SKAction.animate(with: beeFrames, timePerFrame: 0.14) // Create an SKAction to run the flyAction repeatedly let beeAction = SKAction.repeatForever(flyAction) // Instruct our bee to run the final repeat action: bee.run(beeAction) }
Run the project. You will see our bee flap its wings back and forth—cool! You have learned the basics of sprite animation with texture atlases. We will create increasingly complicated animations using this same technique later in this book. For now, pat yourself on the back. The result may seem simple, but you have unlocked a major building block toward your first SpriteKit game!
Putting it all together
First, we learned how to use actions to move, scale, and rotate our sprites. Then, we explored animating through multiple frames, bringing our sprites to life. Let's now combine these techniques to fly our bee back and forth across the screen, flipping the texture at each turn.
Add this code at the bottom of the didMove
function, beneath the bee.run(beeAction)
line:
// Set up new actions to move our bee back and forth: let pathLeft = SKAction.moveBy(x: -200, y: -10, duration: 2) let pathRight = SKAction.moveBy(x: 200, y: 10, duration: 2) // These two scaleX actions flip the texture back and forth // We will use these to turn the bee to face left and right let flipTextureNegative = SKAction.scaleX(to: -1, duration: 0) let flipTexturePositive = SKAction.scaleX(to: 1, duration: 0) // Combine actions into a cohesive flight sequence for our bee let flightOfTheBee = SKAction.sequence([pathLeft, flipTextureNegative, pathRight, flipTexturePositive]) // Last, create a looping action that will repeat forever let neverEndingFlight = SKAction.repeatForever(flightOfTheBee) // Tell our bee to run the flight path, and away it goes! bee.run(neverEndingFlight)
Run the project. You will see the bee flying back and forth, flapping its wings. You have officially learned the fundamentals of animation in SpriteKit! We will build on this knowledge to create a rich, animated game world for our players.