using UnityEngine; /// /// 主角自动巡逻移动:不再支持点击地面移动(避免与拖动屏幕、建筑放置的输入冲突)。 /// 没有敌人时在己方主建筑周围小范围来回走动,所有移动被限制在基地附近(栓绳范围)。 /// 战斗组件发现敌人后调用 SetPatrolEnabled(false) 停止巡逻进行攻击。 /// public class MainCharacterDebugMovement : MonoBehaviour { [Header("巡逻移动")] [Min(0f)] public float moveSpeed = 4f; [Min(0f)] public float patrolStopDistance = 0.15f; [Min(0f)] public float patrolPause = 1.5f; [Header("巡逻区域(以主建筑为锚点)")] [Min(0f)] public float patrolRadius = 5f; [Min(0f)] public float leashRadius = 8f; public string friendlyBuildingTag = "Friend"; private Animator animator; private Transform baseAnchor; private Vector3 fallbackAnchor; private Vector3 patrolTarget; private Vector3 chaseTarget; private bool hasPatrolTarget; private bool hasChaseTarget; private float pauseTimer; private bool patrolEnabled = true; public bool IsMoving { get; private set; } private Vector3 AnchorPosition { get { Vector3 position = baseAnchor != null ? baseAnchor.position : fallbackAnchor; position.y = transform.position.y; return position; } } private void Start() { animator = GetComponent(); fallbackAnchor = transform.position; baseAnchor = FindMainBase(); SetWalking(false); } private void Update() { if (!patrolEnabled) { UpdateChase(); return; } if (pauseTimer > 0f) { pauseTimer -= Time.deltaTime; IsMoving = false; SetWalking(false); return; } if (!hasPatrolTarget) { patrolTarget = GetNextPatrolPoint(); hasPatrolTarget = true; } Vector3 toTarget = patrolTarget - transform.position; toTarget.y = 0f; if (toTarget.magnitude <= patrolStopDistance) { hasPatrolTarget = false; pauseTimer = patrolPause; IsMoving = false; SetWalking(false); return; } Move(toTarget.normalized); } private void UpdateChase() { if (!hasChaseTarget) { IsMoving = false; SetWalking(false); return; } Vector3 toTarget = chaseTarget - transform.position; toTarget.y = 0f; if (toTarget.magnitude <= patrolStopDistance) { IsMoving = false; SetWalking(false); return; } // 追击同样受栓绳限制,不会完全离开基地 Move(toTarget.normalized); } private Transform FindMainBase() { Transform firstBuilding = null; foreach (GameObject candidate in GameObject.FindGameObjectsWithTag(friendlyBuildingTag)) { if (candidate == null || candidate.transform.root == transform.root) { continue; } // 主建筑按名称优先匹配;找不到时退回第一个己方建筑 if (candidate.name.Contains("主要") || candidate.name.Contains("基地")) { return candidate.transform; } if (firstBuilding == null) { firstBuilding = candidate.transform; } } return firstBuilding; } private Vector3 GetNextPatrolPoint() { Vector2 offset = Random.insideUnitCircle * patrolRadius; return ClampToLeash(AnchorPosition + new Vector3(offset.x, 0f, offset.y)); } private Vector3 ClampToLeash(Vector3 position) { Vector3 offset = position - AnchorPosition; offset.y = 0f; if (offset.magnitude > leashRadius) { offset = offset.normalized * leashRadius; } return AnchorPosition + offset; } public bool IsWithinLeash(Vector3 position) { Vector3 offset = position - AnchorPosition; offset.y = 0f; return offset.magnitude <= leashRadius; } public void SetPatrolEnabled(bool enabled) { if (patrolEnabled == enabled) { return; } patrolEnabled = enabled; if (!enabled) { hasPatrolTarget = false; pauseTimer = 0f; IsMoving = false; SetWalking(false); } else { hasChaseTarget = false; } } public void SetChaseTarget(Vector3 position) { chaseTarget = position; chaseTarget.y = transform.position.y; hasChaseTarget = true; } public void ClearChaseTarget() { hasChaseTarget = false; } public void StopMovement() { hasPatrolTarget = false; hasChaseTarget = false; IsMoving = false; SetWalking(false); } private void Move(Vector3 direction) { direction.y = 0f; if (direction.sqrMagnitude <= 0.001f) { IsMoving = false; SetWalking(false); return; } IsMoving = true; SetWalking(true); transform.position += direction * moveSpeed * Time.deltaTime; // 栓绳:任何情况下都不能完全离开基地 Vector3 clamped = ClampToLeash(transform.position); clamped.y = transform.position.y; transform.position = clamped; transform.rotation = Quaternion.LookRotation(direction, Vector3.up); } private void SetWalking(bool walking) { if (animator != null) { animator.SetInteger("speed", walking ? 1 : 0); } } }