using GeometryTD.Definition; using GeometryTD.Entity; using UnityEngine; namespace Components { [DisallowMultipleComponent] public class DefenseTowerController : MonoBehaviour { [SerializeField] private ShooterMuzzleComp _muzzleComp; [SerializeField] private BasicBearingComp _bearingComp; [SerializeField] private BasicBaseComp _baseComp; [SerializeField] private Transform _scanOrigin; [SerializeField] [Min(0.02f)] private float _retargetInterval = 0.1f; [SerializeField] private bool _autoUpdate = true; private Transform _currentTarget; private float _retargetTimer; public Transform CurrentTarget => _currentTarget; private void Awake() { ResolveComponents(); } private void Update() { if (!_autoUpdate) { return; } OnUpdate(Time.deltaTime); } public void OnInit(DefenseTowerStatsData stats) { ResolveComponents(); if (stats == null) { return; } _muzzleComp?.OnInit(stats.AttackDamage, stats.AttackMethodType); _bearingComp?.OnInit(stats.RotateSpeed, stats.AttackRange); _baseComp?.OnInit(stats.AttackSpeed, stats.AttackPropertyType); _currentTarget = null; _retargetTimer = 0f; } public void OnReset() { _currentTarget = null; _retargetTimer = 0f; _muzzleComp?.OnReset(); _bearingComp?.OnReset(); _baseComp?.OnReset(); } public void SetAutoUpdate(bool autoUpdate) { _autoUpdate = autoUpdate; } public void SetTarget(Transform target) { _currentTarget = target; } public void ClearTarget() { _currentTarget = null; } public void OnUpdate(float deltaTime) { if (!HasCoreComponents()) { return; } if (!IsTargetValid(_currentTarget) || !_bearingComp.IsTargetInRange(_currentTarget, _scanOrigin)) { TryRetarget(deltaTime); } if (_currentTarget == null) { _baseComp.Tick(deltaTime); return; } _baseComp.TryAttack(_bearingComp, _muzzleComp, _currentTarget, deltaTime); } private void TryRetarget(float deltaTime) { _retargetTimer -= Mathf.Max(0f, deltaTime); if (_retargetTimer > 0f) { return; } _retargetTimer = _retargetInterval; _currentTarget = FindNearestEnemyTarget(); } private Transform FindNearestEnemyTarget() { Vector3 origin = _scanOrigin != null ? _scanOrigin.position : transform.position; float maxRange = _bearingComp.AttackRange; float maxRangeSquared = maxRange * maxRange; EnemyEntity bestEnemy = null; float bestDistanceSquared = float.MaxValue; for (int i = 0; i < EnemyEntity.ActiveEnemies.Count; i++) { EnemyEntity enemy = EnemyEntity.ActiveEnemies[i]; if (enemy == null || !enemy.isActiveAndEnabled) { continue; } Transform enemyTransform = enemy.transform; Vector3 delta = enemyTransform.position - origin; float distanceSquared = delta.sqrMagnitude; if (distanceSquared > maxRangeSquared || distanceSquared >= bestDistanceSquared) { continue; } bestDistanceSquared = distanceSquared; bestEnemy = enemy; } return bestEnemy != null ? bestEnemy.transform : null; } private void ResolveComponents() { if (_muzzleComp == null) { _muzzleComp = GetComponent(); } if (_bearingComp == null) { _bearingComp = GetComponent(); } if (_baseComp == null) { _baseComp = GetComponent(); } } private bool HasCoreComponents() { return _muzzleComp != null && _bearingComp != null && _baseComp != null; } private static bool IsTargetValid(Transform target) { return target != null && target.gameObject.activeInHierarchy; } } }