From ddf1bd019b725e596ef8377db8dcc7993fdc646e Mon Sep 17 00:00:00 2001 From: Minimata Date: Mon, 26 Jan 2026 18:09:29 +0100 Subject: [PATCH] better healthbars and one for the player as well --- components/health/CHealthbar.cs | 22 ++----- components/health/CHealthbar.cs.uid | 2 +- components/health/CHealthbar.tscn | 49 +++++++++------- player_controller/PlayerController.tscn | 18 +++++- player_controller/PlayerUi.cs | 15 ++++- player_controller/Scripts/PlayerController.cs | 2 + scenes/enemies/Enemy.cs | 7 ++- scenes/enemies/flying_enemy/flying_enemy.tscn | 8 ++- .../grounded_enemy/grounded_enemy.tscn | 8 ++- scenes/ui/Healthbar.cs | 58 +++++++++++++++++++ scenes/ui/Healthbar.cs.uid | 1 + scenes/ui/healthbar.tscn | 49 ++++++++++++++++ 12 files changed, 190 insertions(+), 49 deletions(-) create mode 100644 scenes/ui/Healthbar.cs create mode 100644 scenes/ui/Healthbar.cs.uid create mode 100644 scenes/ui/healthbar.tscn diff --git a/components/health/CHealthbar.cs b/components/health/CHealthbar.cs index 7947be6e..79f587a9 100644 --- a/components/health/CHealthbar.cs +++ b/components/health/CHealthbar.cs @@ -1,26 +1,14 @@ using Godot; using System; -using Movementtests.interfaces; [GlobalClass] -public partial class CHealthbar : Node3D +public partial class CHealthbar : Sprite3D { - private Sprite3D _currentHealth; - private float _initialXScale; - + private Healthbar _healthbar; + public Healthbar Healthbar => _healthbar; + public override void _Ready() { - Visible = false; - _currentHealth = GetNode("Health"); - _initialXScale = _currentHealth.Scale.X; - } - - public void OnHealthChanged(HealthChangedRecord healthChanged) - { - if (healthChanged.MaxHealth == 0) return; - - Visible = true; - var healthPercentage = healthChanged.CurrentHealth / healthChanged.MaxHealth; - _currentHealth.Scale = new Vector3(_initialXScale * healthPercentage, _currentHealth.Scale.Y, _currentHealth.Scale.Z); + _healthbar = GetNode("%Healthbar"); } } diff --git a/components/health/CHealthbar.cs.uid b/components/health/CHealthbar.cs.uid index 00a87e12..16e13cfc 100644 --- a/components/health/CHealthbar.cs.uid +++ b/components/health/CHealthbar.cs.uid @@ -1 +1 @@ -uid://dve6vg6yvg4y8 +uid://chfb3cjo6exga diff --git a/components/health/CHealthbar.tscn b/components/health/CHealthbar.tscn index 25ac28f3..24b581a9 100644 --- a/components/health/CHealthbar.tscn +++ b/components/health/CHealthbar.tscn @@ -1,27 +1,32 @@ -[gd_scene load_steps=3 format=3 uid="uid://bwx2um43k0ou4"] +[gd_scene load_steps=4 format=3 uid="uid://bwx2um43k0ou4"] -[ext_resource type="Texture2D" uid="uid://vpcxswwn1mt6" path="res://assets/ui/white-square-100px.png" id="1_jlvej"] -[ext_resource type="Script" uid="uid://dve6vg6yvg4y8" path="res://components/health/CHealthbar.cs" id="1_w5itk"] +[ext_resource type="Script" uid="uid://chfb3cjo6exga" path="res://components/health/CHealthbar.cs" id="1_w5itk"] +[ext_resource type="PackedScene" uid="uid://cyw8p0p6a78tl" path="res://scenes/ui/healthbar.tscn" id="2_w5itk"] -[node name="CHealthBar" type="Node3D"] +[sub_resource type="ViewportTexture" id="ViewportTexture_jkj2g"] +viewport_path = NodePath("SubViewport") + +[node name="CHealthBar" type="Sprite3D"] +billboard = 1 +double_sided = false +no_depth_test = true +texture = SubResource("ViewportTexture_jkj2g") script = ExtResource("1_w5itk") -[node name="Bar" type="Sprite3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 0.1, 0, 0, 0, 1, 0, 0, 0) -cast_shadow = 0 -billboard = 1 -transparent = false -double_sided = false -no_depth_test = true -texture = ExtResource("1_jlvej") +[node name="SubViewport" type="SubViewport" parent="."] +transparent_bg = true +size = Vector2i(520, 20) -[node name="Health" type="Sprite3D" parent="."] -transform = Transform3D(0.99, 0, 0, 0, 0.09, 0, 0, 0, 1, 0, 0, 0) -cast_shadow = 0 -modulate = Color(0.7191989, 0.19340843, 1.92523e-07, 1) -billboard = 1 -transparent = false -double_sided = false -no_depth_test = true -render_priority = 10 -texture = ExtResource("1_jlvej") +[node name="Healthbar" parent="SubViewport" instance=ExtResource("2_w5itk")] +unique_name_in_owner = true +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -120.0 +offset_top = -4.0 +offset_right = 120.0 +offset_bottom = 4.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/player_controller/PlayerController.tscn b/player_controller/PlayerController.tscn index 99263031..f76f81cf 100644 --- a/player_controller/PlayerController.tscn +++ b/player_controller/PlayerController.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=67 format=3 uid="uid://bei4nhkf8lwdo"] +[gd_scene load_steps=68 format=3 uid="uid://bei4nhkf8lwdo"] [ext_resource type="Script" uid="uid://bbbrf5ckydfna" path="res://player_controller/Scripts/PlayerController.cs" id="1_poq2x"] [ext_resource type="PackedScene" uid="uid://cf3rrgr1imvv4" path="res://scenes/path/path.tscn" id="2_6lejt"] @@ -52,6 +52,7 @@ [ext_resource type="Texture2D" uid="uid://chvt6g0xn5c2m" path="res://systems/dash/light-ring.jpg" id="32_lgpc8"] [ext_resource type="Script" uid="uid://b4dwolbvt8our" path="res://addons/godot_state_charts/history_state.gd" id="41_ruloh"] [ext_resource type="Texture2D" uid="uid://buu21kg4kkhiw" path="res://guide_examples/shared/fireball/fireball.svg" id="42_cmijs"] +[ext_resource type="PackedScene" uid="uid://cyw8p0p6a78tl" path="res://scenes/ui/healthbar.tscn" id="47_76kmc"] [sub_resource type="Resource" id="Resource_cb2lu"] script = ExtResource("2_x835q") @@ -510,6 +511,21 @@ grow_vertical = 2 texture = ExtResource("42_cmijs") expand_mode = 1 +[node name="Healthbar" parent="UI" instance=ExtResource("47_76kmc")] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 7 +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +offset_left = -120.0 +offset_top = -80.0 +offset_right = 119.99963 +offset_bottom = -71.99939 +grow_horizontal = 2 +grow_vertical = 0 + [node name="StateChart" type="Node" parent="."] script = ExtResource("25_wv70j") metadata/_custom_type_script = "uid://couw105c3bde4" diff --git a/player_controller/PlayerUi.cs b/player_controller/PlayerUi.cs index e5bf287f..d0f4a51f 100644 --- a/player_controller/PlayerUi.cs +++ b/player_controller/PlayerUi.cs @@ -1,10 +1,12 @@ using Godot; using System; +using Movementtests.interfaces; public partial class PlayerUi : Control { private TextureRect[] _dashIcons = new TextureRect[3]; private TextureRect _enemyTarget; + private Healthbar _healthbar; public enum TargetState { @@ -30,6 +32,12 @@ public partial class PlayerUi : Control _dashIcons[2] = GetNode("%Dash3"); _enemyTarget = GetNode("%EnemyTarget"); + _healthbar = GetNode("%Healthbar"); + } + + public void Initialize(float initialHealth) + { + _healthbar.Initialize(initialHealth); } public void SetEnemyTargetProperties(TargetProperties targetProperties) @@ -59,5 +67,10 @@ public partial class PlayerUi : Control dashIcon.SetVisible(index <= numberOfDashes); index++; } - } + } + + public void OnHealthChanged(IHealthable healthable, HealthChangedRecord healthChanged) + { + _healthbar.CurrentHealth = healthChanged.CurrentHealth; + } } diff --git a/player_controller/Scripts/PlayerController.cs b/player_controller/Scripts/PlayerController.cs index 55cb7222..372dc66e 100644 --- a/player_controller/Scripts/PlayerController.cs +++ b/player_controller/Scripts/PlayerController.cs @@ -430,8 +430,10 @@ public partial class PlayerController : CharacterBody3D, } if (RKnockback != null) CKnockback!.RKnockback = RKnockback; + PlayerUi.Initialize(CHealth.CurrentHealth); CDamageable.DamageTaken += (damageable, record) => ReduceHealth(damageable, record); CDamageable.DamageTaken += (damageable, record) => RegisterKnockback(new KnockbackRecord(record)); + CHealth.HealthChanged += PlayerUi.OnHealthChanged; CHealth.HealthDepleted += Kill; // State management diff --git a/scenes/enemies/Enemy.cs b/scenes/enemies/Enemy.cs index 158779d2..8fab2afe 100644 --- a/scenes/enemies/Enemy.cs +++ b/scenes/enemies/Enemy.cs @@ -57,7 +57,7 @@ public partial class Enemy : CharacterBody3D, // Private stuff private Area3D _damageBox; private Node3D _target; - private CHealthbar _healthbar; + private Healthbar _healthbar; public override void _Ready() { @@ -79,7 +79,7 @@ public partial class Enemy : CharacterBody3D, if (CHealth is null) GD.PrintErr("This node needs a 'CHealth' child of type IHealthable!"); if (CKnockback is null) GD.PrintErr("This node needs a 'CKnockback' child of type IKnockbackable!"); - _healthbar = GetNode("CHealthBar"); + _healthbar = GetNode("CHealthBar").Healthbar; if (RMovement != null) CMovement!.RMovement = RMovement; if (RHealth != null) @@ -88,6 +88,7 @@ public partial class Enemy : CharacterBody3D, CHealth.CurrentHealth = RHealth.StartingHealth; } if (RKnockback != null) CKnockback!.RKnockback = RKnockback; + _healthbar.Initialize(CHealth!.CurrentHealth); } public void SetupSignals() @@ -96,7 +97,7 @@ public partial class Enemy : CharacterBody3D, CDamageable.DamageTaken += (source, record) => ReduceHealth(source, record); CDamageable.DamageTaken += (source, record) => RegisterKnockback(new KnockbackRecord(record)); CHealth.HealthDepleted += Kill; - HealthChanged += (source, record) => _healthbar.OnHealthChanged(record); + HealthChanged += (source, record) => _healthbar.SetHealth(record.CurrentHealth); } public override void _PhysicsProcess(double delta) diff --git a/scenes/enemies/flying_enemy/flying_enemy.tscn b/scenes/enemies/flying_enemy/flying_enemy.tscn index 4534acc3..b2fd95ca 100644 --- a/scenes/enemies/flying_enemy/flying_enemy.tscn +++ b/scenes/enemies/flying_enemy/flying_enemy.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=21 format=3 uid="uid://cmlud1hwkd6sv"] +[gd_scene load_steps=22 format=3 uid="uid://cmlud1hwkd6sv"] [ext_resource type="Script" uid="uid://bn7sc6id7n166" path="res://scenes/enemies/Enemy.cs" id="1_q8l7o"] [ext_resource type="Script" uid="uid://b6y3ugfydvch0" path="res://components/damage/RDamageModifier.cs" id="2_1bsgx"] @@ -13,6 +13,9 @@ [ext_resource type="PackedScene" uid="uid://bctpe34ddamg5" path="res://components/knockback/CKnockback.tscn" id="10_dejyg"] [ext_resource type="Resource" uid="uid://dt7a1io5o0b8s" path="res://scenes/enemies/flying_enemy/flying_enemy_knockback.tres" id="11_mpa2u"] +[sub_resource type="ViewportTexture" id="ViewportTexture_ykkxn"] +viewport_path = NodePath("SubViewport") + [sub_resource type="Resource" id="Resource_jnv07"] script = ExtResource("2_1bsgx") metadata/_custom_type_script = "uid://b6y3ugfydvch0" @@ -62,7 +65,8 @@ RHealth = ExtResource("2_ma2bq") metadata/_custom_type_script = "uid://bjwrpv3jpsc1e" [node name="CHealthBar" parent="." instance=ExtResource("7_ykkxn")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.70000005, 0) +transform = Transform3D(0.3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.70000005, 0) +texture = SubResource("ViewportTexture_ykkxn") [node name="CDamageable" type="Node" parent="."] script = ExtResource("8_uotso") diff --git a/scenes/enemies/grounded_enemy/grounded_enemy.tscn b/scenes/enemies/grounded_enemy/grounded_enemy.tscn index ee48b7cc..a629eab7 100644 --- a/scenes/enemies/grounded_enemy/grounded_enemy.tscn +++ b/scenes/enemies/grounded_enemy/grounded_enemy.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=21 format=3 uid="uid://dxt0e2ugmttqq"] +[gd_scene load_steps=22 format=3 uid="uid://dxt0e2ugmttqq"] [ext_resource type="Script" uid="uid://bn7sc6id7n166" path="res://scenes/enemies/Enemy.cs" id="1_r6506"] [ext_resource type="Resource" uid="uid://otfc2snh8umc" path="res://scenes/enemies/grounded_enemy/grounded_enemy_damage.tres" id="2_bn56u"] @@ -13,6 +13,9 @@ [ext_resource type="PackedScene" uid="uid://bctpe34ddamg5" path="res://components/knockback/CKnockback.tscn" id="10_jqqi6"] [ext_resource type="Resource" uid="uid://cektf6waf4s04" path="res://scenes/enemies/grounded_enemy/grounded_enemy_knockback.tres" id="11_8k3xb"] +[sub_resource type="ViewportTexture" id="ViewportTexture_18xwy"] +viewport_path = NodePath("SubViewport") + [sub_resource type="Resource" id="Resource_qj0ob"] script = ExtResource("2_r3cnf") Modifier = 1.0 @@ -62,7 +65,8 @@ RHealth = ExtResource("2_w4lm8") metadata/_custom_type_script = "uid://bjwrpv3jpsc1e" [node name="CHealthBar" parent="." instance=ExtResource("7_18xwy")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.2, 0) +transform = Transform3D(0.4, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.2, 0) +texture = SubResource("ViewportTexture_18xwy") [node name="CDamageable" type="Node" parent="."] script = ExtResource("7_1tw73") diff --git a/scenes/ui/Healthbar.cs b/scenes/ui/Healthbar.cs new file mode 100644 index 00000000..ea8259ad --- /dev/null +++ b/scenes/ui/Healthbar.cs @@ -0,0 +1,58 @@ +using Godot; +using System; + +[GlobalClass] +public partial class Healthbar : ProgressBar +{ + private Timer _damageCatchUpTimer; + private ProgressBar _damagedHealth; + + private float _currentHealth; + public float CurrentHealth + { + get => _currentHealth; + set => SetHealth(value); + } + + public override void _Ready() + { + _damageCatchUpTimer = GetNode("DamageCatchUp"); + _damagedHealth = GetNode("Damagebar"); + + _damageCatchUpTimer.Timeout += OnDamageCatchUp; + Visible = false; + } + + public void Initialize(float initialHealth) + { + _currentHealth = initialHealth; + MaxValue = initialHealth; + Value = initialHealth; + _damagedHealth.MaxValue = initialHealth; + _damagedHealth.Value = initialHealth; + } + + public void SetHealth(float newHealth) + { + var previousHealth = _currentHealth; + _currentHealth = Mathf.Min(newHealth, (float) MaxValue); + _currentHealth = newHealth; + Value = _currentHealth; + + Visible = _currentHealth < MaxValue; + + if (_currentHealth < previousHealth) + { + _damageCatchUpTimer.Start(); + } + else + { + _damagedHealth.Value = _currentHealth; + } + } + + public void OnDamageCatchUp() + { + _damagedHealth.Value = _currentHealth; + } +} diff --git a/scenes/ui/Healthbar.cs.uid b/scenes/ui/Healthbar.cs.uid new file mode 100644 index 00000000..d9363aca --- /dev/null +++ b/scenes/ui/Healthbar.cs.uid @@ -0,0 +1 @@ +uid://l5cjcaehyssk diff --git a/scenes/ui/healthbar.tscn b/scenes/ui/healthbar.tscn new file mode 100644 index 00000000..e8c1708f --- /dev/null +++ b/scenes/ui/healthbar.tscn @@ -0,0 +1,49 @@ +[gd_scene load_steps=6 format=3 uid="uid://cyw8p0p6a78tl"] + +[ext_resource type="Script" uid="uid://l5cjcaehyssk" path="res://scenes/ui/Healthbar.cs" id="1_0k5hr"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_0sgot"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0k5hr"] +bg_color = Color(0.698864, 0.047356047, 0, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0sgot"] +bg_color = Color(0.14767182, 0.14767182, 0.14767176, 1) +expand_margin_left = 2.0 +expand_margin_top = 2.0 +expand_margin_right = 2.0 +expand_margin_bottom = 2.0 +shadow_color = Color(0, 0, 0, 0.27450982) +shadow_offset = Vector2(0, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kl70x"] +bg_color = Color(0.8862616, 0.88626146, 0.8862615, 1) + +[node name="Healthbar" type="ProgressBar"] +z_index = 10 +custom_minimum_size = Vector2(512, 12) +offset_right = 512.0 +offset_bottom = 12.0 +theme_override_styles/background = SubResource("StyleBoxEmpty_0sgot") +theme_override_styles/fill = SubResource("StyleBoxFlat_0k5hr") +value = 60.0 +show_percentage = false +script = ExtResource("1_0k5hr") + +[node name="Damagebar" type="ProgressBar" parent="."] +z_index = -10 +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/background = SubResource("StyleBoxFlat_0sgot") +theme_override_styles/fill = SubResource("StyleBoxFlat_kl70x") +value = 80.0 +show_percentage = false + +[node name="DamageCatchUp" type="Timer" parent="."] +wait_time = 0.8 +one_shot = true +ignore_time_scale = true