using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; using Random = UnityEngine.Random; [RequireComponent(typeof(MinecraftUnit))] public class AttackHandler : MonoBehaviour { [SerializeField] protected float damage; [SerializeField] protected float cooldown; [SerializeField] protected Collider attackShape; [SerializeField] protected float knockbackHorizontalForce; [SerializeField] protected float knockbackVerticalForce; protected MinecraftUnit _minecraftUnit; void Awake() { _minecraftUnit = GetComponent(); } void Start() { InvokeRepeating(nameof(Attack), Random.Range(-cooldown*0.2f, cooldown*0.2f), cooldown); } /// /// Launch an Attack, and return true if it's possible to attack /// see what Units are in the attackShape, apply damage and knockback to those unit if they're ennemies /// public virtual bool Attack() { Collider[] targets = DetectTargets(); bool hasHit = false; foreach (Collider target in targets) { if (!target.CompareTag("Unit")) continue; // GetComponent is expensive in performance, optimize here if it's slow AbstractUnit targetUnit = target.GetComponent(); // No friendly fire if (targetUnit.IsTeamA == _minecraftUnit.IsTeamA) continue; targetUnit.TakeDamage(damage); hasHit = true; Vector3 knockbackVector = knockbackHorizontalForce * (target.transform.position - transform.position).normalized + knockbackVerticalForce * Vector3.up; // Knockback logic specific to MinecraftUnit (can't force other team to do our weird impl) if (targetUnit is MinecraftUnit) { MinecraftUnit minecraftTarget = (MinecraftUnit)targetUnit; minecraftTarget.StartCoroutine(minecraftTarget.MovementHandler.TakeImpulse(knockbackVector)); } } // Attack animation if (_minecraftUnit.Animator && hasHit) { _minecraftUnit.Animator.SetTrigger("Attack"); } return hasHit; } private Collider[] DetectTargets() { Collider[] hitColliders; switch (attackShape) { case SphereCollider sphere: hitColliders = Physics.OverlapSphere(transform.position, sphere.radius, sphere.includeLayers); break; case BoxCollider box: hitColliders = Physics.OverlapBox(box.bounds.center, box.bounds.extents, box.transform.rotation, box.includeLayers); break; default: throw new ArgumentException("Only sphere or box are supported"); } return hitColliders; } }