138 lines
4.2 KiB
C#
138 lines
4.2 KiB
C#
using UnityEngine;
|
|
using GeometryTD.Definition;
|
|
using GeometryTD.Entity.EntityData;
|
|
|
|
namespace Components
|
|
{
|
|
[DisallowMultipleComponent]
|
|
public class ShooterBullet : MonoBehaviour
|
|
{
|
|
[SerializeField] [Min(0.1f)] private float _defaultSpeed = 12f;
|
|
[SerializeField] [Min(0.02f)] private float _hitDistance = 0.15f;
|
|
[SerializeField] [Min(0.1f)] private float _maxLifetime = 3f;
|
|
|
|
private Transform _target;
|
|
private float _speed;
|
|
private AttackPayload _attackPayload;
|
|
private float _lifetime;
|
|
private float _runtimeMaxLifetime;
|
|
private bool _isRunning;
|
|
private bool _despawnRequested;
|
|
|
|
public void OnShow(BulletData bulletData)
|
|
{
|
|
_target = bulletData != null ? bulletData.Target : null;
|
|
_attackPayload = bulletData?.AttackPayload?.Clone() ?? new AttackPayload();
|
|
_speed = bulletData != null && bulletData.Speed > 0f ? bulletData.Speed : _defaultSpeed;
|
|
_runtimeMaxLifetime = bulletData != null && bulletData.MaxLifetime > 0f ? bulletData.MaxLifetime : _maxLifetime;
|
|
_lifetime = 0f;
|
|
_despawnRequested = false;
|
|
_isRunning = _target != null;
|
|
if (_isRunning)
|
|
{
|
|
Vector2 initialDirection = (Vector2)(_target.position - transform.position);
|
|
RotateToDirection(initialDirection);
|
|
}
|
|
|
|
if (!_isRunning)
|
|
{
|
|
_despawnRequested = true;
|
|
}
|
|
}
|
|
|
|
public void OnReset()
|
|
{
|
|
_target = null;
|
|
_speed = 0f;
|
|
_attackPayload = new AttackPayload();
|
|
_lifetime = 0f;
|
|
_runtimeMaxLifetime = _maxLifetime;
|
|
_isRunning = false;
|
|
_despawnRequested = false;
|
|
}
|
|
|
|
public void Tick(float deltaTime)
|
|
{
|
|
if (!_isRunning)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_lifetime += Mathf.Max(0f, deltaTime);
|
|
if (_lifetime >= _runtimeMaxLifetime || _target == null)
|
|
{
|
|
_isRunning = false;
|
|
_despawnRequested = true;
|
|
return;
|
|
}
|
|
|
|
Vector3 currentPosition = transform.position;
|
|
Vector2 toTarget = (Vector2)(_target.position - currentPosition);
|
|
float hitDistanceSquared = _hitDistance * _hitDistance;
|
|
if (toTarget.sqrMagnitude <= hitDistanceSquared)
|
|
{
|
|
HitTarget();
|
|
return;
|
|
}
|
|
|
|
Vector2 direction = toTarget.normalized;
|
|
RotateToDirection(direction);
|
|
float moveDistance = _speed * Mathf.Max(0f, deltaTime);
|
|
if (moveDistance * moveDistance >= toTarget.sqrMagnitude)
|
|
{
|
|
Vector3 targetPosition = _target.position;
|
|
transform.position = new Vector3(targetPosition.x, targetPosition.y, currentPosition.z);
|
|
HitTarget();
|
|
return;
|
|
}
|
|
|
|
transform.position += (Vector3)(direction * moveDistance);
|
|
}
|
|
|
|
public bool TryConsumeDespawnRequest()
|
|
{
|
|
if (!_despawnRequested)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
_despawnRequested = false;
|
|
return true;
|
|
}
|
|
|
|
private void HitTarget()
|
|
{
|
|
if (_target == null)
|
|
{
|
|
_isRunning = false;
|
|
_despawnRequested = true;
|
|
return;
|
|
}
|
|
|
|
MonoBehaviour[] components = _target.GetComponentsInParent<MonoBehaviour>();
|
|
foreach (var mono in components)
|
|
{
|
|
if (mono is IDamageReceiver damageReceiver)
|
|
{
|
|
damageReceiver.TakeDamage(_attackPayload);
|
|
break;
|
|
}
|
|
}
|
|
|
|
_isRunning = false;
|
|
_despawnRequested = true;
|
|
}
|
|
|
|
private void RotateToDirection(Vector2 direction)
|
|
{
|
|
if (direction.sqrMagnitude <= Mathf.Epsilon)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float targetZAngle = Vector2.SignedAngle(Vector2.up, direction);
|
|
transform.rotation = Quaternion.Euler(0f, 0f, targetZAngle);
|
|
}
|
|
}
|
|
}
|