Score bijhouden in je karakter
Je raapt nu muntjes op, maar je weet niet hoeveel. In deze les voeg je een score toe die elke keer met 1 omhoog gaat als je een muntje raakt.
Geschreven voor Godot 4.7.x — zie Godot-versies voor compatibiliteit.
Voorspel: waar leeft de score?
In welk script zou jij de variabele score aanmaken?
- In het muntje-script?
- In het karakter-script?
- Ergens anders?
Antwoord
Het muntje is geen goede plek: zodra het muntje wordt opgepakt, verdwijnt het via queue_free() — en daarmee ook zijn score-variabele.
Het karakter is een logische plek: de speler "draagt" zijn eigen score. Zolang het karakter bestaat, bestaat de score.
(In de volgende lessen ontdek je dat een nóg betere plek bestaat: een globale variabele die ook tussen scènes overleeft.)
Stap 1: Voeg score toe aan je karakter
Open het script van je CharacterBody2D en voeg bovenaan een variabele toe:
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -800.0
var score = 0
# ... rest van je script
Stap 2: Hoog de score op vanuit het muntje
Open het script van je muntje. In _on_body_entered heb je al een parameter body — dat is de node die het muntje aanraakt (jouw karakter). Vanuit het muntje kun je dus rechtstreeks bij body.score.
extends Area2D
func _on_body_entered(body: Node2D) -> void:
body.score += 1
print("Score: ", body.score)
queue_free()
| Code | Wat doet het? |
|---|---|
body | De node die het muntje raakt (jouw karakter) |
body.score | De score-variabele van die node |
body.score += 1 | Verhoog de score met 1 |
Stap 3: Test het
Start het spel met F5 en pak een paar muntjes op. Kijk in Uitvoer onderaan:
Score: 1
Score: 2
Score: 3
Voorspel: hoe krijg ik dit op het scherm?
Het werkt in Uitvoer, maar je wilt het op het scherm zien. Hoe zou je dat aanpakken?
Bekijk een (broze) poging
Je zou een Label kunnen toevoegen en in een Label-script proberen het karakter op te zoeken:
extends Label
func _process(delta: float) -> void:
text = "Score: " + str(get_node("../CharacterBody2D").score)
Maak je geen zorgen als
_processenstrnieuw zijn — die komen in Score op het scherm tonen aan bod. Dit voorbeeld is alleen om de pijn te laten zien.
Dit werkt — zolang je karakter precies CharacterBody2D heet en op de juiste plek in de Scene Tree staat. Verschuif of hernoem je iets, of laad je een nieuw level? Crash. In de volgende les (Global variables) zie je een schonere oplossing.
Opdracht 7.2.a: levens met Game Over
Je hebt nu een score in je karakter. Voeg er een levens-systeem aan toe en laat het spel reageren als ze op zijn.
- Voeg
var levens = 3toe aan je karakter. - Laat de vijand (uit Signals & muntje) bij contact
body.levens -= 1doen en de waarde printen. - Nieuw: als
body.levensop 0 (of lager) komt, print"GAME OVER"in Uitvoer en sluit het spel metget_tree().quit().
Klik hier voor een tip.
- Voeg
var levens = 3toe ondervar score = 0in je karakter-script. - Open je vijand-script.
- Pas
_on_body_enteredaan zodat hij eerstbody.levens -= 1doet en print. - Voeg een
if-blok toe:if body.levens <= 0:met daarbinnen de print enget_tree().quit(). - Let op de indentatie: alles binnen het
if-blok moet één tab inspringen.
Klik hier voor de oplossing.
In je karakter-script:
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -800.0
var score = 0
var levens = 3
# ... rest van je script
In je vijand-script:
extends Area2D
func _on_body_entered(body: Node2D) -> void:
body.levens -= 1
print("Levens: ", body.levens)
if body.levens <= 0:
print("GAME OVER")
get_tree().quit()
queue_free()
get_tree().quit() sluit het hele spel-venster. In een echte game zou je hier een Game Over-scherm laten zien — dat leer je later. Voor nu zie je in elk geval dat de check werkt.
Er gaat iets mis
Foutmelding: Invalid access to property or key 'score' on a base object of type 'TileMapLayer'.
Oorzaak: Je muntje raakt de grond. Voor een Area2D is je TileMapLayer met collision ook een body, dus _on_body_entered krijgt dan de grond in plaats van je karakter. De grond heeft geen score. Achteraan de melding staat wat body was: TileMapLayer.
Zo zie je de melding zelf, met een muntje dat de grond als body krijgt:
# FOUT
extends Area2D
func _ready() -> void:
_on_body_entered(TileMapLayer.new())
func _on_body_entered(body: Node2D) -> void:
body.score += 1
Oplossing: Zet het muntje iets hoger, zodat zijn CollisionShape2D de tegels niet raakt. Wil je zeker zijn dat alleen je karakter telt, zet dan if body is CharacterBody2D: boven de regel met score en laat die regel eronder inspringen.
Mijn score begint elke keer weer bij 0 als ik het spel herstart
Oorzaak: Bij opnieuw starten wordt het karakter opnieuw aangemaakt, en dus ook var score = 0. De score leeft maar zolang het karakter bestaat.
Oplossing: Dit lossen we op in Global variables — variabelen die buiten één node leven.