Add Labels to Show Current Level and Score

If you’re familiar with UIKit, you know that you can add labels to your views using the UILabel class. In SpriteKit, however, rather than using the UILabel class, you use the SKLabelNode class.

Like other nodes in SpriteKit, the SKLabelNode class is a subclass of SKNode. That means all of the properties and functionality of the SKNode class—like position, scale, and rotation—are also available within the SKLabelNode class. However, label nodes in SpriteKit are not as intuitive as some other nodes, like sprite nodes, for example. But don’t worry, this chapter will help to unravel the mystery.

Your first stop in learning about labels in SpriteKit is how to add custom fonts to your project.

Adding Custom Fonts

While using custom fonts isn’t always necessary, the Gloop Drop game design document specifies the Nosifer font as its primary font. You can download this free font[31] from the Google Fonts repository. Alternatively, you can use the Nosifer-Regular.ttf font file in the Fonts folder included with the code resources for this chapter.

With the Nosifer-Regular.ttf font file in hand (so to speak), open the gloopdrop project in Xcode.

To use custom fonts in your game, you need to add them to your project. As you begin to add more resources to your projects, you need to consider how to organize them. In this case, you’ll create a new folder in your project to hold your custom font.

From Xcode’s App menu, select File New Group or press N on your keyboard to create a new group within your Xcode project as shown in the first image.

images/AddingLabelsAndWorkingWithTheGameLoop/spritekit-newgroup.png

Rename the group Fonts, and drag the Nosifer-Regular.ttf font file into the group, as shown in the second image.

images/AddingLabelsAndWorkingWithTheGameLoop/spritekit-addfont.png

When prompted, ensure the Copy items if needed and Add to targets options are both checked. Also, verify that the option to Create groups is selected. Once these options are set and everything matches the first image, click Finish.

images/AddingLabelsAndWorkingWithTheGameLoop/spritekit-addtarget.png

The font file now exists within the project; however, the project doesn’t know about it. For the project to recognize a custom font, you need to update the Info.plist file.

In the Project Navigator, select the Info.plist file. Highlight the last item in the list and click the + button to the right of the Key’s label. When the Key drop-down list appears, select Fonts provided by application. Now, click the disclosure icon to the left of the key’s label to expand the list and display Item 0. For the Item 0 Value, enter Nosifer-Regular.ttf, as shown in the second image.

images/AddingLabelsAndWorkingWithTheGameLoop/spritekit-addkey-callouts.png

When you add the Fonts provided by application Key/Value pair to the Info.plist file, you register the font, which makes it available for use in your game.

Now that your custom font is registered and ready to use, you can add the score and level labels to the scene to provide players with key information.

Creating Labels in SpriteKit

Open the GameScene.swift file and add the following two properties to hold the score and level label objects:

 // Labels
 var​ scoreLabel: ​SKLabelNode​ = ​SKLabelNode​()
 var​ levelLabel: ​SKLabelNode​ = ​SKLabelNode​()

This code creates the label objects using the SKLabelNode class—one for the score and one for the level.

Before you write the code to add these two labels to the scene, you need to do a few things first, staring with adding a new Layer enum to help set the z-position of the User Interface (UI) objects.

Setting Label Positions

Open the SpriteKitHelper.swift file and update the Layer enum by adding a new case:

 enum​ ​Layer​: ​CGFloat​ {
 case​ background
 case​ foreground
 case​ player
 case​ collectible
 case​ ui
 }

You’ll use the new ui case for the UI elements, such as the labels. If you remember from Control Render Order with Z-Position, because ui is at the end of this list, any node that has its zPosition property set to Layer.ui will position itself at the front of the node tree—in other words, on top of the other nodes. But the z-position isn’t the only position you need to consider when placing labels, especially when your game supports different screen sizes.

Working with Different Screen Sizes

Gloop Drop was designed to support multiple screen sizes, so you need to consider where your labels will appear depending on which device the player is using. Because the view size is different than the scene size and depends largely on the device in use, some clipping can occur. This happens because of the scaleMode setting.

Four modes are available: fill, aspectFit, resizeFill, and aspectFill. The default value is fill; however, when you create a new SpriteKit project using the iOS Game template, it gets set to aspectFill. That’s okay, though, because Gloop Drop uses aspectFill. You can see this in the GameViewController.swift file where you set up the scene:

 // Create the scene
 // let scene = GameScene(size: view.bounds.size)
 let​ scene = ​GameScene​(size:​CGSize​(width: 1336, height: 1024))
 
 // Set the scale mode to scale to fill the view window
 scene.scaleMode = .aspectFill

