All lessons
Lesson 13

Win and Lose Screen

Two zones, two endings, one full-screen panel. Uses a flag so the game can only end once.

Loading the game engine. This takes a moment the first time.

Two zones. Green wins, red loses. Either one ends the game and brings up the full screen panel.

The scenes

UI node · 2D node · % unique name · .tscn instanced scene

win_and_lose_screen.tscn
  • WinAndLoseScreen Node2D win_and_lose_screen.gd
  • WinLosePlayer CharacterBody2D player.tscn
  • WinZone Area2D %
  • ColorRect
  • CollisionShape2D
  • LoseZone Area2D %
  • ColorRect
  • CollisionShape2D
  • GameOverPanel CanvasLayer game_over_panel.tscn
game_over_panel.tscn
  • GameOverPanel CanvasLayer game_over_panel.gd
  • Overlay Control %
  • Dim ColorRect
  • CenterContainer
  • VBoxContainer
  • MessageLabel Label %
  • PlayAgainButton Button %
  • HomeButton Button %
player.tscn
  • WinLosePlayer CharacterBody2D player.gd
  • Sprite2D
  • CollisionShape2D
extends Node2D

# "$GameOverPanel" is the node named GameOverPanel, sitting under this one.
@onready var game_over_panel: GameOverPanel = $GameOverPanel

## Once the game is over, ignore any more zone touches.
var is_game_over: bool = false

func _ready() -> void:
	%WinZone.body_entered.connect(_on_win_zone_entered)
	%LoseZone.body_entered.connect(_on_lose_zone_entered)

func _on_win_zone_entered(body: Node2D) -> void:
	# Two reasons to quit early: the game already ended, or the thing that
	# touched the zone was not the player. "not (...)" flips true and false.
	if is_game_over or not (body is WinLosePlayer):
		return
	# Set the flag FIRST, so a second touch cannot get past the line above.
	is_game_over = true
	# GameOverPanel is our child, so we skip signals and call its function.
	game_over_panel.show_win()

func _on_lose_zone_entered(body: Node2D) -> void:
	if is_game_over or not (body is WinLosePlayer):
		return
	is_game_over = true
	game_over_panel.show_lose()