Unity中用Vector3.MoveTowards实现NPC仅横竖逐瓦片移动、禁止斜向的方法
逐瓦片轴向追逐NPC实现方案
核心逻辑说明
完全对齐你已实现的玩家逐瓦片移动规则,仅做NPC专属的方向计算逻辑调整,保证移动规则、碰撞判定、流畅度和玩家完全统一:
- 保留
isMoving状态锁,移动过程中不触发新的移动指令,保证每次移动严格走1个瓦片长度 - 方向计算仅选横/纵其中一个轴向移动,天然禁止斜向移动
- 复用你已写好的
IsWalkable碰撞判定逻辑,保证NPC不会穿透障碍物
调整后的完整ChaseScript代码
public class ChaseScript : MonoBehaviour { public float moveSpeed = 4f; public LayerMask SolidObjectLayer; public LayerMask NPC; private Transform playerTransform; private bool isMoving = false; private Animator animator; // 不需要NPC动画可直接删除该行及相关初始化代码 void Start() { // 仅初始化时获取一次玩家Transform,避免每帧重复获取浪费性能 playerTransform = GameObject.Find("Player").transform; // animator = GetComponent<Animator>(); 需要NPC动画时放开该行 } void Update() { if (!isMoving) { CalculateAndMove(); } } void CalculateAndMove() { // 计算与玩家的坐标差 float deltaX = playerTransform.position.x - transform.position.x; float deltaY = playerTransform.position.y - transform.position.y; Vector3 targetMovePos = transform.position; bool hasValidDirection = false; // 优先选择距离差更大的轴向移动,快速缩小与玩家的距离 if (Mathf.Abs(deltaX) > Mathf.Abs(deltaY)) { // 尝试走X轴 targetMovePos.x += Mathf.Sign(deltaX); if (IsWalkable(targetMovePos)) { hasValidDirection = true; } else { // X轴被阻挡,尝试走Y轴 targetMovePos = transform.position; targetMovePos.y += Mathf.Sign(deltaY); if (deltaY != 0 && IsWalkable(targetMovePos)) { hasValidDirection = true; } } } else { // 尝试走Y轴 targetMovePos.y += Mathf.Sign(deltaY); if (deltaY != 0 && IsWalkable(targetMovePos)) { hasValidDirection = true; } else { // Y轴被阻挡,尝试走X轴 targetMovePos = transform.position; targetMovePos.x += Mathf.Sign(deltaX); if (IsWalkable(targetMovePos)) { hasValidDirection = true; } } } if (hasValidDirection) { // 存在可行走方向时启动移动协程,和玩家逻辑完全对齐 StartCoroutine(Move(targetMovePos)); } } IEnumerator Move(Vector3 movePos) { isMoving = true; // 需要NPC动画的可在此处添加动画触发逻辑,和玩家逻辑对齐即可 while ((movePos - transform.position).sqrMagnitude > Mathf.Epsilon) { transform.position = Vector3.MoveTowards(transform.position, movePos, moveSpeed * Time.deltaTime); yield return null; } transform.position = movePos; isMoving = false; // 需要NPC动画的可在此处添加移动结束的动画切换逻辑 } private bool IsWalkable(Vector3 movePos) { // 完全复用玩家的碰撞判定逻辑 if (Physics2D.OverlapCircle(movePos, 0.1f, SolidObjectLayer | NPC) != null) { return false; } return true; } }
配置说明
脚本挂载到NPC对象后,在Inspector面板将SolidObjectLayer和NPC层选为和玩家控制器中配置的相同层即可生效。如果需要NPC支持奔跑效果,可参照玩家逻辑添加速度动态调整代码。
内容的提问来源于stack exchange,提问作者Daniel Canaria
相关产品推荐
相关产品推荐

