SpriteKit Basics: Nodes

SpriteKit Basics: Nodes

SpriteKit is Apple's 2D game engine—a rendering engine built on top of OpenGL. It was introduced with iOS 7, and each subsequent release has brought great additions to the framework. With the use of textured sprites, a built-in physics engine, and the very powerful SKAction class, you can very quickly build functional 2D games.

SpriteKit has built-in editors for scenes and particles, a camera node since the release of iOS9, and built-in support for tilesets since the release of iOS 10. With these new additions, SpriteKit is quickly becoming a powerhouse for creating 2D games.

To follow along with this tutorial, just download the accompanying GitHub repo. It has a folder called ExampleProject Starter. Open the project in that folder in Xcode, and you're ready to go!

Nodes

Nodes are the fundamental building blocks of SpriteKit, and SKNode is the base class of all nodes. All of your
onscreen assets will be an SKNode or a subclass thereof. SKNodes by
themselves do not provide any visual content, however. All visual content is
drawn using one of a number of predefined SKNode subclasses. SKNodes
and its subclasses share several properties you can alter. Some of
the more important ones are as follows.

  • position (CGPoint): the node's position within its parent's coordinate system
  • xScale (CGFloat): scales the width of a node by a multiplier
  • yScale(CGFloat): scales the height of a node by a multiplier
  • alpha (CGFloat): the transparency of the node
  • zRotation (CGFloat): the Euler rotation about the z axis (in radians)

One of the most important SKNodes is the SKScene. This is the root node to which all other nodes are added. By itself, SKScene does not provide any visual elements, but it displays the nodes which are added to it.

Scene Nodes

SKScenes are the root nodes to which all other nodes are added. The scene animates and renders the content from its child nodes. To display a scene, you add it to an SKView (which is a subclass of UIView and therefore has many of the same properties as UIView).

In the SpriteKit starter project, the initial scene is showing when the project loads. For now, this is just a blank black screen. It is shown when the GameViewController invokes presentScene(_:) on the view instance, passing in the scene as a parameter:

Don't worry about the other options for now; I'll explain them later in this series.

Creating a Scene

Many games have more than one screen or scene, so we will create a new scene from scratch and then show it from our initial scene.

Select File > New > File from Xcode's menu, and choose Cocoa Touch Class.

Choose the Cocoa Touch Class template

Make sure Class is set to NewScene and that Subclass of is set to SKScene. Press Next and then Create, making sure the main target is checked. Below is the code for the NewScene.swift.

Now we have two scenes in our project, and neither has any visual content. Let's add an SKLabelNode (like all nodes, this is a subclass of SKNode). The SKLabelNode's sole purpose is to display a text label.

Label Nodes

Label nodes, implemented in the SKLabelNode class, are used to show text within your game. You can use custom fonts if you wish, but for our purposes we will just stick to the default, which displays white text and is set to Helvetica Neue Ultra Light, 32 point.

Add the following inside the didMove(to:) method within GameScene.swift. This method is called immediately after a scene is presented by a view. Generally, this is where you would set up any of your game's assets and add them to the scene.

Here we create an SKLabelNode using the convenience initializer init(text:), which takes as a parameter a string of text.

Adding and Removing Nodes

Just initializing nodes will not show them in the scene. To get the nodes to show, you have to invoke the addChild(_:) method on the receiving node, passing the SKNode that you wish to add as a parameter.

Add the following within the didMove(to:) method.

The addChild(_:) method is not exclusive to SKScenes, but is a method of SKNode. This allows you to build a complex hierarchy of nodes—known as the "node tree". For example, suppose you have a game character and you wanted to move its arms and legs separately. You could create an SKNode instance and then add each individual part as a child of that SKNode (the containing node is known as the parent node). This would give you the benefit of being able to move the character as a whole unit by moving the parent SKNode, but also allow you to move each individual part individually.

Another important method for adding nodes is the insertChild(_:at:) method, which inserts a child into a specific position within the receiver node's list of children. When you add a child to a node, the node maintains an ordered list of children which is referenced by reading the node's children property. It is important when adding multiple nodes to a parent node to take this into consideration, as the order in which you add the nodes affects some of the aspects of scene processing, including hit testing and rendering.

To remove a node, you invoke the removeFromParent() method on the node you wish to remove.

Now that we have covered adding and removing nodes, we can move our focus back to the example project. If you recall, we had just added an SKLabelNode to the GameScene. If you test now, you will see just half of the text off to the bottom left of the screen.

Test showing blank screen with text half off to the bottom left of the screen

Why is only half the text showing, though? Now would be a good time to talk about SpriteKit's coordinate and positioning system.

Positioning and Coordinates

By default, SpriteKit's coordinate system places (0,0) at the bottom left of the screen. Also by default, SpriteKit places nodes so they are positioned at (0,0). Still, though... why are we only seeing half of the text? This is because by default the text label is centered horizontally on the label node's origin, which is (0,0). Below is an image that shows how a node's coordinate system works.

