A node that draws a rectangular texture, image or color.
- iOS 7.0+
- macOS 10.9+
- tvOS 9.0+
- watchOS 3.0+
SKSprite is a node that draws a texture (optionally blended with a color), an image, a colored square. You can also provide a custom shader to create your own rendering effects.
Sprite nodes can be lit with
SKLight objects and optionally cast and receive shadows. 3D lighting can be simulated by supplying a separate normal texture or automatically generating a normal texture from an image.
Sprites are the basic building blocks used to create the majority of your scene’s content, so understanding sprites is useful before moving on to other node classes in SpriteKit. Sprites are represented by
SKSprite objects. An
SKSprite object can be drawn either as a rectangle with a texture mapped onto it or as a colored, untextured rectangle. Textured sprites are more common, because they represent the primary way that you bring custom artwork into a scene. This custom artwork might represent characters in your game, background elements, or even user interface elements, but the basic strategy is the same. An artist creates the images, and your game or app
SKSprite loads them as textures. Then you create sprites with those textures and add them to the scene.
Creating a Textured Sprite Node
The simplest way to create a textured sprite node is to have SpriteKit create both the texture and the sprite for you. You store the artwork in the app bundle (ideally in an asset catalog), and then load it at runtime. Listing 1 shows how to do this.
When you create a sprite in this fashion, you get a lot of default behavior for free:
The sprite node is created with a frame that matches the texture’s size.
The node is rendered so that it is centered on its position. The node's
frameproperty holds the rectangle that defines the area it covers.
The texture is alpha blended into the frame buffer.
SKTextureobject is created and attached to the node. This texture object automatically loads the texture data whenever the sprite node is in the scene, is visible, and is necessary for rendering the scene. Later, if the sprite is removed from the scene or is no longer visible, SpriteKit can delete the texture data if it needs that memory for other purposes. This automatic memory management simplifies but does not eliminate the work you need to do to manage art assets in your game.
The default behavior gives you a useful foundation for creating a sprite-based game.
Although SpriteKit can create textures for you automatically when a sprite is created, in more complex games and apps you need more control over textures. For example, you might want to do any of the following:
Share a texture between multiple sprites.
Change a sprite’s texture after it is created.
Animate a sprite through a series of textures.
Create textures from data that is not directly stored in the app bundle.
Render a node tree into a texture. For example, you might want to take a screenshot of your gameplay to show to the player after he or she completes the level.
Preload textures into memory before presenting a scene.
You do all of these things by working directly with texture objects, for more information, see the
SKTexture class reference.
Customizing a Textured Sprite
You can use each sprite node’s properties to independently configure four distinct rendering stages:
Move a sprite node’s frame so that a different point in the texture is placed at its position. See Using the Anchor Point to Move the Sprite Node’s Frame.
Resize a sprite node. You control how the texture is applied to the sprite when the size of the sprite does not match the size of the texture. See Resizing a Sprite Node.
Colorize a sprite node’s texture when it is applied to the sprite. See Colorizing a Sprite Node.
Use other blend modes in a sprite node to combine its contents with that of the framebuffer. Custom blend modes are useful for lighting and other special effects. See Blending the Sprite into the Frame Buffer.
Often, configuring a sprite node to perform these four steps—positioning, sizing, colorizing, and blending—is based on the artwork used to create its texture. This means that you rarely set property values in isolation from the artwork. You work with your artist to ensure that your game is configuring the sprites to match the artwork.
Here are some of the possible strategies you can follow:
Create the sprite nodes with hardcoded values in your project. This is the fastest approach, but the least desirable in the long term, because it means that the code must be changed whenever the art assets change.
Create your own tools using SpriteKit that lets you fine tune the sprite’s property values. When you have a sprite node configured the way you want it, save the sprite to an archive. Your game uses the archive to create sprites at runtime.
Store the configuration data in a property list that is stored in your app bundle. When the sprite node is loaded, load the property list and use its values to configure the node. Your artist can then provide the correct values and change them without requiring changes to your code.
Changing a Sprite’s Texture
A sprite’s texture property points to its current texture. You can change this property to point to a new texture. The next time the scene renders a new frame, it renders with the new texture. Whenever you change the texture, you may also need to change other sprite properties—such as
center—to be consistent with the new texture. Usually, it is better to ensure that all the artwork is consistent so that the same values can be used for all of the textures. That is, the textures should have a consistent size and anchor point placement so that your game does not need to update anything other than the texture.
Because animation is a common task, you can use actions to animate a series of textures on a sprite. The following code shows how to use an array of frames created to animate a sprite’s texture.
SpriteKit provides the plumbing that allows you to animate or change a sprite’s texture. It doesn’t impose a specific design on your animation system. This means you need to determine what kinds of animations that a sprite may need and then design your own animation system to switch between those animations at runtime. For example, a monster might have walk, fight, idle, and death animation sequences—and it’s up to you to decide when to switch between these sequences.
Using the Anchor Point to Move the Sprite Node’s Frame
By default, the sprite node’s frame—and thus its texture—is centered on its position. However, you might want a different part of the texture to appear at the node’s position. You usually do this when the game element depicted in the texture is not centered in the texture image.
A sprite node’s
anchor property determines which point in the frame is positioned at its position. Anchor points are specified in the unit coordinate system, shown in the following illustration. The unit coordinate system places the origin at the bottom left corner of the frame and
(1,1) at the top right corner of the frame. A sprite’s anchor point defaults to
(0, which corresponds to the center of the frame.
Although you are moving the frame, you do this because you want the corresponding portion of the texture to be centered on the position. The following figure shows a pair of texture images. In the first, the default anchor point centers the texture on the position. In the second, a point at the top of the image is selected instead. You can see that when the node is rotated, the texture image rotates around this point.
The following code shows how to place the anchor point on the rocket’s nose cone. Usually, you set the anchor point when the sprite node is initialized, because it corresponds to the artwork. However, you can set this property at any time. The frame is immediately updated, and the node onscreen is updated the next time the scene is rendered.
Resizing a Sprite Node
The size of the sprite node’s
frame property is determined by the values of three other properties:
The sprite node’s
sizeproperty holds its base (unscaled) size. When a sprite is initialized using
init(image, the value of this property is initialized to be equal to the size of the supplied image.
When a sprite node’s frame is larger than its texture, the texture is stretched to cover its frame. Normally, the texture is stretched uniformly across the frame, as shown in the following figure.
However, sometimes you want to use sprite nodes to build user interface elements, such as buttons or health indicators. Often, these elements contain fixed-size elements, such as end caps, that should not be stretched. In this case, use a portion of the texture without stretching, and then stretch the remaining part of the texture over the rest of the frame.
center property, which is specified in unit coordinates of the texture, controls the scaling behavior. The default value is a rectangle that covers the entire texture, which is why the entire texture is stretched across the frame. If you specify a rectangle that only covers a portion of the texture, you create a 3 x 3 grid. Each box in the grid has its own scaling behavior:
The portions of the texture in the four corners of the grid are drawn without any scaling.
The center of the grid is scaled in both dimensions.
The upper- and lower-middle parts are only scaled horizontally.
The left- and right-middle parts are only scaled vertically.
The following figure shows a close-up view of a texture you might use to draw a user interface button. The complete texture is 28 x 28 pixels. The corner pieces are each 12 x 12 pixels and the center is 4 X 4 pixels.
The following code shows how this button sprite would be initialized. The centerRect property is computed based on the design of the texture.
The following figure shows that the corners remain the same, even when the button is drawn at different sizes.
Colorizing a Sprite Node
You can use the
color properties to colorize the texture applied to a sprite node. The color blend factor defaults to
0, which indicates that the texture should be used unmodified. As you increase this number, more of the texture color is replaced with the blended color. For example, when a monster in your game takes damage, you might want to add a red tint to the character. The following code shows how you would apply a tint to the sprite.
You can also animate the color and color blend factors using actions. The following code shows how to briefly tint the sprite and then return it to normal.
Working with Lighting
You can use a sprite’s lighting properties,
shadowed, to apply effects such as illumination and shadow casting and receiving. These can be used in conjunction with normal mapping to simulate 3D lighting.
The following figure shows a normal mapped sprite node acting as background and two shadow casting sprite nodes (each with a rabbit texture).
The resulting scene shows the two rabbits casting shadows over the background (the light is rendered as a white circle). The noise texture gains a 3D look from the normal mapping:
Applying Shaders to Sprite Nodes
You can use the
shader property of a sprite node to change the appearance of a texture with a custom OpenGL ES fragment shader embedded within a
SKShader object. Custom shaders offer almost limitless possibilities, from adding blurs and color treatments to textures to generating imagery such as random noise.
The following code shows a small custom shader which inverts the color of a texture while leaving the alpha or transparency unaffected:
The following figure illustrates the effect of the shader. The original image, on the left, has its colors inverted by the shader:
Blending the Sprite into the Frame Buffer
The final stage of rendering is to blend the sprite’s texture into its destination frame buffer. The default behavior uses the alpha values of the texture to blend the texture with the destination pixels. However, you can use other blend modes when you want to add other special effects to a scene.
You control the sprite’s blending behavior using the
blend property. For example, an additive blend mode is useful to combine multiple sprites together, for effects such as for fire or lighting. The following code shows how to position three overlapping sprite nodes in a circle to demonstrate the effect of different blend modes:
With the default blend mode of
alpha, the thee circles look like:
However, with a blend mode of
add, the color values are added together, creating a scene that looks like: