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 int _damage; private AttackPropertyType _attackPropertyType; private float _lifetime; private float _runtimeMaxLifetime; private bool _isRunning; private bool _despawnRequested; public void OnShow(BulletData bulletData) { _target = bulletData != null ? bulletData.Target : null; _damage = bulletData != null ? Mathf.Max(0, bulletData.Damage) : 0; _attackPropertyType = bulletData != null ? bulletData.AttackPropertyType : AttackPropertyType.None; _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) { _despawnRequested = true; } } public void OnReset() { _target = null; _speed = 0f; _damage = 0; _attackPropertyType = AttackPropertyType.None; _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 toTarget = _target.position - transform.position; float hitDistanceSquared = _hitDistance * _hitDistance; if (toTarget.sqrMagnitude <= hitDistanceSquared) { HitTarget(); return; } Vector3 forward = toTarget.normalized; float moveDistance = _speed * Mathf.Max(0f, deltaTime); if (moveDistance * moveDistance >= toTarget.sqrMagnitude) { transform.position = _target.position; HitTarget(); return; } transform.position += forward * moveDistance; transform.forward = forward; } 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(); for (int i = 0; i < components.Length; i++) { if (components[i] is IDamageReceiver damageReceiver) { damageReceiver.TakeDamage(_damage, _attackPropertyType); break; } } _isRunning = false; _despawnRequested = true; } } }