A nodes x and y coordinates

Node's origins are at (0,0), and a positive x coordinate moves to the right and a positive y coordinate goes up the screen. Remember that an SKScene is a node, and therefore its origin is also (0,0).

Setting a Node's Position

Now that we have learned SpriteKit's coordinate system works and how it places nodes, we can move the SKLabelNode to a different position so we can see all of the text. Add the following to the didMove(to:) method within GameScene.swift.

Here we position the label to the center of the scene. The position property is of type CGPoint, which has x and y values that represent a single point within the scene.

If you test now, you should see the label has been positioned in the center of the scene.

Test with label positioned in centre of screen

Switching Between Scenes

As it currently stands, NewScene is just a blank scene. Let's also add a label to it, and then we can learn how to switch between scenes. Here's a challenge: before you read ahead, try to add a label to NewScene that says, "Go Back". My solution is below.

The first thing we need to do is add the didMove(to:) method. Add the following to NewScene.swift.

Next, we need to add the label. Add the following within the didMove(to:) method that you added above.

This adds a label to  NewScene with the text "Go Back". Next, we'll implement the functionality this label suggests—we'll respond to touch events by switching scenes.

Responding to Touch

Nearly all mobile games will be interacted with using touch. In this step, you will learn how to respond to touch events within your game.

To register touch event handlers within your game, you must implement the view's touchesBegan(_:with:) method. Add the following to GameScene.swift:

If you want to test this now, you will see YOU TOUCHED printed to the console when you touch on the screen. What we usually need, however, is to be able to tell when a specific node has been touched. To do this, we need some way to find and identify the nodes. We will learn how to accomplish this, and then come back and finish the touchesBegan(_:with:) method.

Searching the Node Tree

To be able to identify a node, you use the node's name property and the search the node tree for a node with that name. The node's name property takes an alphanumeric string without any punctuation. 

There are a couple of methods to search for a node by its name property. If you already have a reference to the node, you can just check its name property directly, which is what we will do in the touchesBegan(_:with:) method. However, it is important to know how to search the node tree for a particular node by name, or to search for a group of nodes with the same name.

The childNode(withName:) method searches the children of a node for the specific name passed in as a parameter.

The enumerateChildNodes(withName:using:) method searches a node's children and calls the block once for each matching node it finds. You use this method when you want to find all nodes that share the same name.

The subscript(_:) method returns an array of nodes that match the name parameter.

You can also search for nodes using an advanced searching syntax that allows you to search the entire scene tree, or search for a pattern rather than an exact name, for example. This advanced searching capability is beyond the scope of this tutorial. However, if you wish to learn more, you can read about in the SKNode programming reference.

Now that we know how to search for nodes within the node tree, let's give our labels a name.

Add the following within the didMove(to:) method within GameScene.swift.

Here, we set startGameLabel's name property to startgame.

We also need to set the label's name within NewScene. Add the following with the didMove(to:) method within NewScene.swift.

We set the name property to goback.

Detecting Which Node Is Touched

Add the following within the touchesBegan(_:with:) method within GameScene.swift.

The multiTouchEnabled property of the scene's view is set to false by default, which means the view only receives the first touch of a multitouch sequence. With this property disabled, you can retrieve the touch by using the first computed property of the touches set, since there is only one object in the set.

We can get the touchLocation within the scene from the location property of the touch. We can then figure out which node was touched by invoking atPoint(_:) and passing in the touchLocation.

We check if the touchedNode's name property is equal to "startgame", and if it is, we know that the user has touched the label. We then create an instance of NewScene and set its scalemode property to be the same as the current scene—this ensures the scene acts the same across different devices. Finally, we create an SKTransition and invoke the presentScene(_:transition:) method, which will present the scene along with the transition.

The SKTransition class has many class methods that you can invoke to show different transitions between scenes instead of immediately showing the scene. This provides a bit of "eye candy" for the end user, and makes showing a new scene seem less abrupt. To see all of the available transition types, check out the SKTransition class in the reference guide.

I'm not going to implement the touchesBegan(_:with:) method in NewScene. Why don't you try doing that on your own and have the label transition back to the GameScene using a different transition type? The code will closely resemble what we have above, only remember we named the SKLabelNode "goback".

Conclusion

We have learned a good bit about nodes so far using scenes, and you've seen how to use a label node as a generic example to learn some of the characteristics of nodes. We've studied their coordinate systems, how to locate them within the node tree, how to position them, and how to respond to touch events. 

There are several other kinds of nodes available, and we'll take a look at them in the next tutorial—starting with SKSpriteNode!

To learn more about how to get started with SpriteKit, you should also check out Davis Allie's post here on Envato Tuts+.

Also, check out our SpriteKit courses! These will take you through all the steps of building your first SpriteKit game for iOS, even if you've never coded with SpriteKit before.

Source: Tuts Plus

About the Author