Add attribute system with core stats and gameplay components

This commit is contained in:
2025-10-13 12:10:45 +02:00
commit ce3596efaa
55 changed files with 1161 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
namespace GameCore.Attributes;
/// <summary>
/// Defines all possible stats an entity can have.
/// </summary>
public enum Attribute
{
// Core Stats
Health,
MaxHealth,
Armor,
MoveSpeed,
Acceleration,
Friction,
JumpHeight,
// Combat Stats
Damage,
AttackSpeed,
AttackRange,
MeleeDamage, // Multiplier
RangedDamage, // Multiplier
// Progression
Level,
Experience,
ExperienceToNextLevel,
// Misc
Luck
}

View File

@@ -0,0 +1,42 @@
using GameCore.ECS.Interfaces;
namespace GameCore.Attributes;
/// <summary>
/// A component that stores all gameplay-relevant stats for an entity.
/// This design is adapted directly from the excellent CharacterAttributes class
/// in the 'broberry' project. It's a flexible, data-driven way to manage stats.
/// </summary>
public class AttributeComponent : IComponent
{
public readonly Dictionary<Attribute, float> BaseValues = new();
public readonly Dictionary<Attribute, float> CurrentValues = new();
public event Action<Attribute, float>? OnAttributeChanged;
public void SetBaseValue(Attribute attr, float value)
{
BaseValues[attr] = value;
SetCurrentValue(attr, value);
}
public float GetValue(Attribute attr)
{
return CurrentValues.GetValueOrDefault(attr, 0f);
}
public void ModifyValue(Attribute attr, float delta)
{
var newValue = GetValue(attr) + delta;
SetCurrentValue(attr, newValue);
}
public void SetCurrentValue(Attribute attr, float value, bool force = false)
{
if (CurrentValues.TryGetValue(attr, out var oldValue) && !(System.Math.Abs(oldValue - value) > 0.001f) &&
!force) return;
CurrentValues[attr] = value;
OnAttributeChanged?.Invoke(attr, value);
}
}

View File

@@ -0,0 +1,23 @@
using GameCore.ECS;
using GameCore.ECS.Interfaces;
namespace GameCore.Attributes;
public class AttributeSystem : ISystem
{
public void Update(World world, float deltaTime)
{
var entities = world.GetEntitiesWith<AttributeComponent>();
foreach (var entity in entities)
{
var attributes = world.GetComponent<AttributeComponent>(entity);
if (attributes == null) continue;
var maxHealth = attributes.GetValue(Attribute.MaxHealth);
var currentHealth = attributes.GetValue(Attribute.Health);
if (currentHealth > maxHealth) attributes.SetCurrentValue(Attribute.Health, maxHealth);
}
}
}