A representation of an image for use in SpriteKit.
- iOS 7.0+
- macOS 10.9+
- tvOS 9.0+
- watchOS 3.0+
SKTexture object is an image that can be applied to
SKShape objects, particles created by an
SKEmitter object or tiles used in an
SKTile. A texture object manages the texture data and graphics resources that are needed to render the image. Most texture objects are created from source images stored in your app bundle—your game’s artwork. Once created, a texture object’s contents are immutable. Multiple sprites can share the same texture object, sharing a single resource.
init(image method to create the
SKTexture object. When the texture object is initialized using an image file, SpriteKit must perform two steps before it can use the texture to render sprites. First, it must load the texture data from the file. Second, it must prepare the texture data to be used by the graphics hardware. Both of these steps can be expensive compared to other SpriteKit operations. In particular, loading a texture from a file is very expensive. SpriteKit defers loading and preparing the texture as long as possible and also provides methods you can use to control these steps.
The texture data is loaded when:
size()method on the texture object is called.
Another method is called that requires the texture’s size, such as creating a new
SKSpriteobject that uses the texture object.
One of the preload methods is called (See Preloading the Texture Data.)
The texture data is prepared for rendering when:
A sprite or particle that uses the texture is part of a node tree that is being rendered.
SKTexture object is ready for rendering, it stays ready until all strong references to the texture object are removed.
Texture objects can be created from data generated at runtime. For example, you can create the texture from a Quartz 2D image, from raw pixel data, or by applying a Core Image filter to an existing texture. You can also call the
texture(from:) method to render a node tree into a texture. None of these textures must be loaded because their data is already in memory when the texture is created. However, the texture must still be prepared by SpriteKit before it can be used for rendering.
To create textures that can be updated at runtime, see the
Managing Texture Memory
Texture objects can consume a lot of memory, depending on the size of your source data. And often, the memory available to prepared textures is limited by the hardware, because the textures need to be loaded into VRAM. So, most games must carefully manage the memory used by textures. Consider the following tips when creating your game:
Access a texture object only when needed and dispose of the object when you are confident that it is no longer needed by your game. This frees the memory and makes it available to other texture objects.
Avoid loading too many textures in a single pass through the rendering loop. If you do, SpriteKit may skip one or more frames to finish loading the texture data. Instead, preload your content before starting your game.
If you frequently use the same textures at the same time to render your sprites, do not load each texture from a separate image file. Instead, group the texture images logically into one or more texture atlases. See
SKTexturefor more information.
For a longer discussion of texture management, see Working with Sprites.
Normal Map Textures
A normal map texture is similar to an image texture, but instead of holding image data to be displayed onscreen, every texel represents a normal vector. Normal map textures are used to simulate 3D lighting (see the
normal property) or used to generate velocity values (see
You can create normal maps in two different ways. First, you can take an existing image map and use it to generate a normal map. SpriteKit filters the color data in the texture and then uses it to generate a map based on pixel contrast. Alternatively, you can load a regular image file but treat it as a normal map. To do this, provide a texture with 32-bit
RGBx pixel data. Each component’s 8-bit integer value is mapped to a floating point number between the values of
1. Use a
0 to represent
-1, a value of
127 to represent
0, and a value of
255 to represent
The image below shows two sprite nodes both with the same texture. The node on the right has a normal map from the same noise texture generated using the
Extracting the Contents of a Texture
cg property returns the contents of a texture as a Quartz Image. For example, to take a screenshot of your scene, use the
texture(from:) method to render the scene’s contents to a texture and then read the
cg property of that texture.
Preloading Textures Into Memory
A major advantage to SpriteKit is that it performs a lot of memory management for you automatically. When rendering a new frame of animation, SpriteKit determines whether a texture is needed to render the current frame. If a texture is needed but is not prepared for rendering, SpriteKit loads the texture data from the file, transforms the data into a format that the graphics hardware can use, and uploads it to the graphics hardware. This process happens automatically in the background, but it isn’t free. If too many unloaded textures are needed at once, it may be impossible to load all the textures in a single frame of animation, causing the frame rate to stutter. To avoid this problem, you need to preload textures into memory, particularly in larger or complex games.
Listing 1 shows how to preload an array of
SKTexture objects. The
preload(_: method calls the completion handler after all of the textures are loaded into memory. In this example, all of the textures for a particular level of the game are preloaded in a single operation. When the textures are all in memory, the completion handler is called. It creates the scene and presents it. (You need to add code to provide these texture objects to the scene; that code isn’t shown here).
Because you are intimately familiar with the design of your game or app, you are the best person to know when new textures are needed. The exact design of your preloading code is going to depend on your game engine. Here are a few possible designs to consider:
For a small game or app, you may be able to preload all of its textures when the app is launched, and then keep them in memory forever.
For a larger game or app, you may need to split the textures into levels or themes. Each level or theme’s textures are designed to fit in a specific amount of memory. When the player starts a new level, you preload all of that level’s texture objects. When the player finishes playing the level, the textures not needed for the next level are discarded. By preloading the levels, the load time is all up front, before gameplay starts.
If a game needs more textures than can fit into memory, you need to preload textures dynamically as the game is being played. Typically, you preload some textures at the start of a level, and then load other textures when you think they will be needed soon. For example, in a racing game, the player is always moving in the same direction, so for each frame you might fetch a new texture for content the player is about to see. The textures are loaded in the background, displacing the oldest textures for the track. In an adventure game that allows for player-controlled movement, you might have to provisionally load textures when a player is moving in a particular direction.
Removing a Texture From Memory
After a texture is loaded into the graphics hardware’s memory, it stays in memory until the referencing
SKTexture object is deleted. This means that between levels (or in a dynamic game), you may need to make sure a texture object is deleted. Delete a
SKTexture object object by removing any strong references to it, including:
This class cannot be subclassed.