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

@@ -1,6 +1,7 @@
using Chickensoft.Collections;
using Godot;
using Zennysoft.Game.Abstractions;
using Zennysoft.Game.Implementation.Components;
namespace Zennysoft.Ma.Adapter;
@@ -18,38 +19,16 @@ public interface IPlayer : IKillable
public void Knockback(float impulse);
public void GainExp(double expGained);
public void LevelUp();
public void Move(float delta);
public void TeleportPlayer(Transform3D newTransform);
public void HealHP(int amount);
public void RaiseHP(int amount);
public void HealVT(int amount);
public void RaiseVT(int amount);
public void ModifyBonusAttack(int amount);
public void ModifyBonusDefense(int amount);
public void ModifyMaximumHP(int amount);
public void ModifyMaximumVT(int amount);
public void ModifyBonusLuck(double amount);
public void SetHealthTimerStatus(bool isActive);
public IInventory Inventory { get; }
public PlayerStats Stats { get; }
public Vector3 CurrentPosition { get; }
public Basis CurrentBasis { get; }
@@ -63,4 +42,16 @@ public interface IPlayer : IKillable
public void Equip(EquipableItem equipable);
public void Unequip(EquipableItem equipable);
public HealthComponent HealthComponent { get; }
public VTComponent VTComponent { get; }
public AttackComponent AttackComponent { get; }
public DefenseComponent DefenseComponent { get; }
public ExperiencePointsComponent ExperiencePointsComponent { get; }
public LuckComponent LuckComponent { get; }
}

View File

@@ -7,9 +7,6 @@ namespace Zennysoft.Game.Ma;
[Meta, Id("player_data")]
public partial record PlayerData
{
[Save("player_stats")]
public required PlayerStats PlayerStats { get; init; }
[Save("player_inventory")]
public required IInventory Inventory { get; init; }
}

View File

@@ -1,115 +0,0 @@
namespace Zennysoft.Ma.Adapter;
using Chickensoft.Collections;
using Godot;
public class PlayerStats
{
public PlayerStats(AutoProp<int> currentHP,
AutoProp<int> maximumHP,
AutoProp<int> currentVT,
AutoProp<int> maximumVT,
AutoProp<int> currentAttack,
AutoProp<int> maxAttack,
AutoProp<int> bonusAttack,
AutoProp<int> currentDefense,
AutoProp<int> maxDefense,
AutoProp<int> bonusDefense,
AutoProp<double> currentExp,
AutoProp<int> expToNextLevel,
AutoProp<int> currentLevel,
AutoProp<double> luck)
{
CurrentHP = currentHP;
MaximumHP = maximumHP;
CurrentVT = currentVT;
MaximumVT = maximumVT;
CurrentAttack = currentAttack;
MaxAttack = maxAttack;
BonusAttack = bonusAttack;
CurrentDefense = currentDefense;
MaxDefense = maxDefense;
BonusDefense = bonusDefense;
CurrentExp = currentExp;
ExpToNextLevel = expToNextLevel;
CurrentLevel = currentLevel;
Luck = luck;
}
public AutoProp<int> CurrentHP { get; init; }
public AutoProp<int> MaximumHP { get; init; }
public AutoProp<int> CurrentVT { get; init; }
public AutoProp<int> MaximumVT { get; init; }
public AutoProp<int> CurrentAttack { get; init; }
public AutoProp<int> MaxAttack { get; init; }
public AutoProp<int> BonusAttack { get; init; }
public AutoProp<int> CurrentDefense { get; init; }
public AutoProp<int> MaxDefense { get; init; }
public AutoProp<int> BonusDefense { get; init; }
public AutoProp<double> CurrentExp { get; init; }
public AutoProp<int> ExpToNextLevel { get; init; }
public AutoProp<int> CurrentLevel { get; init; }
public AutoProp<double> Luck { get; init; }
public void SetCurrentHP(int newValue)
{
var clampedValue = Mathf.Clamp(newValue, 0, MaximumHP.Value);
CurrentHP.OnNext(clampedValue);
}
public void SetMaximumHP(int newValue)
{
MaximumHP.OnNext(newValue);
}
public void SetCurrentVT(int newValue)
{
var clampedValue = Mathf.Clamp(newValue, 0, MaximumVT.Value);
CurrentVT.OnNext(clampedValue);
}
public void SetMaximumVT(int newValue)
{
MaximumVT.OnNext(newValue);
}
public void SetCurrentExp(double newValue)
{
CurrentExp.OnNext(newValue);
}
public void SetCurrentLevel(int newValue)
{
CurrentLevel.OnNext(newValue);
}
public void SetCurrentAttack(int newValue)
{
var clampedValue = Mathf.Clamp(newValue, 0, MaxAttack.Value);
CurrentAttack.OnNext(clampedValue);
}
public void SetBonusAttack(int newValue)
{
BonusAttack.OnNext(newValue);
}
public void SetMaxAttack(int newValue)
{
MaxAttack.OnNext(newValue);
}
public void SetCurrentDefense(int newValue)
{
var clampedValue = Mathf.Clamp(newValue, 0, MaxDefense.Value);
CurrentDefense.OnNext(clampedValue);
}
public void SetBonusDefense(int newValue)
{
BonusDefense.OnNext(newValue);
}
public void SetMaxDefense(int newValue)
{
MaxDefense.OnNext(newValue);
}
public void SetExpToNextLevel(int newValue)
{
ExpToNextLevel.OnNext(newValue);
}
public void SetLuck(double newValue)
{
var clampedValue = Mathf.Clamp(newValue, 0, 1.0);
Luck.OnNext(clampedValue);
}
}

