knockback component

This commit is contained in:
2026-01-18 12:39:01 +01:00
parent 9690280cd7
commit 35b9ea383c
21 changed files with 180 additions and 49 deletions

View File

@@ -3,37 +3,53 @@ using Godot;
using Movementtests.interfaces;
[GlobalClass]
public partial class Enemy : CharacterBody3D, IDamageable, IDamageMaker, IHealthable, IKillable, IMoveable, ISpawnable
public partial class Enemy : CharacterBody3D,
IDamageable,
IDamageDealer,
IHealthable,
IKillable,
IMoveable,
ISpawnable,
IKnockbackable
{
public event Action<IDamageable, float> DamageTaken;
// Signals and events
public event Action<IDamageable, DamageRecord> DamageTaken;
public event Action<IHealthable, float> HealthChanged;
public event Action<IHealthable> HealthDepleted;
// Public export components
[Export]
public Node3D Target { get; set; }
[ExportGroup("Health")]
[Export]
public Node CHealth { get; set; }
[Export]
public RHealth RHealth { get; set; }
public float CurrentHealth { get; set; }
[Export]
public RDeathEffect[] DeathEffects { get; set; }
[ExportGroup("Damage")]
[Export]
public Node CDamage { get; set; }
[Export]
public RDamage RDamage { get; set; }
[Export]
public Node CKnockback { get; set; }
[Export]
public RKnockback RKnockback { get; set; }
[ExportGroup("Movement")]
[Export]
public Node CMovement { get; set; }
[Export]
public RMovement RMovement { get; set; }
[Export]
public RDeathEffect[] DeathEffects { get; set; }
// Public stuff
public float CurrentHealth { get; set; }
// Private stuff
private Area3D _damageBox;
public override void _Ready()
@@ -52,12 +68,17 @@ public partial class Enemy : CharacterBody3D, IDamageable, IDamageMaker, IHealth
healthable.RHealth = RHealth;
healthable.CurrentHealth = RHealth.StartingHealth;
}
if (CKnockback is IKnockbackable knockbackable && RKnockback != null) knockbackable.RKnockback = RKnockback;
}
public void SetupSignals()
{
_damageBox.BodyEntered += OnDamageBoxTriggered;
if (CDamage is IDamageable damageable) damageable.DamageTaken += ReduceHealth;
if (CDamage is IDamageable damageable)
{
damageable.DamageTaken += ReduceHealth;
damageable.DamageTaken += RegisterKnockback;
}
if (CHealth is IHealthable healthable) healthable.HealthDepleted += Kill;
}
@@ -74,6 +95,7 @@ public partial class Enemy : CharacterBody3D, IDamageable, IDamageMaker, IHealth
delta: delta
);
Velocity = ComputeVelocity(inputs);
Velocity += ComputeKnockback();
MoveAndSlide();
}
@@ -85,25 +107,28 @@ public partial class Enemy : CharacterBody3D, IDamageable, IDamageMaker, IHealth
public void OnDamageBoxTriggered(Node3D body)
{
GD.Print("Take this!");
if (body is not IDamageable damageable) return;
damageable.TakeDamage(RDamage);
var damageRecord = new DamageRecord(this, RDamage);
damageable.TakeDamage(damageRecord);
}
public float TakeDamage(RDamage damage)
public DamageRecord TakeDamage(DamageRecord damageRecord)
{
GD.Print("Ouch!");
if (CDamage is not IDamageable damageable) return 0;
if (CDamage is not IDamageable damageable)
return damageRecord with { Damage = new RDamage(0, damageRecord.Damage.DamageType) };
var finalDamage = damageable.TakeDamage(damage);
DamageTaken?.Invoke(this, damage.DamageDealt);
var finalDamage = damageable.TakeDamage(damageRecord);
DamageTaken?.Invoke(this, finalDamage);
GD.Print($"Received damage: {finalDamage.Damage.DamageDealt}");
return finalDamage;
}
public void ReduceHealth(IDamageable source, float amount)
public void ReduceHealth(IDamageable source, DamageRecord damageRecord)
{
if (CHealth is not IHealthable healthable) return;
healthable.ReduceHealth(source, amount);
healthable.ReduceHealth(source, damageRecord);
}
public void Kill(IHealthable source)
@@ -114,4 +139,16 @@ public partial class Enemy : CharacterBody3D, IDamageable, IDamageMaker, IHealth
}
QueueFree();
}
public void RegisterKnockback(IDamageable source, DamageRecord damageRecord)
{
if (CKnockback is not IKnockbackable knockbackable) return;
knockbackable.RegisterKnockback(source, damageRecord);
}
public Vector3 ComputeKnockback()
{
if (CKnockback is not IKnockbackable knockbackable) return Vector3.Zero;
return knockbackable.ComputeKnockback();
}
}