From df449af0f362f6bea9189018b76eef9927a502a3 Mon Sep 17 00:00:00 2001 From: Jeremy Baxter Date: Thu, 22 Jan 2026 17:40:18 +1300 Subject: [PATCH 1/5] player: rename BackpackUI to HUD --- player/player.gd | 26 +++++++++++++------------- player/player.tscn | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/player/player.gd b/player/player.gd index fe99f5a..a849ce4 100644 --- a/player/player.gd +++ b/player/player.gd @@ -16,21 +16,21 @@ var direction = Vector3.ZERO var target_velocity = Vector3.ZERO func resize_ui(): - var bpui_h = 200 + var hud_h = 200 var size = get_viewport().get_visible_rect().size $Message.size.x = size.x - $BackpackUI.size.x = size.x - $BackpackUI.size.y = bpui_h - $BackpackUI.position.x = 0 - $BackpackUI.position.y = size.y - bpui_h + $HUD.size.x = size.x + $HUD.size.y = hud_h + $HUD.position.x = 0 + $HUD.position.y = size.y - hud_h -func make_backpack_ui(): +func make_hud(): var text = "Holding " + $Pivot/Container/Gear.gear_name() for node in $Backpack.get_children(): if not node is Gear: continue text += "\n%s (%s)" % [node.gear_name(), node.name] - $BackpackUI.text = text + $HUD.text = text func message(string): $Message.text = string @@ -40,7 +40,7 @@ func message(string): func die(): suspended = true visible = false - $BackpackUI.visible = false + $HUD.visible = false # strip gears for gear in $Backpack.get_children(): @@ -61,8 +61,8 @@ func respawn(): var gear = starting_gear.instantiate() $Pivot/Container.add_child(gear) - make_backpack_ui() - $BackpackUI.visible = true + make_hud() + $HUD.visible = true # Backpack functions @@ -87,7 +87,7 @@ func use_backpack_slot(n): old.reparent($Backpack, false) get_node(gear_node).reparent($Pivot/Container, false) get_node("Pivot/Container/" + n).name = "Gear" - make_backpack_ui() + make_hud() return # couldn't find a free slot, so replace # the new slot with the current gear @@ -95,7 +95,7 @@ func use_backpack_slot(n): old.reparent($Backpack, false) old.name = n get_node("Pivot/Container/" + n).name = "Gear" - make_backpack_ui() + make_hud() return func equip(gear: Gear): @@ -120,7 +120,7 @@ func equip(gear: Gear): new_gear = gear.duplicate() new_gear.name = "Gear" $Pivot/Container.add_child(new_gear) - make_backpack_ui() + make_hud() message("You picked up a " + gear_name + "!") return true # if no slots are free diff --git a/player/player.tscn b/player/player.tscn index 3da27e3..10a0f29 100644 --- a/player/player.tscn +++ b/player/player.tscn @@ -93,7 +93,7 @@ vertical_alignment = 1 wait_time = 4.0 one_shot = true -[node name="BackpackUI" type="Label" parent="."] +[node name="HUD" type="Label" parent="."] offset_right = 200.0 offset_bottom = 200.0 text = "Pictures of you" From 47aa5ac9aa099fbb1fce2facfd53c154a7464214 Mon Sep 17 00:00:00 2001 From: Jeremy Baxter Date: Thu, 22 Jan 2026 20:54:21 +1300 Subject: [PATCH 2/5] player: display health in HUD --- player/player.gd | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/player/player.gd b/player/player.gd index a849ce4..02bba3c 100644 --- a/player/player.gd +++ b/player/player.gd @@ -25,11 +25,13 @@ func resize_ui(): $HUD.position.y = size.y - hud_h func make_hud(): - var text = "Holding " + $Pivot/Container/Gear.gear_name() + var text = "" for node in $Backpack.get_children(): if not node is Gear: continue - text += "\n%s (%s)" % [node.gear_name(), node.name] + text += "%s (%s)\n" % [node.gear_name(), node.name] + text += "Holding " + $Pivot/Container/Gear.gear_name() + "\n" + text += str(health) + " hp" $HUD.text = text func message(string): From e6cbaba0fadeab7482784a085470d126dadab25d Mon Sep 17 00:00:00 2001 From: Jeremy Baxter Date: Thu, 22 Jan 2026 21:11:05 +1300 Subject: [PATCH 3/5] player: add health callbacks Allows us to update the HUD on health change --- player/player.gd | 22 ++++++++++++++++++---- world/killbrick.gd | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/player/player.gd b/player/player.gd index 02bba3c..b91bccc 100644 --- a/player/player.gd +++ b/player/player.gd @@ -10,11 +10,12 @@ const gear_slots = ["1", "2", "3"] var starting_gear = preload("res://gears/ball.tscn") -var health = 100 var suspended = false var direction = Vector3.ZERO var target_velocity = Vector3.ZERO +var _health = 100 + func resize_ui(): var hud_h = 200 var size = get_viewport().get_visible_rect().size @@ -31,7 +32,7 @@ func make_hud(): continue text += "%s (%s)\n" % [node.gear_name(), node.name] text += "Holding " + $Pivot/Container/Gear.gear_name() + "\n" - text += str(health) + " hp" + text += str(health()) + " hp" $HUD.text = text func message(string): @@ -39,6 +40,19 @@ func message(string): $Message.visible = true $Message/VanishTimer.start() +func harm(hp): + assert(hp >= 0) + _health -= hp + make_hud() + +func heal(hp): + assert(hp >= 0) + _health += hp + make_hud() + +func health(): + return _health + func die(): suspended = true visible = false @@ -55,7 +69,7 @@ func die(): func respawn(): position = Vector3(spawn) $CameraGimbal.reset() - health = 100 + _health = 100 visible = true suspended = false @@ -159,7 +173,7 @@ func _physics_process(delta): if suspended: return - if health < 1 or position.y <= -1000: + if health() < 1 or position.y <= -1000: die() # UI and backpack keys diff --git a/world/killbrick.gd b/world/killbrick.gd index c587fe8..45f437b 100644 --- a/world/killbrick.gd +++ b/world/killbrick.gd @@ -2,4 +2,4 @@ extends Area3D func _on_body_entered(body: Node3D): if body is Player: - body.health = 0 + body.die() From 42de0ed122bfe4ed87c57e7d5cdcab397bc0cb86 Mon Sep 17 00:00:00 2001 From: Jeremy Baxter Date: Thu, 22 Jan 2026 21:17:47 +1300 Subject: [PATCH 4/5] player: organise code --- player/player.gd | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/player/player.gd b/player/player.gd index b91bccc..48f08e0 100644 --- a/player/player.gd +++ b/player/player.gd @@ -16,6 +16,8 @@ var target_velocity = Vector3.ZERO var _health = 100 +# Player UI + func resize_ui(): var hud_h = 200 var size = get_viewport().get_visible_rect().size @@ -40,6 +42,8 @@ func message(string): $Message.visible = true $Message/VanishTimer.start() +# State functions + func harm(hp): assert(hp >= 0) _health -= hp @@ -143,7 +147,7 @@ func equip(gear: Gear): message("Backpack full") return false -# Player movement and engine callbacks +# Player mechanics func move_player(x, z): var camera_basis = $CameraGimbal.get_global_transform().basis @@ -164,19 +168,7 @@ func move_player(x, z): if x != 0: direction += camera_basis.x * x -func _ready(): - get_viewport().size_changed.connect(resize_ui) - resize_ui() - respawn() - -func _physics_process(delta): - if suspended: - return - - if health() < 1 or position.y <= -1000: - die() - - # UI and backpack keys +func do_backpack_keys(): if Input.is_action_just_pressed("backpack_1"): use_backpack_slot("1") if Input.is_action_just_pressed("backpack_2"): @@ -184,7 +176,7 @@ func _physics_process(delta): if Input.is_action_just_pressed("backpack_3"): use_backpack_slot("3") - # Movement keys +func do_movement(delta): var mx = 0 var mz = 0 @@ -212,7 +204,7 @@ func _physics_process(delta): move_and_slide() - # Gear uses +func do_gears(): var gear = $Pivot/Container/Gear assert(gear is Gear) if gear.continuous(): @@ -222,6 +214,27 @@ func _physics_process(delta): if Input.is_action_just_pressed("gear_use"): gear.use(self) +# Engine callbacks + +func _ready(): + get_viewport().size_changed.connect(resize_ui) + resize_ui() + respawn() + +func _physics_process(delta): + if health() < 1 or position.y <= -1000: + die() + + if suspended: + return + + # Backpack keys + do_backpack_keys() + # Movement + do_movement(delta) + # Use gears + do_gears() + # Signals func _on_vanish_timer_timeout(): From 9a0ff2dd1b9fd1e1c19a002d7783fff30af85c34 Mon Sep 17 00:00:00 2001 From: Simon Ward Date: Thu, 22 Jan 2026 21:48:53 +1300 Subject: [PATCH 5/5] world: added grass and sky --- Shaders/SkyShader.gdshader | 9 +++++++++ Textures/grass.jpg | Bin 0 -> 18669 bytes main.tscn | 37 +++++++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 Shaders/SkyShader.gdshader create mode 100644 Textures/grass.jpg diff --git a/Shaders/SkyShader.gdshader b/Shaders/SkyShader.gdshader new file mode 100644 index 0000000..504da4e --- /dev/null +++ b/Shaders/SkyShader.gdshader @@ -0,0 +1,9 @@ +shader_type sky; +uniform vec3 skyColor : source_color; +uniform vec3 horizonColor : source_color; + +void sky() { + float col = clamp(EYEDIR.y / 0.05, 0.0, 1.0); + vec3 finalColor = mix(horizonColor,skyColor,col); + COLOR = finalColor; +} diff --git a/Textures/grass.jpg b/Textures/grass.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4efd863ee7f75cf0fe58e9945ab5a9d19278a3c4 GIT binary patch literal 18669 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 XKE)Do-1|