using UnityEngine; namespace Components { [DisallowMultipleComponent] public class BasicBearingComp : MonoBehaviour { [SerializeField] [Min(1f)] private float _rotateSpeed = 180f; [SerializeField] [Min(0.1f)] private float _attackRange = 5f; [SerializeField] [Min(0.1f)] private float _aimToleranceAngle = 2f; [SerializeField] private Transform _rotateRoot; public float RotateSpeed => _rotateSpeed; public float AttackRange => _attackRange; public float AimToleranceAngle => _aimToleranceAngle; public void OnInit(float rotateSpeed, float attackRange = 5f) { _rotateSpeed = Mathf.Max(1f, rotateSpeed); _attackRange = Mathf.Max(0.1f, attackRange); } public void OnReset() { _rotateSpeed = 1f; _attackRange = 5f; } public bool IsTargetInRange(Transform target, Transform origin = null) { if (target == null) { return false; } Transform originTransform = origin != null ? origin : transform; Vector3 delta = target.position - originTransform.position; return delta.sqrMagnitude <= _attackRange * _attackRange; } public bool TrackTarget(Transform target, float deltaTime) { if (target == null) { return false; } Transform rotateRoot = _rotateRoot != null ? _rotateRoot : transform; Vector2 toTarget = (Vector2)(target.position - rotateRoot.position); if (toTarget.sqrMagnitude <= Mathf.Epsilon) { return true; } float targetZAngle = Vector2.SignedAngle(Vector2.up, toTarget); float currentZAngle = rotateRoot.eulerAngles.z; float maxStep = _rotateSpeed * Mathf.Max(0f, deltaTime); float angleDelta = Mathf.DeltaAngle(currentZAngle, targetZAngle); float nextZAngle = currentZAngle + Mathf.Clamp(angleDelta, -maxStep, maxStep); rotateRoot.rotation = Quaternion.Euler(0f, 0f, nextZAngle); return IsTargetAligned(target); } public bool IsTargetAligned(Transform target) { if (target == null) { return false; } Transform rotateRoot = _rotateRoot != null ? _rotateRoot : transform; Vector2 toTarget = (Vector2)(target.position - rotateRoot.position); if (toTarget.sqrMagnitude <= Mathf.Epsilon) { return true; } float targetZAngle = Vector2.SignedAngle(Vector2.up, toTarget); float currentZAngle = rotateRoot.eulerAngles.z; float angle = Mathf.Abs(Mathf.DeltaAngle(currentZAngle, targetZAngle)); return angle <= _aimToleranceAngle; } public bool TryAttack(ShooterMuzzleComp shooterMuzzleComp, Transform target, float deltaTime) { if (shooterMuzzleComp == null || target == null) { return false; } if (!IsTargetInRange(target)) { return false; } bool isAligned = TrackTarget(target, deltaTime); if (!isAligned) { return false; } return shooterMuzzleComp.Attack(target); } } }