Skip to content

05.Heads up display

la.panon. edited this page Apr 17, 2025 · 2 revisions

There is nothing special to mention about this chapter. We will only show you code examples.

import gdext

import gdext/classes/gdSceneTree
import gdext/classes/gdLabel
import gdext/classes/gdButton
import gdext/classes/gdTimer
import gdext/classes/gdInput

type Hud* {.gdsync.} = ptr object of CanvasLayer
  ScoreLabel: Label
  Message: Label
  StartButton: Button
  MessageTimer: Timer

proc startGame*(self: Hud): Error {.gdsync, signal, name: "start_game".}

proc showMessage*(self: Hud; text: String) =
  self.Message.text = text
  show self.Message
  start self.MessageTimer

proc updateScore*(self: Hud; score: int) =
  self.ScoreLabel.text = $score

proc showGetReady*(self: Hud) =
  self.showMessage "Get Ready"

proc showGameOver*(self: Hud) =
  self.showMessage "Game Over"

  discard self.MessageTimer.connect("timeout", self.callable"_on_game_over_timer_timeout")
  proc onGameOverTimerTimeout(self: Hud) {.gdsync, name: "_on_game_over_timer_timeout".} =
    self.MessageTimer.disconnect("timeout", self.callable"_on_game_over_timer_timeout")
    self.Message.text = "Dodge the Creeps!"
    show self.Message
    discard self.getTree.createTimer(1)[].connect("timeout", self.callable"_on_start_button_timer_timeout")

  proc onStartButtonTimerTimeout(self: Hud) {.gdsync, name: "_on_start_button_timer_timeout".} =
    show self.StartButton

proc onMessageTimerTimeout(self: Hud) {.gdsync, name: "_on_message_timer_timeout".} =
  hide self.Message

proc onStartButtonPressed(self: Hud) {.gdsync, name: "_on_start_button_pressed".} =
  hide self.StartButton
  discard self.startGame()

method ready*(self: Hud) {.gdsync.} =
  self.ScoreLabel = self/"ScoreLabel" as Label
  self.Message = self/"Message" as Label
  self.StartButton = self/"StartButton" as Button
  self.MessageTimer = self/"MessageTimer" as Timer

  discard self.MessageTimer.connect("timeout", self.callable("_on_message_timer_timeout"))
  discard self.StartButton.connect("pressed", self.callable( "_on_start_button_pressed"))

Well... the showGameOver is quite strange compared to the GDScript one.

func show_game_over():
	show_message("Game Over")
	# Wait until the MessageTimer has counted down.
	await $MessageTimer.timeout

	$Message.text = "Dodge the Creeps!"
	$Message.show()
	# Make a one-shot timer and wait for it to finish.
	await get_tree().create_timer(1.0).timeout
	$StartButton.show()
proc showGameOver*(self: Hud) =
  self.showMessage "Game Over"

  discard self.MessageTimer.connect("timeout", self.callable"_on_game_over_timer_timeout")
  proc onGameOverTimerTimeout(self: Hud) {.gdsync, name: "_on_game_over_timer_timeout".} =
    self.MessageTimer.disconnect("timeout", self.callable"_on_game_over_timer_timeout")
    self.Message.text = "Dodge the Creeps!"
    show self.Message
    discard self.getTree.createTimer(1)[].connect("timeout", self.callable"_on_start_button_timer_timeout")

  proc onStartButtonTimerTimeout(self: Hud) {.gdsync, name: "_on_start_button_timer_timeout".} =
    show self.StartButton

Since await signal is not yet supported by gdext-nim, we have to force it to be reproduced using connect and disconnect in this way.

Fortunately, {.gdsync.} can be applied to closures (functions within functions), so it can be expressed, albeit with a few lines of boilerplate. It might be interesting to create a template that removes this boilerplate.

# nim/nimmain/src/classes/gdmain.nim
type Main* {.gdsync.} = ptr object of Node
+ Hud: Hud

method ready(self: Main) {.gdsync.} =
+ self.Hud = self/"Hud" as Hud

proc newGame(self: Main) {.gdsync, name: "new_game".} =
+ self.Hud.updateScore(self.score)
+ self.Hud.showGetReady()

proc onScoreTimerTimeout(self: Main) {.gdsync, name: "_on_score_timer_timeout".} =
  inc self.score
+ self.Hud.updateScore(self.score)
# nim/nimmain/bootstrap.nim
  import gdext
  import classes/gdPlayer
  import classes/gdMob
  import classes/gdMain
+ import classes/gdHud


  GDExtensionEntryPoint

This completes the description of what is needed to port Dodge the Creeps to Nim. Have you been finishing up the project? That sounds good.

Want more comprehensive knowledge? Take a peek at our guide and documentation. Visit the demo and you'll find some content that actually works. My favorite is the chip-8 emulator. Thanks Flan.

This concludes this short tutorial. Thank you for reading this far.

« Previous: The main game scene

Clone this wiki locally