Refactor Player class to use components, also use components in Enemy class types and fiddle with boss structure

This commit is contained in:
2025-10-22 02:41:08 -07:00
parent 44fd8c82b0
commit 6ec45c4805
85 changed files with 941 additions and 1449 deletions

View File

@@ -3,6 +3,7 @@ using Chickensoft.Introspection;
using Godot;
using System.Collections.Immutable;
using System.Linq;
using Zennysoft.Game.Implementation.Components;
using Zennysoft.Ma.Adapter;
using Zennysoft.Ma.Adapter.Entity;
@@ -25,17 +26,35 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
[Dependency] protected IPlayer _player => this.DependOn(() => GetParent().GetChildren().OfType<IPlayer>().Single());
#endregion
#region Node Dependencies
[Node] private Area3D LineOfSight { get; set; } = default!;
[Node] private RayCast3D Raycast { get; set; } = default!;
public HealthComponent HealthComponent { get; private set; }
[Node] private HealthComponent _healthComponent { get; set; } = default!;
#endregion
public AttackComponent AttackComponent { get; private set; }
public DefenseComponent DefenseComponent { get; private set; }
public virtual IEnemyModelView EnemyModelView { get; set; } = default!;
public Vector3 TargetPosition { get; private set; }
[ExportGroup("Enemy Stats")]
[Export] public int InitialHP { get; set; } = 50;
[Export] public int InitialAttack { get; set; } = 8;
[Export] public int InitialDefense { get; set; } = 8;
[Export] public int ExpGiven { get; set; } = 10;
public Enemy()
{
HealthComponent = new HealthComponent(InitialHP);
HealthComponent.HealthReachedZero += Die;
HealthComponent.DamageTaken += TakeHit;
AttackComponent = new AttackComponent(InitialAttack);
DefenseComponent = new DefenseComponent(InitialDefense);
}
#region Godot methods
public void Setup()
{
@@ -43,8 +62,6 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
_enemyLogic.Set(this as IEnemy);
_enemyLogic.Set(_player);
SetPhysicsProcess(true);
_healthComponent.HealthReachedZero += Die;
_healthComponent.HealthLowered += TakeHit;
EnemyModelView.HitPlayer += EnemyModelView_HitPlayer;
}
@@ -73,7 +90,6 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
this.Provide();
_enemyLogic.Start();
LineOfSight.BodyEntered += LineOfSight_BodyEntered;
}
#endregion
@@ -124,12 +140,12 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
public virtual void TakeDamage(int damage)
{
GD.Print($"Enemy Hit for {damage} damage.");
_healthComponent.CurrentHP.OnNext(_healthComponent.CurrentHP.Value - damage);
HealthComponent.Damage(damage);
}
private void EnemyModelView_HitPlayer()
private void EnemyModelView_HitPlayer(object sender, System.EventArgs e)
{
_player.TakeDamage(new Damage(30, ElementType.None, false, false, false));
_player.TakeDamage(new Damage(AttackComponent.TotalAttack, ElementType.None, false, false, false));
}
public virtual void TakeHit()
@@ -141,8 +157,8 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
public virtual void Die()
{
SetPhysicsProcess(false);
_healthComponent.CurrentHP.OnCompleted();
_enemyLogic.Input(new EnemyLogic.Input.Defeated());
_player.ExperiencePointsComponent.Gain(ExpGiven);
EnemyModelView.PlayDeathAnimation();
var tweener = CreateTween();
tweener.TweenInterval(1.0f);
@@ -160,23 +176,6 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
return null;
}
private void LineOfSight_BodyEntered(Node3D body)
{
var overlappingBodies = LineOfSight.GetOverlappingBodies();
foreach (var _ in overlappingBodies)
{
if (Raycast.GlobalPosition != _player.CurrentPosition)
Raycast.LookAt(_player.CurrentPosition, Vector3.Up);
Raycast.ForceRaycastUpdate();
if (Raycast.IsColliding())
{
var collider = Raycast.GetCollider();
if (collider is IPlayer)
_enemyLogic.Input(new EnemyLogic.Input.Follow());
}
}
}
public void OnExitTree()
{
_enemyLogic.Stop();