broken composition and signals

This commit is contained in:
2026-01-17 17:02:31 +01:00
parent 0436053c62
commit 4ccdbc0ee6
22 changed files with 302 additions and 36 deletions

View File

@@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAction_00601_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7c0f83388bfc4d2c9d09befcec9dd79bc90908_003Fb8_003F4d300c4d_003FAction_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fdf73a4db74df89d59655c5fb6326406f47fbfa9af1fa81518fe0a07c49d34133_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASceneTree_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F8d6960554e939a669841b1ece03d27df4ab42f92bb80be3767eaec8cdaccf84b_003FSceneTree_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=floorplane/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,8 +1,9 @@
using Godot;
using System;
namespace Movementtests.interfaces;
public interface IDamageable
{
void TakeDamage(RDamage damage);
event Action<float> DamageTaken;
float TakeDamage(RDamage damage);
}

View File

@@ -1,7 +1,6 @@
namespace Movementtests.interfaces;
public interface IKillable
public interface IHealthable
{
float CurrentHealth { get; set; }
void ReduceHealth(float amount);
}

View File

@@ -1,7 +1,6 @@
namespace Movementtests.interfaces;
public interface IHealthable
public interface IKillable
{
float CurrentHealth { get; set; }
void ReduceHealth(float amount);
void Kill();
}

View File

@@ -0,0 +1 @@
uid://dqpjr2d01sk1a

View File

@@ -9,4 +9,8 @@ public static class NodeExtensions
{
return nodes == null ? System.Array.Empty<IDamageable>() : nodes.OfType<IDamageable>().ToArray();
}
public static IKillable[] ToIKillables(this GodotObject[] nodes)
{
return nodes == null ? System.Array.Empty<IKillable>() : nodes.OfType<IKillable>().ToArray();
}
}

View File

@@ -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"

View File

@@ -29,6 +29,12 @@ public partial class PlayerController : CharacterBody3D, IDamageable, IKnockback
}
private BufferedActions _bufferedAction = BufferedActions.None;
///////////////////////////
// Signals and events //
///////////////////////////
public event Action<float> 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)
{

View File

@@ -6,8 +6,7 @@ using Movementtests.systems.damage;
[GlobalClass]
public partial class RDamageModifier : Resource, IDamageable
{
[Signal]
delegate void DamageTakenEventHandler(float damage);
public event Action<float> DamageTaken;
[Export]
public EDamageTypes DamageType = EDamageTypes.Normal;
@@ -25,13 +24,12 @@ public partial class RDamageModifier : Resource, IDamageable
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;
}
}

View File

@@ -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");
}
}

View File

@@ -0,0 +1 @@
uid://b4cwruitopcee

View File

@@ -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;
}
}

View File

@@ -0,0 +1 @@
uid://baiapod3csndf

View File

@@ -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; }
@@ -17,6 +17,12 @@ public partial class FirstEnemy : CharacterBody3D, IDamageable, IKillable, IKnoc
[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<RayCast3D>("WallInFrontRayCast");
_damageBox = GetNode<Area3D>("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<float> 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();
}
}

View File

@@ -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<float> 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();
}
}

View File

@@ -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)

View File

@@ -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"

View File

@@ -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")

View File

@@ -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"

35
scenes/health/CHealth.cs Normal file
View File

@@ -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();
}
}
}

View File

@@ -0,0 +1 @@
uid://bjwrpv3jpsc1e

View File

@@ -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")