Lesson 06
Stakes make exploration matter. We add a hazard zone that resets the player to a safe spawn point when touched. Same Area3D pattern as fragments, different consequence.
main.tscn. Add a child Marker3D to Main, rename it SpawnPoint. Position it somewhere safe on the floor (y ≈ 1).Marker3D
A Marker3D is an invisible position holder — no mesh, no collision, just a transform. Ideal for spawn points, patrol targets, and camera anchors. It shows as a small cross in the editor and nothing in-game.
Hazard. Save as hazard.tscn.Attach hazard.gd:
extends Area3D
# Emitted when the player touches the hazard.
signal player_hit(body: Node3D)
func _ready() -> void:
body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
player_hit.emit(body)Signal up, don't act down
The hazard doesn't move the player itself — it announces a hit and lets Main decide what happens (respawn now, later maybe lose a life). Emitting signals instead of reaching across the scene keeps each piece independent and easy to change.
hazard.tscn under Main and place it in the player's path.hazards.Extend main.gd to wire hazards and respawn the player at the marker:
@onready var spawn_point: Marker3D = $SpawnPoint
@onready var player: CharacterBody3D = $Player
func _ready() -> void:
var frags: Array = get_tree().get_nodes_in_group("fragments")
total_fragments = frags.size()
for frag in frags:
frag.collected.connect(_on_fragment_collected)
for hz in get_tree().get_nodes_in_group("hazards"):
hz.player_hit.connect(_on_player_hit)
_respawn_player() # start the player at the spawn point
func _on_player_hit(_body: Node3D) -> void:
_respawn_player()
func _respawn_player() -> void:
player.velocity = Vector3.ZERO
player.global_position = spawn_point.global_positionZero the velocity on respawn
If you teleport the player without resetting velocity, any downward speed from falling carries over and they may immediately clip or shoot off. Always zero velocity when repositioning a physics body.
global_position vs position
Use global_position to place the player at the marker's world location. Plain position is relative to the parent — if Main is at origin they happen to match, but global_position is the correct, robust choice.
Checkpoint — expected state
SpawnPoint Marker3D and a hazard.tscn Area3D.player_hit; Main respawns the player at the marker.global_position is used on respawn.