Control Render Order with Z-Position

When you add nodes to the scene, you’re building a node tree, which you briefly read about in Chapter 1, Creating Scenes with Sprites and Nodes. The order in which you add a node to the scene determines how it’s rendered. In this case, you added the background node last, which places it on top of the other nodes.

Here’s how it works:

  • The scene renders itself, clearing its contents to its background color.
  • The scene renders the foreground node, the player node, and finally, the background node.

You could build your scenes with this process in mind, but that can get complicated as you add and remove nodes. Luckily, you’re able to change how things render by using a node’s z-position. You can think of the z-position as the node’s depth setting within the scene.

When you use z-positions to set up your nodes, the node tree gets rendered differently. Here’s how it works:

  • The global z-position for each node is calculated by recursively adding its z-position to its parent’s z-position.

  • The drawing order is determined by the node’s z-position and is ordered from lowest to highest.

  • If two nodes share the same z-position, parent nodes are rendered first, followed by siblings and their children. The child nodes are rendered in the order in which they appear in the parent’s children array.

The default z-position for a node is 0. Setting this to a higher number brings it closer to the top. So, a z-position of 10, for example, is on top of a node whose z-position is set to 5.

Although you can set the z-position for each node using hard-coded numbers throughout your code, it’s best to use an enum. Using an enum makes it easier to maintain your code as you build more advanced scenes.

Open the SpriteKitHelper.swift file and add the following code to the top of this file, below the import statements:

 // MARK: - SPRITEKIT HELPERS
 
 // Set up shared z-positions
 enum​ ​Layer​: ​CGFloat​ {
 case​ background
 case​ foreground
 case​ player
 }

This code creates a new Layer enum that you can use for ordering the different nodes. Because player is last in the list, it has the highest number, which means any nodes that use this value will appear on the top-most layer.

Now that you have an enum available for setting a z-position value, you can use it to set the node’s zPosition property.

Open the Player.swift file, and inside the init() method, add the following line after setting the anchorPoint:

 self​.zPosition = ​Layer​.player.rawValue

Here, you’re using one of the enum values you set up earlier to set the node’s zPosition property. Because this is the player node, you want it to appear on top of everything else.

Next, open the GameScene.swift file, and inside the didMove(to:) method, update the code for both the background and foreground nodes.

For the background node, below the line of code that sets its anchorPoint, add the following:

 background.zPosition = ​Layer​.background.rawValue

For the foreground node, below the line of code that sets its anchorPoint, add the following:

 foreground.zPosition = ​Layer​.foreground.rawValue

Build and run the project to confirm everything is working as expected.

images/AddingAnimationAndMovementWithActions/spritekit-build-00.png

Although you can keep the code as it is now—remember, in Add the Player to the Scene, you swapped the order in which you’re adding nodes to the scene—it’s better to put everything back the way it was. For reference, the didMove(to:) method should look like this:

 override​ ​func​ ​didMove​(to view: ​SKView​) {
 
 // Set up background
 let​ background = ​SKSpriteNode​(imageNamed: ​"background_1"​)
  background.anchorPoint = ​CGPoint​(x: 0, y: 0)
  background.zPosition = ​Layer​.background.rawValue
  background.position = ​CGPoint​(x: 0, y: 0)
 addChild​(background)
 
 // Set up foreground
 let​ foreground = ​SKSpriteNode​(imageNamed: ​"foreground_1"​)
  foreground.anchorPoint = ​CGPoint​(x: 0, y: 0)
  foreground.zPosition = ​Layer​.foreground.rawValue
  foreground.position = ​CGPoint​(x: 0, y: 0)
 addChild​(foreground)
 
 // Set up player
 let​ player = ​Player​()
  player.position = ​CGPoint​(x: size.width/2, y: foreground.frame.maxY)
 addChild​(player)
 }

Build and run the project again to make sure things continue to look as expected.

A Word about Render Order

images/aside-icons/warning.png

In Chapter 1, Creating Scenes with Sprites and Nodes, you may recall a property named ignoresSiblingOrder. When ignoresSiblingOrder is set to its default value of false, nodes within a scene are sorted and rendered in a deterministic order: parents before children, and then siblings in the order in which they appear in the node tree.

In contrast, when the ignoresSiblingOrder property is set to true, the render order is based entirely on a node’s z-position. The default zPosition property value of a node is 0. While setting ignoresSiblingOrder = true offers an increase in performance, you must ensure that each node has its zPosition property set. In cases where two nodes share the same z-position, their render order is arbitrary and can change.

For most SpriteKit games, leaving ignoresSiblingOrder = false is recommended unless performance is an issue.

With your player image resources added and your base methods set up, you have everything in place to animate Blob’s walk cycle.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset