diff --git a/Movement tests.sln.DotSettings.user b/Movement tests.sln.DotSettings.user
index c6ee6542..7ffbec7a 100644
--- a/Movement tests.sln.DotSettings.user
+++ b/Movement tests.sln.DotSettings.user
@@ -1,4 +1,5 @@
+ ForceIncluded
ForceIncluded
ForceIncluded
True
\ No newline at end of file
diff --git a/interfaces/IDamageable.cs b/interfaces/IDamageable.cs
index 45ff698d..f32b8a33 100644
--- a/interfaces/IDamageable.cs
+++ b/interfaces/IDamageable.cs
@@ -1,8 +1,9 @@
-using Godot;
+using System;
namespace Movementtests.interfaces;
public interface IDamageable
{
- void TakeDamage(RDamage damage);
+ event Action DamageTaken;
+ float TakeDamage(RDamage damage);
}
\ No newline at end of file
diff --git a/interfaces/IHealthable.cs b/interfaces/IHealthable.cs
index 0f0fd3e7..a86d72f5 100644
--- a/interfaces/IHealthable.cs
+++ b/interfaces/IHealthable.cs
@@ -1,7 +1,6 @@
namespace Movementtests.interfaces;
-public interface IKillable
+public interface IHealthable
{
- float CurrentHealth { get; set; }
void ReduceHealth(float amount);
}
\ No newline at end of file
diff --git a/interfaces/IKillable.cs b/interfaces/IKillable.cs
index 4cc1c8d5..ce532e6e 100644
--- a/interfaces/IKillable.cs
+++ b/interfaces/IKillable.cs
@@ -1,7 +1,6 @@
namespace Movementtests.interfaces;
-public interface IHealthable
+public interface IKillable
{
- float CurrentHealth { get; set; }
- void ReduceHealth(float amount);
+ void Kill();
}
\ No newline at end of file
diff --git a/interfaces/IKillable.cs.uid b/interfaces/IKillable.cs.uid
new file mode 100644
index 00000000..575bd80b
--- /dev/null
+++ b/interfaces/IKillable.cs.uid
@@ -0,0 +1 @@
+uid://dqpjr2d01sk1a
diff --git a/interfaces/NodeExtensions.cs b/interfaces/NodeExtensions.cs
index e3c066d4..b16e24a4 100644
--- a/interfaces/NodeExtensions.cs
+++ b/interfaces/NodeExtensions.cs
@@ -9,4 +9,8 @@ public static class NodeExtensions
{
return nodes == null ? System.Array.Empty() : nodes.OfType().ToArray();
}
+ public static IKillable[] ToIKillables(this GodotObject[] nodes)
+ {
+ return nodes == null ? System.Array.Empty() : nodes.OfType().ToArray();
+ }
}
\ No newline at end of file
diff --git a/maps/GYMs/enemies.tscn b/maps/GYMs/enemies.tscn
index f46011b3..b60db4ec 100644
--- a/maps/GYMs/enemies.tscn
+++ b/maps/GYMs/enemies.tscn
@@ -54,7 +54,7 @@ metadata/_custom_type_script = "uid://b2vdwkiqauhk3"
[sub_resource type="Resource" id="Resource_caohq"]
script = ExtResource("6_7m3bq")
-Speed = 4.0
+Speed = 0.3
TargetHeight = 10.0
metadata/_custom_type_script = "uid://do0dic4r3ri0s"
diff --git a/player_controller/Scripts/PlayerController.cs b/player_controller/Scripts/PlayerController.cs
index 9b2710e9..91bc2c61 100644
--- a/player_controller/Scripts/PlayerController.cs
+++ b/player_controller/Scripts/PlayerController.cs
@@ -29,6 +29,12 @@ public partial class PlayerController : CharacterBody3D, IDamageable, IKnockback
}
private BufferedActions _bufferedAction = BufferedActions.None;
+ ///////////////////////////
+ // Signals and events //
+ ///////////////////////////
+
+ public event Action DamageTaken;
+
///////////////////////////
// Public stuff //
///////////////////////////
@@ -1729,10 +1735,13 @@ public partial class PlayerController : CharacterBody3D, IDamageable, IKnockback
}
}
- public void TakeDamage(RDamage damage)
+ public float TakeDamage(RDamage damage)
{
+ float damageTaken = 0;
foreach (var damageable in DamageModifiers.ToIDamageables())
- damageable.TakeDamage(damage);
+ damageTaken += damageable.TakeDamage(damage);
+ DamageTaken?.Invoke(damageTaken);
+ return damageTaken;
}
///////////////////////////
@@ -1746,7 +1755,6 @@ public partial class PlayerController : CharacterBody3D, IDamageable, IKnockback
}
if (!WeaponSystem.InHandState.Active) return;
-
var bodies = WeaponHitbox.GetOverlappingBodies();
foreach (var body in bodies)
{
diff --git a/resource_definitions/RDamageModifier.cs b/resource_definitions/RDamageModifier.cs
index 389b59d5..37ef33dd 100644
--- a/resource_definitions/RDamageModifier.cs
+++ b/resource_definitions/RDamageModifier.cs
@@ -6,8 +6,7 @@ using Movementtests.systems.damage;
[GlobalClass]
public partial class RDamageModifier : Resource, IDamageable
{
- [Signal]
- delegate void DamageTakenEventHandler(float damage);
+ public event Action DamageTaken;
[Export]
public EDamageTypes DamageType = EDamageTypes.Normal;
@@ -24,14 +23,13 @@ public partial class RDamageModifier : Resource, IDamageable
Modifier = modifier;
DamageType = damageType;
}
-
- public void TakeDamage(RDamage damage)
+
+ public float TakeDamage(RDamage damage)
{
- if (damage.DamageType != DamageType) return;
+ if (damage.DamageType != DamageType) return 0;
var finalDamage = damage.DamageDealt * Modifier;
- var message = $"Damage of type {DamageType} taken: {finalDamage}";
- GD.Print(message);
- EmitSignalDamageTaken(finalDamage);
+ DamageTaken?.Invoke(finalDamage);
+ return finalDamage;
}
}
diff --git a/resource_definitions/RDeathEffect.cs b/resource_definitions/RDeathEffect.cs
new file mode 100644
index 00000000..bf5ad607
--- /dev/null
+++ b/resource_definitions/RDeathEffect.cs
@@ -0,0 +1,12 @@
+using Godot;
+using System;
+using Movementtests.interfaces;
+
+[GlobalClass]
+public partial class RDeathEffect : Resource, IKillable
+{
+ public void Kill()
+ {
+ GD.Print("Death Effect triggered");
+ }
+}
diff --git a/resource_definitions/RDeathEffect.cs.uid b/resource_definitions/RDeathEffect.cs.uid
new file mode 100644
index 00000000..d1b1fc7b
--- /dev/null
+++ b/resource_definitions/RDeathEffect.cs.uid
@@ -0,0 +1 @@
+uid://b4cwruitopcee
diff --git a/resource_definitions/RHealth.cs b/resource_definitions/RHealth.cs
new file mode 100644
index 00000000..cd78f89d
--- /dev/null
+++ b/resource_definitions/RHealth.cs
@@ -0,0 +1,20 @@
+using Godot;
+using System;
+using Movementtests.interfaces;
+
+[GlobalClass]
+public partial class RHealth : Resource
+{
+ [Export]
+ public float StartingHealth = 100.0f;
+
+ public RHealth()
+ {
+ StartingHealth = 100.0f;
+ }
+
+ public RHealth(float startingHealth)
+ {
+ StartingHealth = startingHealth;
+ }
+}
diff --git a/resource_definitions/RHealth.cs.uid b/resource_definitions/RHealth.cs.uid
new file mode 100644
index 00000000..d10bb059
--- /dev/null
+++ b/resource_definitions/RHealth.cs.uid
@@ -0,0 +1 @@
+uid://baiapod3csndf
diff --git a/scenes/enemies/FirstEnemy.cs b/scenes/enemies/FirstEnemy.cs
index 1364c656..22e20b64 100644
--- a/scenes/enemies/FirstEnemy.cs
+++ b/scenes/enemies/FirstEnemy.cs
@@ -1,10 +1,10 @@
using Godot;
using System;
+using System.Linq;
using Movementtests.interfaces;
-
[GlobalClass]
-public partial class FirstEnemy : CharacterBody3D, IDamageable, IKillable, IKnockbackable, IDamageMaker
+public partial class FirstEnemy : CharacterBody3D, IDamageable, IDamageMaker, IHealthable, IKillable
{
[Export]
public Node3D Target { get; set; }
@@ -16,6 +16,12 @@ public partial class FirstEnemy : CharacterBody3D, IDamageable, IKillable, IKnoc
public RDamage GetDamageDealt { get; set; }
[Export]
public RDamageModifier[] DamageModifiers { get; set; }
+
+ [Export]
+ public CHealth Health { get; set; }
+
+ [Export]
+ public RDeathEffect[] DeathEffects { get; set; }
private RayCast3D _wallInFrontRayCast;
private Area3D _damageBox;
@@ -24,11 +30,22 @@ public partial class FirstEnemy : CharacterBody3D, IDamageable, IKillable, IKnoc
{
_wallInFrontRayCast = GetNode("WallInFrontRayCast");
_damageBox = GetNode("DamageBox");
+
_damageBox.BodyEntered += OnDamageBoxTriggered;
+
+ foreach (var damageable in DamageModifiers)
+ damageable.DamageTaken += ReduceHealth;
+
+ Health.Dead += Kill;
}
-
+
public override void _PhysicsProcess(double delta)
{
+ if (Engine.IsEditorHint())
+ {
+ return;
+ }
+
var target = Target.GlobalPosition;
var direction = (target - GlobalPosition).Normalized();
@@ -53,9 +70,34 @@ public partial class FirstEnemy : CharacterBody3D, IDamageable, IKillable, IKnoc
if(body is IDamageable damageable) damageable.TakeDamage(GetDamageDealt);
}
- public void TakeDamage(RDamage damage)
+ public event Action DamageTaken;
+
+ public float TakeDamage(RDamage damage)
{
+ var finalDamage = 0f;
foreach (var damageable in DamageModifiers.ToIDamageables())
- damageable.TakeDamage(damage);
+ finalDamage += damageable.TakeDamage(damage);
+ DamageTaken?.Invoke(finalDamage);
+ return finalDamage;
+ }
+
+ public float CurrentHealth
+ {
+ get => Health.CurrentHealth;
+ set => Health.CurrentHealth = value;
+ }
+
+ public void ReduceHealth(float amount)
+ {
+ Health.ReduceHealth(amount);
+ }
+
+ public void Kill()
+ {
+ foreach (var killable in DeathEffects.ToIKillables())
+ {
+ killable.Kill();
+ }
+ QueueFree();
}
}
diff --git a/scenes/enemies/FlyingEnemy.cs b/scenes/enemies/FlyingEnemy.cs
index d8a24e91..db205b77 100644
--- a/scenes/enemies/FlyingEnemy.cs
+++ b/scenes/enemies/FlyingEnemy.cs
@@ -3,7 +3,7 @@ using System;
using Movementtests.interfaces;
[GlobalClass]
-public partial class FlyingEnemy : CharacterBody3D, IDamageable, IKillable, IKnockbackable, IDamageMaker
+public partial class FlyingEnemy : CharacterBody3D, IDamageable, IHealthable, IKnockbackable, IDamageMaker
{
[Export]
public Node3D Target { get; set; }
@@ -17,6 +17,11 @@ public partial class FlyingEnemy : CharacterBody3D, IDamageable, IKillable, IKno
[Export]
public RDamageModifier[] DamageModifiers { get; set; }
+ [Export]
+ public CHealth Health { get; set; }
+ [Export]
+ public RDeathEffect[] DeathEffects { get; set; }
+
private RayCast3D _groundDistanceRaycast;
private Area3D _damageBox;
@@ -32,6 +37,10 @@ public partial class FlyingEnemy : CharacterBody3D, IDamageable, IKillable, IKno
_damageBox.BodyEntered += OnDamageBoxTriggered;
_randomDirection = new Vector3(GD.RandRange(-1, 1), 1, GD.RandRange(-1, 1)).Normalized();
+
+ foreach (var damageable in DamageModifiers)
+ damageable.DamageTaken += ReduceHealth;
+ Health.Dead += Kill;
}
public override void _PhysicsProcess(double delta)
@@ -84,9 +93,29 @@ public partial class FlyingEnemy : CharacterBody3D, IDamageable, IKillable, IKno
if(body is IDamageable damageable) damageable.TakeDamage(GetDamageDealt);
}
- public void TakeDamage(RDamage damage)
+ public event Action DamageTaken;
+
+ public float TakeDamage(RDamage damage)
{
+ var finalDamage = 0f;
foreach (var damageable in DamageModifiers.ToIDamageables())
- damageable.TakeDamage(damage);
+ finalDamage += damageable.TakeDamage(damage);
+ DamageTaken?.Invoke(finalDamage);
+ return finalDamage;
+ }
+
+ public void ReduceHealth(float amount)
+ {
+ GD.Print("Reducing health by " + amount);
+ Health.ReduceHealth(amount);
+ }
+
+ public void Kill()
+ {
+ foreach (var killable in DeathEffects.ToIKillables())
+ {
+ killable.Kill();
+ }
+ QueueFree();
}
}
diff --git a/scenes/enemies/first_enemy.tscn b/scenes/enemies/first_enemy.tscn
index 8301c53e..a7f8b58e 100644
--- a/scenes/enemies/first_enemy.tscn
+++ b/scenes/enemies/first_enemy.tscn
@@ -1,12 +1,50 @@
-[gd_scene load_steps=9 format=3 uid="uid://dxt0e2ugmttqq"]
+[gd_scene load_steps=21 format=3 uid="uid://dxt0e2ugmttqq"]
[ext_resource type="Script" uid="uid://bn7sc6id7n166" path="res://scenes/enemies/FirstEnemy.cs" id="1_4yfjf"]
-[ext_resource type="Script" uid="uid://b6y3ugfydvch0" path="res://resource_definitions/RDamageModifier.cs" id="2_ylcc3"]
+[ext_resource type="Script" uid="uid://b2vdwkiqauhk3" path="res://scenes/enemies/EnemyInitInputs.cs" id="2_42xu3"]
+[ext_resource type="Script" uid="uid://bjwrpv3jpsc1e" path="res://scenes/health/CHealth.cs" id="2_gsmti"]
+[ext_resource type="Script" uid="uid://b6y3ugfydvch0" path="res://resource_definitions/RDamageModifier.cs" id="2_r3cnf"]
+[ext_resource type="Script" uid="uid://jitubgv6judn" path="res://resource_definitions/RDamage.cs" id="3_1tw73"]
+[ext_resource type="Script" uid="uid://b4cwruitopcee" path="res://resource_definitions/RDeathEffect.cs" id="3_onjoj"]
+[ext_resource type="Script" uid="uid://baiapod3csndf" path="res://resource_definitions/RHealth.cs" id="3_pvbr4"]
-[sub_resource type="Resource" id="Resource_gsmti"]
-script = ExtResource("2_ylcc3")
+[sub_resource type="Resource" id="Resource_66m7n"]
+script = ExtResource("2_42xu3")
+Speed = 2.0
+metadata/_custom_type_script = "uid://b2vdwkiqauhk3"
+
+[sub_resource type="Resource" id="Resource_a6xb8"]
+script = ExtResource("3_1tw73")
+metadata/_custom_type_script = "uid://jitubgv6judn"
+
+[sub_resource type="Resource" id="Resource_42xu3"]
+script = ExtResource("2_r3cnf")
metadata/_custom_type_script = "uid://b6y3ugfydvch0"
+[sub_resource type="Resource" id="Resource_1tw73"]
+script = ExtResource("2_r3cnf")
+DamageType = 1
+metadata/_custom_type_script = "uid://b6y3ugfydvch0"
+
+[sub_resource type="Resource" id="Resource_qj0ob"]
+script = ExtResource("2_r3cnf")
+DamageType = 2
+metadata/_custom_type_script = "uid://b6y3ugfydvch0"
+
+[sub_resource type="Resource" id="Resource_d7vrc"]
+script = ExtResource("2_r3cnf")
+DamageType = 3
+Modifier = 2.0
+metadata/_custom_type_script = "uid://b6y3ugfydvch0"
+
+[sub_resource type="Resource" id="Resource_7gyf3"]
+script = ExtResource("3_onjoj")
+metadata/_custom_type_script = "uid://b4cwruitopcee"
+
+[sub_resource type="Resource" id="Resource_r3cnf"]
+script = ExtResource("3_pvbr4")
+metadata/_custom_type_script = "uid://baiapod3csndf"
+
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_62kkh"]
[sub_resource type="CapsuleMesh" id="CapsuleMesh_3uydm"]
@@ -23,11 +61,20 @@ albedo_color = Color(0.06469653, 0.06469653, 0.06469653, 1)
[sub_resource type="BoxShape3D" id="BoxShape3D_4yfjf"]
size = Vector3(1, 2, 2)
-[node name="FirstEnemy" type="CharacterBody3D"]
+[node name="FirstEnemy" type="CharacterBody3D" node_paths=PackedStringArray("Health")]
collision_layer = 16
collision_mask = 273
script = ExtResource("1_4yfjf")
-DamageModifiers = Array[Object]([SubResource("Resource_gsmti")])
+Inputs = SubResource("Resource_66m7n")
+GetDamageDealt = SubResource("Resource_a6xb8")
+DamageModifiers = Array[Object]([SubResource("Resource_42xu3"), SubResource("Resource_1tw73"), SubResource("Resource_qj0ob"), SubResource("Resource_d7vrc")])
+Health = NodePath("CHealth")
+DeathEffects = Array[Object]([SubResource("Resource_7gyf3")])
+
+[node name="CHealth" type="Node" parent="."]
+script = ExtResource("2_gsmti")
+HealthResource = SubResource("Resource_r3cnf")
+metadata/_custom_type_script = "uid://bjwrpv3jpsc1e"
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
diff --git a/scenes/enemies/first_enemy_health.tres b/scenes/enemies/first_enemy_health.tres
new file mode 100644
index 00000000..b0a72db9
--- /dev/null
+++ b/scenes/enemies/first_enemy_health.tres
@@ -0,0 +1,7 @@
+[gd_resource type="Resource" script_class="RHealth" load_steps=2 format=3 uid="uid://bohbojc68j7y1"]
+
+[ext_resource type="Script" uid="uid://baiapod3csndf" path="res://resource_definitions/RHealth.cs" id="1_h6jgd"]
+
+[resource]
+script = ExtResource("1_h6jgd")
+metadata/_custom_type_script = "uid://baiapod3csndf"
diff --git a/scenes/enemies/flying_enemy.tscn b/scenes/enemies/flying_enemy.tscn
index 521323f9..d99924b0 100644
--- a/scenes/enemies/flying_enemy.tscn
+++ b/scenes/enemies/flying_enemy.tscn
@@ -1,7 +1,24 @@
-[gd_scene load_steps=10 format=3 uid="uid://cmlud1hwkd6sv"]
+[gd_scene load_steps=21 format=3 uid="uid://cmlud1hwkd6sv"]
[ext_resource type="Script" uid="uid://cmvep0qi7qlvf" path="res://scenes/enemies/FlyingEnemy.cs" id="1_b46rq"]
[ext_resource type="Script" uid="uid://b6y3ugfydvch0" path="res://resource_definitions/RDamageModifier.cs" id="2_1bsgx"]
+[ext_resource type="Script" uid="uid://do0dic4r3ri0s" path="res://scenes/enemies/FlyingEnemyInputs.cs" id="2_aarbi"]
+[ext_resource type="Script" uid="uid://jitubgv6judn" path="res://resource_definitions/RDamage.cs" id="2_irbqc"]
+[ext_resource type="Script" uid="uid://b4cwruitopcee" path="res://resource_definitions/RDeathEffect.cs" id="4_12h4s"]
+[ext_resource type="Script" uid="uid://bjwrpv3jpsc1e" path="res://scenes/health/CHealth.cs" id="4_ys4jv"]
+[ext_resource type="Script" uid="uid://baiapod3csndf" path="res://resource_definitions/RHealth.cs" id="5_irbqc"]
+
+[sub_resource type="Resource" id="Resource_7nxyi"]
+script = ExtResource("2_aarbi")
+Speed = 5.0
+TargetHeight = 10.0
+metadata/_custom_type_script = "uid://do0dic4r3ri0s"
+
+[sub_resource type="Resource" id="Resource_o3msb"]
+script = ExtResource("2_irbqc")
+DamageDealt = 2.0
+DamageType = 2
+metadata/_custom_type_script = "uid://jitubgv6judn"
[sub_resource type="Resource" id="Resource_2pnje"]
script = ExtResource("2_1bsgx")
@@ -13,6 +30,26 @@ DamageType = 1
Modifier = 2.0
metadata/_custom_type_script = "uid://b6y3ugfydvch0"
+[sub_resource type="Resource" id="Resource_irbqc"]
+script = ExtResource("2_1bsgx")
+DamageType = 2
+Modifier = 0.5
+metadata/_custom_type_script = "uid://b6y3ugfydvch0"
+
+[sub_resource type="Resource" id="Resource_uotso"]
+script = ExtResource("2_1bsgx")
+DamageType = 3
+metadata/_custom_type_script = "uid://b6y3ugfydvch0"
+
+[sub_resource type="Resource" id="Resource_ys4jv"]
+script = ExtResource("4_12h4s")
+metadata/_custom_type_script = "uid://b4cwruitopcee"
+
+[sub_resource type="Resource" id="Resource_aarbi"]
+script = ExtResource("5_irbqc")
+StartingHealth = 50.0
+metadata/_custom_type_script = "uid://baiapod3csndf"
+
[sub_resource type="SphereShape3D" id="SphereShape3D_b46rq"]
[sub_resource type="SphereMesh" id="SphereMesh_1bsgx"]
@@ -29,12 +66,21 @@ albedo_color = Color(0.06469653, 0.06469653, 0.06469653, 1)
[sub_resource type="BoxShape3D" id="BoxShape3D_4yfjf"]
size = Vector3(1, 1, 1.5)
-[node name="FlyingEnemy" type="CharacterBody3D"]
+[node name="FlyingEnemy" type="CharacterBody3D" node_paths=PackedStringArray("Health")]
collision_layer = 16
collision_mask = 273
motion_mode = 1
script = ExtResource("1_b46rq")
-DamageModifiers = Array[Object]([SubResource("Resource_2pnje"), SubResource("Resource_1bsgx")])
+Inputs = SubResource("Resource_7nxyi")
+GetDamageDealt = SubResource("Resource_o3msb")
+DamageModifiers = Array[Object]([SubResource("Resource_2pnje"), SubResource("Resource_1bsgx"), SubResource("Resource_irbqc"), SubResource("Resource_uotso")])
+Health = NodePath("CHealth")
+DeathEffects = Array[Object]([SubResource("Resource_ys4jv")])
+
+[node name="CHealth" type="Node" parent="."]
+script = ExtResource("4_ys4jv")
+HealthResource = SubResource("Resource_aarbi")
+metadata/_custom_type_script = "uid://bjwrpv3jpsc1e"
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("SphereShape3D_b46rq")
diff --git a/scenes/enemies/flying_enemy_health.tres b/scenes/enemies/flying_enemy_health.tres
new file mode 100644
index 00000000..8e85b91e
--- /dev/null
+++ b/scenes/enemies/flying_enemy_health.tres
@@ -0,0 +1,8 @@
+[gd_resource type="Resource" script_class="RHealth" load_steps=2 format=3 uid="uid://dg1xbjhyhgnnk"]
+
+[ext_resource type="Script" uid="uid://baiapod3csndf" path="res://resource_definitions/RHealth.cs" id="1_jht15"]
+
+[resource]
+script = ExtResource("1_jht15")
+StartingHealth = 50.0
+metadata/_custom_type_script = "uid://baiapod3csndf"
diff --git a/scenes/health/CHealth.cs b/scenes/health/CHealth.cs
new file mode 100644
index 00000000..85674d69
--- /dev/null
+++ b/scenes/health/CHealth.cs
@@ -0,0 +1,35 @@
+using Godot;
+using System;
+using Movementtests.interfaces;
+
+[GlobalClass]
+public partial class CHealth : Node, IHealthable
+{
+ [Signal]
+ public delegate void HealthChangedEventHandler(float health);
+ [Signal]
+ public delegate void DeadEventHandler();
+
+ [Export]
+ public RHealth HealthResource;
+
+ public float CurrentHealth { get; set; }
+
+ public override void _Ready()
+ {
+ CurrentHealth = HealthResource.StartingHealth;
+ }
+
+ public void ReduceHealth(float amount)
+ {
+ CurrentHealth -= amount;
+ EmitSignalHealthChanged(CurrentHealth);
+
+ if (CurrentHealth <= 0)
+ {
+ CurrentHealth = 0;
+ GD.Print("Dead!");
+ EmitSignalDead();
+ }
+ }
+}
diff --git a/scenes/health/CHealth.cs.uid b/scenes/health/CHealth.cs.uid
new file mode 100644
index 00000000..7eb438a4
--- /dev/null
+++ b/scenes/health/CHealth.cs.uid
@@ -0,0 +1 @@
+uid://bjwrpv3jpsc1e
diff --git a/scenes/health/CHealth.tscn b/scenes/health/CHealth.tscn
new file mode 100644
index 00000000..cb76c432
--- /dev/null
+++ b/scenes/health/CHealth.tscn
@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=3 uid="uid://c4ikbhojckpnc"]
+
+[ext_resource type="Script" uid="uid://bjwrpv3jpsc1e" path="res://scenes/health/CHealth.cs" id="1_75uyt"]
+
+[node name="CHealth" type="Node"]
+script = ExtResource("1_75uyt")