You need to enable JavaScript to run this app. Unity中用Vector3.MoveTowards实现NPC仅横竖逐瓦片移动、禁止斜向的方法
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 17:15:02