143 lines
4.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|