From 9c0cd3f5493d4f8f9fbebb7bee0504181f777d24 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Wed, 29 Oct 2025 02:59:02 +0100 Subject: [PATCH] Add HUD presenter component and player HUD scene for health and ammo display --- Code/Presenters/HudPresenterComponent.cs | 121 +++++++++++++++++++ Code/Presenters/HudPresenterComponent.cs.uid | 1 + Objects/UI/player_hud.tscn | 46 +++++++ Objects/player.tscn | 5 +- project.godot | 1 + 5 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 Code/Presenters/HudPresenterComponent.cs create mode 100644 Code/Presenters/HudPresenterComponent.cs.uid create mode 100644 Objects/UI/player_hud.tscn diff --git a/Code/Presenters/HudPresenterComponent.cs b/Code/Presenters/HudPresenterComponent.cs new file mode 100644 index 0000000..98d44a6 --- /dev/null +++ b/Code/Presenters/HudPresenterComponent.cs @@ -0,0 +1,121 @@ +using System.Linq; +using GameCore.Attributes; +using GameCore.Combat; +using GameCore.Combat.Effects; +using GameCore.ECS; +using GameCore.ECS.Interfaces; +using GameCore.Events; +using GameCore.Inventory; +using GameCore.Player; +using Godot; + +namespace CryptonymThunder.Code.Presenters; + +[GlobalClass] +public partial class HudPresenterComponent : Control, IPresenterComponent +{ + private World _world; + private Entity _playerEntity; + private AttributeComponent _playerAttributes; + private EquipmentComponent _playerEquipment; + private InventoryComponent _playerInventory; + + [Export] private Label _healthLabel; + [Export] private Label _ammoLabel; + [Export] private Label _weaponLabel; + + private string _currentAmmoId; + + public void Initialize(Entity coreEntity, World world) + { + _world = world; + _playerEntity = coreEntity; + + _playerAttributes = world.GetComponent(_playerEntity); + _playerEquipment = world.GetComponent(_playerEntity); + _playerInventory = world.GetComponent(_playerEntity); + + if (_playerAttributes != null) + { + _playerAttributes.OnAttributeChanged += OnAttributeChanged; + OnAttributeChanged(Attribute.Health, _playerAttributes.GetValue(Attribute.Health)); + } + + _world.Subscribe(OnEntityDamaged); + _world.Subscribe(OnEntityHealed); + _world.Subscribe(OnInventoryChanged); + _world.Subscribe(OnWeaponEquipped); + } + + private void OnWeaponEquipped(WeaponEquippedEvent e) + { + if (!e.Owner.Equals(_playerEntity)) return; + _weaponLabel.Text = e.NewWeaponItemId; + + _currentAmmoId = null; + + var playerWeapon = _world.GetComponent(_playerEntity); + var ammoCost = playerWeapon?.FireCosts + .OfType() + .FirstOrDefault(); + + if (ammoCost != null) + { + _currentAmmoId = ammoCost.AmmoId; + } + + _world.Logger.Info($"Current ammo ID set to {_currentAmmoId}"); + + if (_currentAmmoId != null) + { + var ammoCount = _playerInventory.GetItemCount(_currentAmmoId); + _ammoLabel.Text = $"Ammo: {ammoCount}"; + } + else + { + _ammoLabel.Text = "Ammo: --"; + } + } + + private void OnInventoryChanged(InventoryItemChangedEvent e) + { + if (!e.Owner.Equals(_playerEntity)) return; + + _world.Logger.Info($"Inventory changed: {e.ItemId} new quantity: {e.NewQuantity}"); + + if (e.ItemId == _currentAmmoId) + { + _ammoLabel.Text = $"Ammo: {e.NewQuantity}"; + } + } + + private void OnEntityHealed(EntityHealedEvent e) + { + if (!e.Target.Equals(_playerEntity)) return; + + _world.Logger.Info($"Player healed {e.AmountHealed}, new health: {e.NewHealth}"); + } + + private void OnEntityDamaged(EntityDamagedEvent e) + { + if (!e.Target.Equals(_playerEntity)) return; + + _world.Logger.Info($"Player took {e.DamageTaken} damage, new health: {e.NewHealth}"); + } + + private void OnAttributeChanged(Attribute attr, float newValue) + { + if (attr == Attribute.Health) + { + _healthLabel.Text = $"Health: {Mathf.CeilToInt(newValue)}"; + } + } + + public void SyncToPresentation(float delta) + { + } + + public void SyncToCore(float delta) + { + } +} \ No newline at end of file diff --git a/Code/Presenters/HudPresenterComponent.cs.uid b/Code/Presenters/HudPresenterComponent.cs.uid new file mode 100644 index 0000000..60933cc --- /dev/null +++ b/Code/Presenters/HudPresenterComponent.cs.uid @@ -0,0 +1 @@ +uid://c6nouigv5wsu1 diff --git a/Objects/UI/player_hud.tscn b/Objects/UI/player_hud.tscn new file mode 100644 index 0000000..6faa2d5 --- /dev/null +++ b/Objects/UI/player_hud.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=2 format=3 uid="uid://b36xmciamjyc0"] + +[ext_resource type="Script" uid="uid://c6nouigv5wsu1" path="res://Code/Presenters/HudPresenterComponent.cs" id="1_yd76s"] + +[node name="PlayerHUD" type="Control" node_paths=PackedStringArray("_healthLabel", "_ammoLabel", "_weaponLabel")] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_yd76s") +_healthLabel = NodePath("MarginContainer/HBoxContainer/HealthLabel") +_ammoLabel = NodePath("MarginContainer/HBoxContainer/AmmoLabel") +_weaponLabel = NodePath("MarginContainer/HBoxContainer/WeaponLabel") +metadata/_custom_type_script = "uid://c6nouigv5wsu1" + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 8 +theme_override_constants/margin_top = 8 +theme_override_constants/margin_right = 8 +theme_override_constants/margin_bottom = 8 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] +layout_mode = 2 + +[node name="HealthLabel" type="Label" parent="MarginContainer/HBoxContainer"] +layout_mode = 2 +text = "health 100" +uppercase = true + +[node name="AmmoLabel" type="Label" parent="MarginContainer/HBoxContainer"] +layout_mode = 2 +text = "ammo 100" +uppercase = true + +[node name="WeaponLabel" type="Label" parent="MarginContainer/HBoxContainer"] +layout_mode = 2 +text = "gun" +uppercase = true diff --git a/Objects/player.tscn b/Objects/player.tscn index 11919d8..0395f91 100644 --- a/Objects/player.tscn +++ b/Objects/player.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=5 format=3 uid="uid://c576jiewfs5gj"] +[gd_scene load_steps=6 format=3 uid="uid://c576jiewfs5gj"] [ext_resource type="Script" uid="uid://hkiny1ftv4r7" path="res://Code/Presenters/CharacterBody3DPresenter.cs" id="2_3y5cq"] +[ext_resource type="PackedScene" uid="uid://b36xmciamjyc0" path="res://Objects/UI/player_hud.tscn" id="3_0ad8t"] [ext_resource type="Script" uid="uid://crx03e8buoni3" path="res://Code/Presenters/CameraPresenterComponent.cs" id="3_2i4gt"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_y0qk3"] @@ -26,3 +27,5 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5901337, 0) script = ExtResource("3_2i4gt") [node name="Camera3D" type="Camera3D" parent="CameraPivot"] + +[node name="PlayerHUD" parent="." instance=ExtResource("3_0ad8t")] diff --git a/project.godot b/project.godot index c3abb5f..fabaf39 100644 --- a/project.godot +++ b/project.godot @@ -28,6 +28,7 @@ project/assembly_name="cryptonym-thunder" folder_colors={ "res://Code/": "blue", "res://Objects/": "orange", +"res://Objects/UI/": "green", "res://Scenes/": "green" }