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

Unity 2021中Animator混合树抖动问题求助

玩家动画异常抖动问题排查

环境与设置

  • Unity版本:2021.3.6f1
  • 动画配置:四向idle/walk独立动画,通过两个混合树控制,使用moveX、moveY、is_idle三个Animator参数
  • 输入系统:Unity新输入系统
  • 相机:Cinemachine(已确认无问题)

问题现象

运行时动画出现异常抖动,表现为Animator不断重置动画播放状态。

排查过的方案

  • 最初使用Any State到各动画状态的过渡,问题依旧
  • 改用混合树后,调整多种参数仍未解决

关键代码(Player Controller)

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

public class PlayerController : MonoBehaviour
{
    public float moveSpeed = 1f;
    public ContactFilter2D movementFilter;
    public float collissionOffset = 0.05f;

    Vector2 movementInput;
    Vector2 prevMovementInput;
    Rigidbody2D rb;
    Animator animator;

    List<RaycastHit2D> castCollissions = new List<RaycastHit2D>();

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
    }

    private void FixedUpdate()
    {
        if (movementInput != Vector2.zero)
        {
            bool success = TryMove(movementInput);

            if (movementInput != prevMovementInput)
            {
                animator.SetFloat("moveX", movementInput.x);
                animator.SetFloat("moveY", movementInput.y);
                prevMovementInput = movementInput;
            }

            if (!success)
            {
                success = TryMove(new Vector2(movementInput.x, 0));
                if (!success)
                {
                    success = TryMove(new Vector2(0, movementInput.y));
                }
            }
            animator.SetBool("is_idle", false);
        }
        else
        {
            //animator.SetBool("is_idle", true);
        }
    }

    private bool TryMove(Vector2 direction)
    {
        int count = rb.Cast(direction,
                movementFilter,
                castCollissions,
                moveSpeed * Time.fixedDeltaTime + collissionOffset);

        if (count == 0)
        {
            rb.MovePosition(rb.position + direction * moveSpeed * Time.fixedDeltaTime);
            return true;
        }
        else
        {
            return false;
        }
    }

    void UpdateAnimation_DONT_USE()
    {
        // 原无混合树时的动画控制逻辑
        if (movementInput.x == 0.00d)
        {
            if (movementInput.y == 1.00d)
            {
                //up
                animator.SetInteger("direction", 1);
            }
        }
        else if (movementInput.x == 1.00d)
        {
            if (movementInput.y == 0.00d)
            {
                //right
                animator.SetInteger("direction", 2);
            }
        }
        else if (movementInput.x == 0.00d)
        {
            if (movementInput.y == -1.00d)
            {
                //down
                animator.SetInteger("direction", 3);
            }
        }
        else if (movementInput.x == -1.00d)
        {
            if (movementInput.y == 0.00d)
            {
                //left
                animator.SetInteger("direction", 4);
            }
        }
    }

    void OnMove(InputValue movementValue)
    {
        movementInput = movementValue.Get<Vector2>();
    }
}

可能的问题点与解决建议

  1. 输入值精度误差
    新输入系统的摇杆输入可能存在微小浮点波动,导致movementInput != prevMovementInput频繁触发,不断重置混合树参数。添加阈值判断避免误触发:
if (Mathf.Abs(movementInput.x - prevMovementInput.x) > 0.01f || Mathf.Abs(movementInput.y - prevMovementInput.y) > 0.01f)
{
    animator.SetFloat("moveX", movementInput.x);
    animator.SetFloat("moveY", movementInput.y);
    prevMovementInput = movementInput;
}
  1. FixedUpdate与动画帧时序不匹配
    Animator的参数更新依赖Update帧,而当前参数设置在FixedUpdate中,可能因FixedUpdate调用频率(默认50次/秒)与游戏帧率不一致导致同步问题。建议将Animator参数更新逻辑移到Update()方法中。

  2. 混合树过渡设置问题
    检查混合树的动画过渡时长(Transition Duration),若设置为0会导致瞬间切换引发抖动;同时确认混合树的参数范围与输入值(-1到1)完全匹配,避免参数超出范围导致的异常混合。

  3. is_idle参数逻辑缺失
    当前代码中静止状态下的is_idle设置被注释,导致无法切换到idle混合树,可能引发状态冲突。取消注释animator.SetBool("is_idle", true),确保静止时正确触发idle动画。

  4. 移动失败时的参数同步问题
    当TryMove失败(比如碰撞障碍物),玩家实际未移动但movementInput仍为非零,导致混合树参数与实际移动状态不符。可以在移动失败后,根据玩家实际的移动方向(而非原始输入)更新Animator参数,或者在完全无法移动时临时将is_idle设为true。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:03:05