Label nodes and debugging cursor's position

Categories: Adventure Game

In this series of posts I describe the process I've followed, as an amateur game designer, for developing an adventure game written in Swift using the SpriteKit framework for iOS.

Introduction

In the conclusion of the last post in this series, I anticipated that I was going to talk about how to render sprites, but I need to delay a little bit that topic because I still don’t have a clear game design idea.

I like to think of this as an application of the “Give the player options” rule in Gilbert’s Rules of Thumb for adventure games that don’t suck. I’m stuck at the “game design” puzzle, but that shouldn’t prevent me to post regular updates on the project :)

In this post I’ll describe how to display text using SpriteKit’s label nodes. More specifically how to add a small label to the cursor node to display its position for debugging purpose.

SKLabelNode

I can use SKLabelNode for displaying text in a SpriteKit game scene.

Using an SKLabelNode is straightforward: create a new SKLabelNode instance and add it to the list of a node’s children (note that SKScene is a SKNode, that’s the reason why you can add SKNodes directly to the game scene).

If the hierarchy containing the SKLabelNode instance is in the current game scene, SpriteKit will render the content of the node’s text property.

Cursor’s position

I start by adding a new lazy stored property to the Cursor node class:

1
2
// TODO: Display cursor position only during development
private lazy var posLabel = SKLabelNode()

Note: ideally the cursor’s position should be visible only in development builds, but for now let’s just add a TODO comment.

Next I update the Cursor class initializer to set posLabel’s position and add it to the children list:

1
2
3
4
5
posLabel.position = CGPoint(
    x: 0,
    y: half + Cursor.positionLabelTopMargin
)
addChild(posLabel)

The label’s position is relative to the Cursor node, that means that the label will be horizontally centered (x: 0) and vertically at top (y: half + Cursor.positionLabelTopMargin).

Note: y computation includes Cursor.positionLabelTopMargin static constant, that I use to reference to the numeric value used as the top margin between cursor path and label node.

1
2
// Margin between position label and cursor path
static let positionLabelTopMargin: CGFloat = 10

To update the label’s text I define an observer on the Cursor’s position property that updates posLabel.text with a string with the format (x, y), that represents the position of the cursor.

1
2
3
4
5
override var position: CGPoint {
    didSet {
        posLabel.text = formatPos()
    }
}

Each time the position property changes, this observer will update the text property of the label node.

Note: formatPos is a helper function that returns the node position as a formatted string.

1
2
3
4
5
6
7
private func formatPos() -> String {
    return "(\(formatCoord(position.x)), \(formatCoord(position.y)))"
}

private func formatCoord(_ n: CGFloat) -> String {
    return String(format: "%.0f", n)
}

This is the final result:

Conclusion

This was kind of a placeholder post, but it was a good excuse for introducing a new node type and I think it’s useful to get feedback on the cursor’s position for debugging purpose.

In the next post, as soon as I have the design prototype of the first game scene ready, I’ll create a sprite node for displaying the scene’s background.

Resources

Discussion on r/iOSProgramming