Files

143 lines
4.5 KiB
C#

using BumpCombat.Player;
using BumpCombat.Core;
using UnityEngine;
namespace BumpCombat.Enemies
{
/// <summary>
/// A small gameplay projectile used by the stage ranged enemies. The
/// projectile owns its travel and lifetime; the enemy owns its warning
/// and attack timing.
/// </summary>
public sealed class EnemyProjectile : MonoBehaviour
{
private PlayerHealth target;
private Vector2 direction;
private float damage;
private float speed;
private float remainingDistance;
private float hitRadius;
private bool resolved;
public EnemyController Owner { get; private set; }
public static EnemyProjectile Launch(
EnemyController owner,
Vector2 origin,
Vector2 direction,
float damage,
float speed,
float maxDistance,
float hitRadius,
bool isBeam)
{
GameObject root = new GameObject(
isBeam ? "Necrofire Beam Projectile" : "Skeleton Archer Arrow");
root.transform.position = origin;
root.transform.right = direction.sqrMagnitude > 0.0001f
? direction.normalized
: Vector2.right;
EnemyProjectile projectile = root.AddComponent<EnemyProjectile>();
projectile.Owner = owner;
projectile.direction = root.transform.right;
projectile.damage = Mathf.Max(0f, damage);
projectile.speed = Mathf.Max(0f, speed);
projectile.remainingDistance = Mathf.Max(0.1f, maxDistance);
projectile.hitRadius = Mathf.Max(0.03f, hitRadius);
projectile.target = FindAnyObjectByType<PlayerHealth>();
StageEnemyEffectVisual.AttachProjectile(
root,
isBeam,
isBeam ? 1.2f : 0.6f,
Mathf.Max(0.04f, projectile.hitRadius * 2f));
return projectile;
}
private void Update()
{
if (resolved
|| target == null
|| Owner == null
|| Owner.IsDead
|| !Owner.isActiveAndEnabled)
{
Destroy(gameObject);
return;
}
if (!RunManager.GameplayInputEnabled)
{
return;
}
if (Time.deltaTime <= 0f)
{
return;
}
float distance = speed * Time.deltaTime;
Vector2 previousPosition = transform.position;
if (distance > 0f)
{
transform.position += (Vector3)(direction * distance);
remainingDistance -= distance;
}
bool hitTarget = false;
if (distance > 0f)
{
RaycastHit2D[] hits = Physics2D.CircleCastAll(
previousPosition,
hitRadius,
direction,
distance,
Physics2D.AllLayers);
for (int i = 0; i < hits.Length; i++)
{
if (hits[i].collider != null
&& hits[i].collider.GetComponentInParent<PlayerHealth>() == target)
{
hitTarget = true;
break;
}
}
}
else
{
Collider2D[] overlaps = Physics2D.OverlapCircleAll(
transform.position,
hitRadius,
Physics2D.AllLayers);
for (int i = 0; i < overlaps.Length; i++)
{
if (overlaps[i] != null
&& overlaps[i].GetComponentInParent<PlayerHealth>() == target)
{
hitTarget = true;
break;
}
}
}
if (hitTarget)
{
resolved = true;
target.TryTakeDamage(
damage,
((Vector2)target.transform.position - (Vector2)transform.position).normalized,
Owner.PlayerKnockbackDistance);
Destroy(gameObject);
return;
}
if (remainingDistance <= 0f)
{
Destroy(gameObject);
}
}
private void OnDisable()
{
resolved = true;
}
}
}