108 lines
3.5 KiB
C#
108 lines
3.5 KiB
C#
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 bool canShoot => (target.transform.position - transform.position).sqrMagnitude < attackRangeSquared && target != null;
|
|
|
|
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();
|
|
UpdateTarget(FindObjectOfType<Player.PlayerController>()?.transform);
|
|
}
|
|
|
|
protected virtual void Start()
|
|
=> movement = transform.GetComponentInParent<IMovement>();
|
|
|
|
protected virtual void Update()
|
|
{
|
|
remainingCooldown -= Time.deltaTime;
|
|
|
|
if (canShoot && !isShooting)
|
|
StartCoroutine(ShootCoroutine());
|
|
}
|
|
|
|
protected IEnumerator ShootCoroutine()
|
|
{
|
|
isShooting = true;
|
|
float movementBaseSpeed = movement.BaseSpeed;
|
|
movement.BaseSpeed = 0f;
|
|
|
|
yield return new WaitForSeconds(focusingTime);
|
|
|
|
while (canShoot)
|
|
{
|
|
if (remainingCooldown <= 0f)
|
|
Shoot();
|
|
yield return null;
|
|
}
|
|
movement.BaseSpeed = movementBaseSpeed;
|
|
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);
|
|
if (raycastHit2D.transform != target)
|
|
velocity = GetVelocityForProjectile(timeForProjectileToHit * 2);
|
|
|
|
projectile.SetVelocity(velocity);
|
|
|
|
remainingCooldown = cooldownPerShoot;
|
|
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);
|
|
}
|
|
}
|
|
}
|