BGJ-2022.1/Assets/Scripts/AI/ShootingEnemyAI.cs

122 lines
4.0 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 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<IMovement>();
animator = transform.GetComponentInParent<Animator>();
audioSource = transform.GetComponentInParent<AudioSource>();
UpdateTarget(FindObjectOfType<Player.PlayerController>()?.transform);
}
protected virtual void Update()
{
if (IsPaused)
return;
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);
}
}
}