You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity3D动画状态机运行时敌方物体无法移动问题排查

问题背景

学习动画状态机实现过程中遇到运行异常:为敌方物体实现的逻辑为检测到玩家后自动向玩家移动,双方距离进入攻击范围时触发「攻击」状态。目前攻击触发可正常生效,但敌方物体完全无法执行跟随移动逻辑,没有任何位移,无法定位问题来自实现代码还是动画配置等其他环节,对应实现代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class enemyRun : StateMachineBehaviour
{

    public float speed = 2.5f;
    public float attackRange = 3f;

    Transform player;
    Rigidbody rb;
    //Boss boss;

    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        player = GameObject.FindGameObjectWithTag("Player").transform;
        rb = animator.GetComponent<Rigidbody>();
        //boss = animator.GetComponent<enemy>();

    }

    // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        //boss.LookAtPlayer();

        Vector3 target = new Vector3(player.position.x, player.position.y, player.position.z);
        Vector3 newPos = Vector3.MoveTowards(rb.position, target, speed * Time.fixedDeltaTime);
        rb.MovePosition(newPos);
    
        if (Vector3.Distance(player.position, rb.position) <= attackRange)
        {
            animator.SetTrigger("attack");
        }
    }

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        animator.ResetTrigger("attack");
    }
}
排查方向与修复方案

代码层面问题

  • 时间参数调用错误:OnStateUpdate和Update同频,是每帧调用的,这里移动计算用了Time.fixedDeltaTime(固定物理帧的时间步长,默认0.02s),当游戏实际帧率高于/低于50帧时,每帧移动的距离计算会完全错误,帧率较高时每帧移动距离极小,视觉上就是完全不动。把Time.fixedDeltaTime替换为Time.deltaTime即可。
  • Rigidbody获取存在空引用风险:animator.GetComponent<Rigidbody>()只会查找Animator组件所在物体上挂载的Rigidbody,如果你的Rigidbody挂在敌人对象的父节点或者子节点上,这里拿到的rb是null,后续移动逻辑自然不会生效。可以在OnStateEnter里加一行空判断快速定位:
    if (rb == null) Debug.LogError("未获取到Rigidbody,请检查组件挂载层级");
    
  • 移动轴设置不合理:当前代码直接复制玩家的全坐标作为目标点,如果是地面3D游戏/2D游戏,玩家和敌人的Y轴坐标不一致,会导致敌人持续向Y轴方向移动,很容易被地形卡住表现为不动。地面单位的目标点应该锁定自身Y轴,修改为:
    Vector3 target = new Vector3(player.position.x, rb.position.y, player.position.z);
    

配置层面问题

  • Rigidbody约束设置错误:检查Rigidbody组件的Constraints选项,如果冻结了移动平面的对应轴(比如3D地面游戏冻结了X、Z轴位置,2D游戏冻结了X轴位置),所有代码控制的位移都会失效。地面单位通常只需要冻结Y轴位置、全旋转轴即可。
  • 动画状态未正常切入:虽然攻击逻辑能触发,但要确认敌人是否真的进入了enemyRun状态——如果状态机切换条件配置错误,敌人一直停留在Idle等其他状态,OnStateUpdate里的移动逻辑根本不会执行,可以在OnStateEnter里加Debug日志确认状态是否正常进入。
  • Animator根运动冲突:如果Animator组件勾选了Apply Root Motion,动画自带的根运动位移会覆盖代码控制的Rigidbody移动。纯代码控制位移的话直接取消勾选该选项即可。
  • 物理碰撞卡住:检查敌人的碰撞体尺寸是否合理,有没有初始就嵌入地形、其他静态碰撞体的情况,这种情况下Rigidbody的移动会被物理引擎阻挡,无法产生位移。

内容的提问来源于stack exchange,提问作者Teabelly

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:39:18