using System.Collections; using Movement; using Pausable; using UnityEngine; using UnityEngine.Events; namespace AI { public class ShootingEnemyAI : MonoBehaviour, IPausable { [SerializeField] protected float focusingTime = .5f; [SerializeField] protected float attacksPerSecond = 1f; [SerializeField] protected float attackRange = 5f; [SerializeField] protected float timeForProjectileToHit = .25f; protected float cooldownPerShoot = 0f; protected float remainingCooldown = 0f; protected float attackRangeSquared = 5f; protected Transform target = null; protected bool isShooting = false; protected IMovement movement = null; protected Animator animator = null; protected AudioSource audioSource = null; protected int layerMask = ~(1 << 9); protected bool canShoot => target != null && (target.transform.position - transform.position).sqrMagnitude < attackRangeSquared; public UnityEvent OnShoot { get; protected set; } = null; #region IPausable public bool IsPaused { get; protected set; } = false; public virtual void Pause() => IsPaused = true; public virtual void Resume() => IsPaused = false; #endregion protected virtual void Awake() { cooldownPerShoot = 1f / attacksPerSecond; attackRangeSquared = attackRange * attackRange; OnShoot = new UnityEvent(); } protected virtual void Start() { movement = transform.GetComponentInParent(); animator = transform.GetComponentInParent(); audioSource = transform.GetComponentInParent(); UpdateTarget(FindObjectOfType()?.transform); } protected virtual void Update() { remainingCooldown -= Time.deltaTime; if (canShoot && !isShooting) StartCoroutine(ShootCoroutine()); } protected IEnumerator ShootCoroutine() { isShooting = true; float movementBaseSpeed = movement.BaseSpeed; movement.BaseSpeed = 0f; animator.SetBool("isAttacking", true); yield return new WaitForSeconds(focusingTime); while (canShoot) { if (remainingCooldown <= 0f) Shoot(); yield return null; } movement.BaseSpeed = movementBaseSpeed; animator.SetBool("isAttacking", false); remainingCooldown = 0f; isShooting = false; } protected virtual void Shoot() { Projectile projectile = ProjectilePool.Instance.Get(); projectile.transform.position = transform.position; Vector3 velocity = GetVelocityForProjectile(timeForProjectileToHit); RaycastHit2D raycastHit2D = Physics2D.Raycast(transform.position, target.position - transform.position, attackRange, layerMask); if (raycastHit2D.transform != target) velocity = GetVelocityForProjectile(timeForProjectileToHit * 2); projectile.SetVelocity(velocity); remainingCooldown = cooldownPerShoot; audioSource.Play(); OnShoot?.Invoke(); } protected Vector3 GetVelocityForProjectile(float time) { Vector3 vector3 = target.position - transform.position; vector3.z = 0f; vector3.y -= (Physics2D.gravity.y / 2) * (time * time); vector3 /= time; return vector3; } public virtual void UpdateTarget(Transform transform) => target = transform; protected virtual void OnDrawGizmosSelected() { Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(transform.position, 0.125f); Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, attackRange); } } }