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

Unity脚本设置动画跳至最后关键帧、抖动异常如何解决

问题原因

你的代码存在3个核心逻辑错误,直接导致了异常表现:

  • 动画创建、播放逻辑错误放入了每帧执行的LateUpdate(或Update/FixedUpdate)中:每帧都会重新创建AnimationClip、重复向Animation组件添加同名动画片段、反复触发Play()重置动画播放进度,相当于动画永远在第0帧和刚启动的状态反复跳,重复添加的clip还会导致动画播放状态堆叠,出现速度越来越快、抖动跳变的问题。
  • 旋转属性绑定方式错误:localRotation是Quaternion类型,x/y/z/w四个分量不是独立的线性值,不能单独拆分做曲线插值;且你设置的动画起始关键帧四个分量全为0,根本不是合法的四元数值(单位四元数起始值w应为1),动画系统无法正确插值,就会直接跳转到结束帧。
  • 动画起始值未取骨骼当前真实状态:你硬编码起始旋转为全0值,和骨骼挂载时的初始旋转不匹配,会导致动画起始帧就跳变。
修复方法
  • 把所有动画初始化、创建、绑定逻辑全部移到Start()生命周期中,保证全局只执行1次
  • 不要直接操作localRotation的四个分量,改用localEulerAngles做角度插值,逻辑更直观也不会出现四元数插值异常
  • 动画播放逻辑只需要在初始化完成后调用一次,不要每帧重复触发
  • 曲线起始值取骨骼当前的初始欧拉角,结束值为目标旋转角度,保证插值平滑

修复后的完整代码如下:

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

public class DeformBone : MonoBehaviour
{
    // 动画总时长5秒,和原逻辑保持一致
    public float animDuration = 5f;
    // 目标Z轴旋转角度
    public float targetZAngle = 5f;
    
    void Start()
    {
        // 初始化逻辑仅执行一次
        SetupRotationAnimation();
    }

    private void SetupRotationAnimation()
    {
        // 取当前骨骼初始欧拉角作为动画起始值,避免跳变
        Vector3 startEuler = transform.localEulerAngles;
        Vector3 endEuler = new Vector3(startEuler.x, startEuler.y, startEuler.z + targetZAngle);
        
        // 创建欧拉角插值曲线
        AnimationCurve rotXCurve = AnimationCurve.EaseInOut(0, startEuler.x, animDuration, endEuler.x);
        AnimationCurve rotYCurve = AnimationCurve.EaseInOut(0, startEuler.y, animDuration, endEuler.y);
        AnimationCurve rotZCurve = AnimationCurve.EaseInOut(0, startEuler.z, animDuration, endEuler.z);

        AnimationClip clip = new AnimationClip();
        clip.legacy = true;

        // 绑定localEulerAngles曲线,不直接操作四元数分量
        clip.SetCurve("", typeof(Transform), "localEulerAngles.x", rotXCurve);
        clip.SetCurve("", typeof(Transform), "localEulerAngles.y", rotYCurve);
        clip.SetCurve("", typeof(Transform), "localEulerAngles.z", rotZCurve);

        // 初始化Animation组件
        Animation animation = GetComponent<Animation>();
        if (animation == null)
        {
            animation = gameObject.AddComponent<Animation>();
        }
        animation.playAutomatically = false;
        animation.wrapMode = WrapMode.PingPong;

        // 注册并播放动画,仅执行一次
        animation.AddClip(clip, "rotateyo");
        animation.Play("rotateyo");
    }
}

补充说明:如果后续需要动态修改旋转目标,不建议用legacy动画实现,直接在LateUpdate中手动对transform.localRotation做插值即可,逻辑更灵活,也不容易和骨骼原有动画产生冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:21:34