Characters

This commit is contained in:
2025-10-05 18:21:16 +02:00
parent b52b3aa830
commit 174a399ee7
77 changed files with 14406 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
using UnityEngine;
namespace MegaKoop.Game.Combat
{
/// <summary>
/// Bundles damage information so different systems can respond consistently.
/// </summary>
public struct DamagePayload
{
public float Amount;
public Vector3 HitPoint;
public Vector3 HitNormal;
public GameObject Source;
public Team SourceTeam;
public GameObject Target;
public DamagePayload(float amount, Vector3 hitPoint, Vector3 hitNormal, GameObject source, Team sourceTeam, GameObject target)
{
Amount = amount;
HitPoint = hitPoint;
HitNormal = hitNormal;
Source = source;
SourceTeam = sourceTeam;
Target = target;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7e3b00f0d0eff2b0e813e41895012e02

View File

@@ -0,0 +1,97 @@
using System;
using UnityEngine;
using UnityEngine.Events;
namespace MegaKoop.Game.Combat
{
[DisallowMultipleComponent]
public class Health : MonoBehaviour, IDamageable
{
[SerializeField] private float maxHealth = 100f;
[SerializeField] private Team team = Team.Neutral;
[SerializeField] private bool ignoreFriendlyFire = true;
[SerializeField] private bool destroyOnDeath = false;
[SerializeField] private UnityEvent<float> onHealthChanged;
[SerializeField] private UnityEvent onDeath;
public float MaxHealth => maxHealth;
public float CurrentHealth { get; private set; }
public Team Team => team;
public bool IsAlive => CurrentHealth > 0f;
public event Action<float> NormalizedHealthChanged;
private void Awake()
{
maxHealth = Mathf.Max(1f, maxHealth);
CurrentHealth = maxHealth;
onHealthChanged?.Invoke(CurrentHealth / MaxHealth);
NormalizedHealthChanged?.Invoke(CurrentHealth / MaxHealth);
}
public void ApplyDamage(DamagePayload payload)
{
if (!IsAlive || payload.Amount <= 0f)
{
return;
}
if (ignoreFriendlyFire && team != Team.Neutral && payload.SourceTeam == team)
{
return;
}
CurrentHealth = Mathf.Max(0f, CurrentHealth - payload.Amount);
float normalized = CurrentHealth / MaxHealth;
onHealthChanged?.Invoke(normalized);
NormalizedHealthChanged?.Invoke(normalized);
if (CurrentHealth <= 0f)
{
HandleDeath();
}
}
public void Heal(float amount)
{
if (amount <= 0f || !IsAlive)
{
return;
}
CurrentHealth = Mathf.Min(MaxHealth, CurrentHealth + amount);
float normalized = CurrentHealth / MaxHealth;
onHealthChanged?.Invoke(normalized);
NormalizedHealthChanged?.Invoke(normalized);
}
private void HandleDeath()
{
onDeath?.Invoke();
if (destroyOnDeath)
{
Destroy(gameObject);
}
}
private void OnValidate()
{
maxHealth = Mathf.Max(1f, maxHealth);
}
public void ForceSetNormalizedHealth(float normalized)
{
normalized = Mathf.Clamp01(normalized);
bool wasAlive = IsAlive;
CurrentHealth = normalized * MaxHealth;
onHealthChanged?.Invoke(normalized);
NormalizedHealthChanged?.Invoke(normalized);
if (CurrentHealth <= 0f && wasAlive)
{
HandleDeath();
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 920077a2cfc4cde58a4ceeea4b96ebe9

View File

@@ -0,0 +1,9 @@
namespace MegaKoop.Game.Combat
{
public interface IDamageable
{
Team Team { get; }
bool IsAlive { get; }
void ApplyDamage(DamagePayload payload);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2044a5c09d25d50beb90c486ace32d50

View File

@@ -0,0 +1,9 @@
namespace MegaKoop.Game.Combat
{
public enum Team
{
Neutral = 0,
Heroes = 1,
Enemies = 2
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 620167bdb0a57e180b2bee989e9ee5d1