geometry-tower-defense/Assets/GameMain/Scripts/Components/BasicBearingComp.cs

121 lines
3.6 KiB
C#

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;
[SerializeField] private SpriteRenderer _renderer;
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 void SetColor(Color color)
{
if (_renderer != null)
{
_renderer.color = color;
}
}
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);
}
}
}