using UnityEngine; namespace Arena.Combat { /// /// Moves straight ahead and damages the first IDamageable of the targeted team it touches. /// It goes through the other teams: no friendly fire. /// Needs a trigger collider and a kinematic Rigidbody. /// [RequireComponent(typeof(Rigidbody))] public class Projectile : MonoBehaviour { [System.Serializable] public class Settings { [Tooltip("Speed, in meters per second.")] [Min(0f)] public float Speed = 20f; [Tooltip("Time before an unused projectile is destroyed, in seconds.")] [Min(0.1f)] public float Lifetime = 2f; } #region FIELDS [SerializeField] private Settings _settings; private DamageInfo _damage; #endregion #region UNITY LIFECYCLES private void Update() { transform.position += transform.forward * _settings.Speed * Time.deltaTime; } private void OnTriggerEnter(Collider other) { // Ignore the other trigger zones, and the shooter with all its children if (other.isTrigger || IsFromShooter(other)) return; // The collider can be on a child of the IDamageable: arm, head, model... IDamageable target = other.GetComponentInParent(); if (target != null) { // A friend is crossed, not hit if (!_damage.CanHit(target.Team)) return; target.TakeDamage(_damage); } Destroy(gameObject); } #endregion #region PUBLIC METHODS /// /// Starts the projectile. Called right after Instantiate by whoever fires it. /// /// Damage dealt to the IDamageable it touches. Its source is the shooter, ignored by the projectile. public void Launch(DamageInfo damage) { _damage = damage; Destroy(gameObject, _settings.Lifetime); } #endregion #region PRIVATE METHODS private bool IsFromShooter(Collider other) { GameObject shooter = _damage.Source; return shooter && other.transform.IsChildOf(shooter.transform); } #endregion } }