View File

@@ -14,8 +14,6 @@ public partial class PlayerLogic
public readonly record struct Attack;
public readonly record struct AttackAnimationFinished;
public readonly record struct Die;
}
}

View File

@@ -9,5 +9,5 @@ public interface IPlayerLogic : ILogicBlock<PlayerLogic.State>;
[LogicBlock(typeof(State), Diagram = true)]
public partial class PlayerLogic : LogicBlock<PlayerLogic.State>, IPlayerLogic
{
public override Transition GetInitialState() => To<State.Idle>();
public override Transition GetInitialState() => To<State.Alive>();
}

View File

@@ -1,18 +0,0 @@
using Chickensoft.Introspection;
namespace Zennysoft.Ma.Adapter;
public partial class PlayerLogic
{
public partial record State
{
[Meta]
public partial record Attacking : Alive, IGet<Input.AttackAnimationFinished>
{
public Transition On(in Input.AttackAnimationFinished input)
{
return To<Idle>();
}
}
}
}

View File

@@ -1,22 +0,0 @@
using Chickensoft.Introspection;
using Godot;
namespace Zennysoft.Ma.Adapter;
public partial class PlayerLogic
{
public abstract partial record State
{
[Meta, Id("player_logic_state_alive_idle")]
public partial record Idle : Alive, IGet<Input.Attack>
{
public virtual Transition On(in Input.Attack input)
{
GD.Print("Attacking...");
Output(new Output.Animations.Attack());
return To<Attacking>();
}
}
}
}

View File

@@ -8,7 +8,7 @@ public partial class PlayerLogic
public partial record State
{
[Meta, Id("player_logic_alive")]
public abstract partial record Alive : State, IGet<Input.PhysicsTick>, IGet<Input.Die>
public partial record Alive : State, IGet<Input.PhysicsTick>, IGet<Input.Die>
{
public virtual Transition On(in Input.PhysicsTick input)
{

View File

@@ -16,7 +16,7 @@ public partial class PlayerLogic
OnDetach(() => Get<IAppRepo>().GameEntered -= OnGameEntered);
}
public Transition On(in Input.Enable input) => To<Idle>();
public Transition On(in Input.Enable input) => To<Alive>();
public void OnGameEntered() => Input(new Input.Enable());
}