Deciding which scale mode to use depends on the design of your game. From the Apple documentation:

  • fill: Each axis of the scene is scaled independently so that each axis in the scene exactly maps to the length of that axis in the view.

  • aspectFit: The scaling factor of each dimension is calculated and the smaller of the two is chosen. Each axis of the scene is scaled by the same scaling factor. This guarantees that the entire scene is visible but may require letterboxing in the view.

  • resizeFill: The scene is not scaled to match the view. Instead, the scene is automatically resized so its dimensions always match those of the view.

  • aspectFill: The scaling factor of each dimension is calculated and the larger of the two is chosen. Each axis of the scene is scaled by the same scaling factor. This guarantees that the entire area of the view is filled but may cause parts of the scene to be cropped.

Selecting the best scale mode—then deciding how to appropriately handle the art assets and gameplay logic based on that decision—isn’t always easy as it depends largely on your game’s design and the devices you intend to support.

Look at following image:

images/AddingLabelsAndWorkingWithTheGameLoop/spritekit-scalemode.png

This image shows how Gloop Drop looks with each scaleMode option.

With Gloop Drop, the game design called for support on both the iPad and the iPhone. With the radically different screen sizes, and the desire to keep the art simple by only having one size in @1x, @2x, and @3x resolutions, it made sense to design the game with the iPad size in mind. With that being the case, the next decision was how to handle the size and position of sprites.

For most games, it makes sense to use aspectFill simply because it offers you a way to design with a constant-sized scene, which provides a predictable coordinate system and frame; however, if doing so, you as the designer/developer need to ensure that your gameplay logic stays visible regardless of the viewable area.

To position the level and score labels at the top right and left of the scene, and to keep them within the boundaries of the viewable area on all devices, you’ll use a custom SKScene extension.

Scroll to the bottom of the SpriteKitHelper.swift file and add the following extension and two extension methods:

 extension​ ​SKScene​ {
 
 // Top of view
 func​ ​viewTop​() -> ​CGFloat​ {
 return​ ​convertPoint​(fromView: ​CGPoint​(x: 0.0, y: 0)).y
  }
 
 // Bottom of view
 func​ ​viewBottom​() -> ​CGFloat​ {
 guard​ ​let​ view = view ​else​ { ​return​ 0.0 }
 return​ ​convertPoint​(fromView: ​CGPoint​(x: 0.0,
  y: view.bounds.size.height)).y
  }
 }

This extension and its two methods convert the view’s coordinates to scene coordinates. By converting the view’s coordinates to scene coordinates, you’re able to position the label nodes—or any node for that matter—at the top and bottom of the viewable screen.

Your next step is to add the labels to the scene.

Adding Labels to the Scene

Open the GameScene.swift file, and below the didMove(to:) method, add the following method to set up the labels:

 func​ ​setupLabels​() {
 /* SCORE LABEL */
  scoreLabel.name = ​"score"
  scoreLabel.fontName = ​"Nosifer"
  scoreLabel.fontColor = .yellow
  scoreLabel.fontSize = 35.0
  scoreLabel.horizontalAlignmentMode = .right
  scoreLabel.verticalAlignmentMode = .center
  scoreLabel.zPosition = ​Layer​.ui.rawValue
  scoreLabel.position = ​CGPoint​(x: frame.maxX - 50, y: ​viewTop​() - 100)
 
 // Set the text and add the label node to scene
  scoreLabel.text = ​"Score: 0"
 addChild​(scoreLabel)
 
 /* LEVEL LABEL */
  levelLabel.name = ​"level"
  levelLabel.fontName = ​"Nosifer"
  levelLabel.fontColor = .yellow
  levelLabel.fontSize = 35.0
  levelLabel.horizontalAlignmentMode = .left
  levelLabel.verticalAlignmentMode = .center
  levelLabel.zPosition = ​Layer​.ui.rawValue
  levelLabel.position = ​CGPoint​(x: frame.minX + 50, y: ​viewTop​() - 100)
 
 // Set the text and add the label node to scene
  levelLabel.text = ​"Level: ​​(​level​)​​"
 addChild​(levelLabel)
 }

This code sets up the score and level labels using the available SKLabelNode properties. Here, you can see properties like fontName, fontColor, and fontSize, which set the properties for the font the label will use. Notice the fontName is the name of your custom font: Nosifer. Also, notice the two alignment-related properties: horizontalAlignmentMode and verticalAlignmentMode. These two properties control how the text is aligned within the node. In this case, the score label is right-aligned horizontally, and the level label is left-aligned horizontally; both are vertically centered. Additionally, you’re setting the zPosition property to use Layer.ui.rawValue and the position property to use the extensions you created earlier, which tucks the labels into the top right and left corners of the viewable scene.

Before you build and run the project, you need to call the newly-created setupLabels() method. In the didMove(to:) method, immediately above the code that sets up the player node, add the following code that calls the new setupLabels() method:

 // Set up User Interface
 setupLabels​()

With the call to setupLabels() added, build and run the project. If everything went according to plan, you’ll see the level and score labels in place.

images/AddingLabelsAndWorkingWithTheGameLoop/spritekit-build-00.png

While this is a good start, the text for each label is static. In other words, when the player scores points and advances to the next level, these labels will not update. Your next step is to fix that problem.

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

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