feat: Enemies

This commit is contained in:
2026-11-05 08:59:08 +01:00
parent cd65f702ae
commit 743703c6bd
109 changed files with 75286 additions and 15238 deletions

View File

@@ -4,8 +4,10 @@ using UnityEngine;
namespace Arena.Combat
{
/// <summary>
/// Fires projectiles from a muzzle, limited by the fire interval and the ammo count.
/// Placed on the root of the shooter, which the projectiles ignore.
/// Weapon that fires projectiles from a muzzle, limited by the fire interval and the ammo count.
/// Held by a Handle (usually a hand): snaps to it when enabled, then follows the orientation of the Owner
/// while the Owner is active, otherwise the orientation of the Handle. Can be dropped with physics.
/// The projectiles ignore the shooter and all its children.
/// </summary>
public class ProjectileLauncher : MonoBehaviour
{
@@ -14,6 +16,9 @@ namespace Arena.Combat
{
[Tooltip("Weapon data: damage, fire interval, ammo, projectile.")]
public WeaponData Weapon;
[Tooltip("Team hurt by the projectiles: Enemy for the player, Allied for an enemy, All for everyone.")]
public Team Target = Team.All;
}
[System.Serializable]
@@ -21,12 +26,26 @@ namespace Arena.Combat
{
[Tooltip("Spawn point of the projectiles. Its forward axis gives the direction.")]
public Transform Muzzle;
[Tooltip("Shooter: the projectiles never hit it nor its children, and the weapon follows its orientation while it is active. Empty: the GameObject of this launcher.")]
public GameObject Owner;
[Tooltip("Transform that holds the weapon, usually a hand. The weapon takes its position and orientation when enabled.")]
public Transform Handle;
[Tooltip("Rigidbody of the weapon, kinematic while held. Drop makes it fall.")]
public Rigidbody Body;
}
[System.Serializable]
public class StateContainer
{
public int Ammo;
[Tooltip("True while an action blocks the shots: running, dash, stun... Set by the owner.")]
public bool Disabled;
public bool IsDropped;
}
#region FIELDS
@@ -41,6 +60,7 @@ namespace Arena.Combat
public event Action<int, int> OnAmmoChange;
public StateContainer State => _state;
public Transform Muzzle => _references.Muzzle;
public int MaxAmmo => _settings.Weapon.MaxAmmo;
private float _nextFireTime;
@@ -54,6 +74,28 @@ namespace Arena.Combat
_state.Ammo = MaxAmmo;
}
void OnEnable()
{
Transform handle = _references.Handle;
if (handle && !_state.IsDropped)
transform.SetPositionAndRotation(handle.position, handle.rotation);
}
void LateUpdate()
{
// LateUpdate: after the animation has moved the hand
if (_state.IsDropped)
return;
GameObject owner = _references.Owner;
if (owner && owner.activeInHierarchy)
transform.rotation = owner.transform.rotation;
else if (_references.Handle)
transform.rotation = _references.Handle.rotation;
}
#endregion
#region PUBLIC METHODS
@@ -63,7 +105,7 @@ namespace Arena.Combat
/// </summary>
public bool TryFire()
{
if (Time.time < _nextFireTime || _state.Ammo <= 0)
if (_state.Disabled || _state.IsDropped || Time.time < _nextFireTime || _state.Ammo <= 0)
return false;
_nextFireTime = Time.time + _settings.Weapon.FireInterval;
@@ -72,10 +114,43 @@ namespace Arena.Combat
Transform muzzle = _references.Muzzle;
Projectile projectile = Instantiate(_settings.Weapon.ProjectilePrefab, muzzle.position, muzzle.rotation);
projectile.Launch(new DamageInfo(_settings.Weapon.Damage, _settings.Weapon.DamageType, gameObject));
GameObject owner = _references.Owner ? _references.Owner : gameObject;
projectile.Launch(new DamageInfo(_settings.Weapon.Damage, _settings.Weapon.DamageType, owner, _settings.Target));
return true;
}
/// <summary>
/// Blocks or allows the shots. Called by the owner when an action prevents shooting.
/// </summary>
public void SetDisabled(bool isDisabled)
{
_state.Disabled = isDisabled;
}
/// <summary>
/// Lets go of the weapon: it leaves its handle and falls with physics. It can no longer fire.
/// </summary>
public void Drop()
{
if (_state.IsDropped)
return;
_state.IsDropped = true;
_state.Disabled = true;
transform.SetParent(null, true);
Rigidbody body = _references.Body;
if (!body)
{
Debug.LogWarning($"{name}: no Rigidbody referenced, the weapon cannot fall.", this);
return;
}
body.isKinematic = false;
body.useGravity = true;
}
/// <summary>
/// Adds ammo without exceeding the weapon maximum.
/// </summary>