Unity 动画系统

这篇具有很好参考价值的文章主要介绍了Unity 动画系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

动画系统包含:

  • 动画片段 Animation Clip,记录物体变化的信息,可以是角色的闪转腾挪,也可以是一扇门的开闭
  • 动画状态机 Animator Controller,根据设置切换动画片段
  • 动画组件 Animator,Animation
  • 替身 Avatar,对人形动画进行复用

动画复用

把一个 .anim 的动画文件作为文本打开
unity动画,动画,unity
里面有个path属性记录动画要操作的对象的路径,如果根据path找不到对象,这个动画就会失效

unity动画,动画,unity
其他物体要使用这个动画就必须包含路径一致的对象,否则Animation窗口里就会显示Missing

unity动画,动画,unity
对于人形动画的fbx文件,选中动画按Ctrl + D就可以把动画复制出来,同样作为文本打开

unity动画,动画,unity
这里path为空,而attribute记录Avatar中对应的骨骼节点和进行什么操作

Avatar 替身系统

unity动画,动画,unity
在mixamo上下载一个动画文件

unity动画,动画,unity
不同DCC软件制作的骨骼节点的名称可能不一样的,不能直接使用该动画,这时候需要借助Avatar建立骨骼和Unity肌肉系统的映射关系

假设A,B两个模型的骨骼名称不同,要把A模型的动画片段A复用到B模型上
unity动画,动画,unity
步骤:
1.创建AAvatar,AAvatar中保存模型A骨骼和Unity肌肉结构的对应关系,骨骼信息也被保存到Avatar文件中
2.创建BAvatar,BAvatar中保存模型B骨骼和Unity肌肉结构的对应关系
3.通过AAvatar,把动画片段A从描述A的骨骼变化翻译为描述unity肌肉拉伸
4.模型B使用动画片段A,通过BAvatar把动画文件中对Unity肌肉结构的描述翻译为对B模型骨骼变化的描述

具体操作
unity动画,动画,unity
在模型的Rig面板中选择人形动画,点击Apply

Avatar Definition Create From This Model 从这个模型本身创建Avatar,把当前模型的骨骼与Unity肌肉结构建立对应关系
Copy from OtherAvatar 从其他Avatar中复制骨骼层次结构、绑定信息等,需要确保两者具有相似的骨骼层次结构和绑定信息,模型不会创建新的Avatar,只会导入动画
Skin Weights 蒙皮或者mesh上的节点可以被几个骨骼所影响
Strip Bones 勾选后,Unity会自动删除所有不必要的骨骼,并将相邻的骨骼合并为一个单独的骨骼。这样可以减少骨骼数量和顶点权重数量,从而提高游戏性能
Optimize Game Objects 勾选后会删除模型上的骨骼,从Avatar中读取骨骼信息

unity动画,动画,unity
模型中会出现Avatar,点击Inspector界面上的Configure Avatar进入配置界面
unity动画,动画,unity
这里可以看到骨骼和Unity肌肉的映射关系,这些Unity基本已经配置好了,一般不需要修改
unity动画,动画,unity
动画的Rig面板中选择Copy From Other Avatar,并选择来源模型的Avatar,点击Apply
在模型的Animator组件中选择各自的Avatar文件,这时动画就可以复用了

Animator

unity动画,动画,unity

Apply Root Motion 有的动画片段自带位移,勾选后就会把位移应用到对象上,如果通过脚本控制位移就不勾选
Update Mode Normal 与Monobehaviour的Update同步
Animate Physics 与FixedUpdate同步,如果角色动画需要与物理系统交互,选这个
Unscaled Time 与Update同步,忽略TimeScale
Culling Mode Always Animate 不剔除,始终运行动画
Cull Update Transforms 不可见时会禁用重定向,ik,Transform变化
Cull Completely 不可见时停止模拟,再次出现时,从停止的状态继续模拟

运行时最下面还会显示动画片段相关信息

unity动画,动画,unity
在Animator中动画状态分为3种:单独的动画片段,多个片段组成的混合树,另一个状态机

unity动画,动画,unity
在Animator窗口右上角有个Auto Live Link,选中后会在窗口内聚焦当前播放的动画状态
unity动画,动画,unity

动画片段(AnimationClip)

unity动画,动画,unity

Tag 给动画加标签,在代码中就可以根据动画的标签执行不同的逻辑
Motion 这个动画状态管理的动画片段,如果是混合树就显示管理的混合树
Speed 动画播放速度,负值就是倒放,脚本无法修改Speed数值
Multiplier 勾选右边的Parameter激活,选择Parameters中的一个浮点型参数关联,动画的速度就等于 Speed * Multiplier
Motion Time 范围0~1f,修改后会使动画停在特定时间点,0是开始,1是结束
Mirror 镜像动画
Cycle Offset 播放时的偏移值,0表示不偏移,0.5表示从中间开始播放,偏移不是切割,动画还是会完整播放,只是动画的起始点改变
Foot IK 使用IK矫正,把脚步实际位置向IK Goal位置拉近一点,需要设置IK Goal权重
Write Defaults Animator触发OnEable时,将遍历AnimatorController中的所有片段,收集所有片段的属性值。如果某个片段中没有描述某些属性的变化,是否为其写入默认值

正向动力学(Forward Kinematics):常见的动画一般是由骨骼根节点(人形动画是屁股)到末梢骨骼节点依次计算旋转位移缩放来决定每个骨骼的最终位置
反向动力学(Inverse Kinematics):末梢骨骼位置确定,反向计算各个父节点骨骼的旋转位移缩放,比如脚放在台阶上,反向计算其各个父骨骼

unity动画,动画,unity
使用Avatar把骨骼系统转为肌肉系统后,双手,双脚位置可能出现一些偏移,Unity会保存转换前骨骼系统下手脚的正确位置,并把这些位置放在IK Goal(目标位置)上,也就是上图中双手,双脚位置的红球,手肘处的红球和膝盖处的红球是IK Hint(辅助位置),通过它防止肘部关节出现奇怪的扭曲,Foot Ik参考的是IK Goal的初始位置
unity动画,动画,unity
使用IK需要在Layer上激活IK Pass,这样就可以在脚本中调用IK相关方法

public class AnimatorTest : MonoBehaviour
{
    [Range(0, 1)]
    public float weight;
    
    private Animator animator;
    //动画状态
    private AnimatorStateInfo stateInfo;
    //关联Multiplier参数
    private float animationMultiplier = 1;
    //Multiplier映射的hash值
    private int multiplierHash;

    void Start()
    {
        animator = GetComponent<Animator>();
        multiplierHash = Animator.StringToHash("Multiplier");
        animator.SetFloat(multiplierHash, animationMultiplier);

        //获取当前动画状态,0表示base layer
        stateInfo = animator.GetCurrentAnimatorStateInfo(0);
        //判断动画的Tag是否为Anim
        if (stateInfo.IsTag("Anim"))
        {
            //do something
        }
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.W))
        {
            animationMultiplier += 0.1f;
            animator.SetFloat(multiplierHash, animationMultiplier);
        }
    }

    /// <summary>
    /// layer上开启IK Pass
    /// </summary>
    private void OnAnimatorIK(int layerIndex)
    {
        //设置右脚IKGoal的位置
        animator.SetIKPosition(AvatarIKGoal.RightFoot, new Vector3(1,0,0));
        //权重越高,右脚越靠近设置的位置
        animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, weight);
    }
}

调用时机
unity动画,动画,unity
unity动画,动画,unity
当Animator的Update Mode为Nomal或Unscaled Time,OnAnimatorMove和OnAnimatorIk方法与Update同步,当Update Mode为Animate Physics时,与FixedUpdate同步

状态转换(Transition)

unity动画,动画,unity
两个状态之间可以添加多个转换,这样会变成三个箭头,选中右侧的某个转换就可以为其单独设置转换条件,比如条件1和条件2都会触发 idle -> walk 这个转换,分别设置转换条件即可,它们之间是 “或” 的关系

转换的优先级:
1.如果有勾选了Solo,只执行勾选的转换,不考虑其他的
2.勾选的Solo的转换中,哪个条件先满足就执行哪个转换
3.如果条件同时满足,优先执行上面的转换
4.勾选Mute的转换不会执行

unity动画,动画,unity
上方可以修改转换名称

Has Exit Time 勾选表示条件满足也要播放到某个时间点才执行转换,不勾选需要设置Conditions
Exit Time 比例值,0表示从第一帧转换,0.5表示从中间帧开始
Fixed Duration 勾选表示转换持续时间按秒计算,否则按百分比计算
Transition Duration 转换持续时间
Transition Offset 0表示下一个动画状态从第一帧开始播放,0.5表示下一个动画状态从中间一帧开始播放
Transition Duration 转换持续时间
Interruption Source None 转换不能被打断
Current State 可以被其他相同起始状态的转换打断,设置Ordered Interruption需要优先级更高
Next State 可以被其他相同目标状态的转换打断
Current State Then Next State 有相同状态的转换都可以打断,但起始状态一样的优先级更高
Next State Then Current State 有相同状态的转换都可以打断,但目标状态一样的优先级更高
Ordered Interruption 勾选表示转换按照优先级排序,优先级更高的状态才能打断
Conditions 转换条件

状态机里只有四个状态,从A到D。当中的所有转换由相应的触发器变量(trigger)来控制
unity动画,动画,unity
与A相关的转换有三个
unity动画,动画,unity

选中A到B的转换,把Interruption Source设置为Current State且Ordered Interruption勾选
当激活触发器来启动A->B的转换时,从A到B的转换就可以被某些同样从A出发的转换所打断了,因为勾选Ordered Interruption,转换只能被优先级更高的A到C的转换打断

unity动画,动画,unity
Trigger类型的参数只要激活就会触发转换,如果与Trigger相关的动画转换并没有被执行,Trigger会一直处于激活状态,直到转换被执行
Conditions可以设置多条,它们之间是 “与” 的关系,必须同时满足才能触发转换,注意如果勾选Has Exit Time,即使条件满足也得等动画播放到Exit Time才能触发转换

Root Motion动画

Root Motion动画自带根位移,会把动画上的位移应用到对象上,有效避免角色动画和实际位移不同步产生的滑步现象。动画文件会在每一帧里直接修改对象的坐标值和角度值(绝对值),而Root Motion则通过相对位移和转角来移动游戏对象

Animator勾选Apply Root Motion后,Unity会让游戏对象会乘以缩放矩阵,旋转矩阵,平移矩阵

public class AnimatorTest : MonoBehaviour
{
    private Animator animator;

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

    /// <summary>
    /// 使用该方法用代码替代动画修改对象位移旋转
    /// </summary>
    private void OnAnimatorMove()
    {
        //animator.deltaPosition已经考虑了缩放值
        transform.position += animator.deltaPosition;
        transform.rotation *= animator.deltaRotation;
    }
}

unity动画,动画,unity
勾选Apply Root Motion并实现OnAnimatorMove,动画由脚本控制

在Generic动画中的使用Root Motion,只需要管理一根根骨骼Root node,实际工作中,美术一般会给模型单独制作一根根骨骼,这个骨骼的作用就是记录模型的位移旋转
unity动画,动画,unity
Unity会把Generic动画对这根骨骼的操作当作对游戏对象的操作,Apply Root Motion会把根骨骼节点上的绝对坐标和绝对角度,转换为游戏对象的相对位移和相对转角

unity动画,动画,unity
Root Transform Rotation(绕y轴旋转),Root Transform Position(Y)(y方向位移),Root Transform Position(XZ)(水平方向位移),这三个属性与Root Motion相关的动画
unity动画,动画,unity
动画文件中的Root Q和Root T表示对游戏对象的旋转和位移,勾选Root Transform Rotation下的Bake Into Pose就不会旋转游戏对象,而是去旋转根骨骼节点,当我们不希望动画带动游戏对象旋转时,就需要勾选这个Bake Into Pose。后面的loop match是检查动画第一帧和最后一帧的吻合度,红色表示不吻合,绿色表示吻合,红色就不要勾选Bake Into Pose
Root Transform Position(Y)下的Bake Into Pose同理,勾选后动画不会影响游戏对象y方向上的位移,而是去修改根骨骼的位移

Root Transform Rotation 绕y轴旋转
Bake Into Pose 勾选表示旋转只影响骨骼和蒙皮(外观),并不影响游戏对象的旋转,能不能勾选参考loop match
Based Upon 游戏对象开始时对准的方向
Original 动画本来的朝向,美术制作时设置的朝向,一般选这个
Root Node Rotation(Generic) 对准根骨骼节点方向,一般不准确
Body Orientation(Humanoid) 对准上半身前方,一般不准确
Offset 对旋转做偏移
Root Transform Position(Y) y方向位移
Bake Into Pose 勾选表示y方向位移只影响骨骼和蒙皮(外观),并不影响游戏对象的位置,能不能勾选参考loop match
Based Upon 垂直方向上把模型的哪个位置对齐到游戏对象的原点
Original 美术在设置的原点,一般选这个
Root Node Rotation(Generic)将根骨骼作为原点
Center of Mass(Humanoid) 质心作为原点
Feet(Humanoid) 脚作为原点,动画复用可能导致Original不准,此时可以选这项
Offset y方向偏移量
Root Transform Position(XZ) 水平方向位移
Bake Into Pose 勾选表示水平方向位移只影响骨骼和蒙皮(外观),并不影响游戏对象的位置,能不能勾选参考loop match
Based Upon 水平方向上把模型的哪个位置对齐到游戏对象的原点
Original 美术在设置的原点,一般选这个
Root Node Rotation(Generic)将根骨骼作为原点
Center of Mass(Humanoid) 质心作为原点

unity动画,动画,unity
在动画预览界面点击坐标轴图标就可以显示center of mass,这个质心也被称为body transform,它的位置接近hips骨骼
红色箭头为质心在水平面的投影,我们可以把这个投影当作Root Motion的根骨骼节点,这个点被称为root Transform,代码中这样访问它的位置和方向

private Animator animator;
void Start()
{
    animator = GetComponent<Animator>();
    Vector3 bodyTransformPos = animator.bodyPosition;
    Quaternion bodyTransformRotation = animator.bodyRotation;
    Vector3 rootTransformPos = animator.rootPosition;
    Quaternion rootTransformRotation = animator.rootRotation;
}

Humanoid动画中的Root Motion的原理:Unity会计算处一个root transform,Root Motion会把动画文件中描述的root transform的坐标和角度值,转换为相对位移和相对转角,并以此来移动游戏对象

动画切割

unity动画,动画,unity
点击动画的fbx文件,在Animation页签的Clips点击 “+” 新建一个动画片段,移动左右的滑块调整动画范围,或者直接设置动画的开始帧和结束帧,下面的loop mathc表示动画起始帧和结束帧的相似程度,绿色表示相似度高,黄色表示不够相似,红色表示完全不同,如果要切割一个循环动画,需要保持绿色,否则不用管
unity动画,动画,unity
设置好点击下面的Apply,就会生成相应的动画片段

动画曲线(Curves)

我们可以为动画文件添加一个Curve,或者说添加一个属性,把一些额外信息写入到动画中
unity动画,动画,unity
拖动预览窗口中的滑块调整位置,点击添加关键帧后就可以输入数值调整当前帧的数值,也可以点开Curve窗口进行详细调整曲线
unity动画,动画,unity
点击Apply保存,Animation窗口中就会显示刚才添加的曲线属性
unity动画,动画,unity
在动画状态机中新建一个曲线同名float参数,Animator会自动把动画中该曲线的值赋给这个参数,最后在脚本中读取这个参数就行

unity动画,动画,unity
另外我们可以在脚本中直接定义一个动画曲线Animation Curve

public class CurveTest : MonoBehaviour
{
    public AnimationCurve curve;
    private float _time;

    private void Update()
    {
        _time = (_time + Time.deltaTime) % 1;
        Debug.LogError(curve.Evaluate(_time));
    }
}

动画事件(Events)

动画播放到某一帧时触发事件,比如动画播放到某一帧时生成特效
unity动画,动画,unity
在动画的fbx文件中找到Events,拖动下面动画预览的位置就可以调整事件触发时机,点击左侧Add Event按钮添加事件,或者右键添加事件,出现一个蓝色事件标记
unity动画,动画,unity
添加后定义事件调用的方法(Function),支持float,int,string,object4种类型的参数,点击Apply保持

	public void PlayEffect()
    {
        Debug.LogError("test");
    }

脚本中需要定义同名public方法,脚本和Animator挂在同一个物体上,当动画播放到Event时,Animator会发出一个message,并以此调用这个游戏对象上所有组件里的同名方法
unity动画,动画,unity
如果是单独的动画片段文件,打开Animation窗口,点击Add Event按钮添加事件

Animator Layers(动画层级)和Avatar Mask(替身蒙版)

有时候需要把多个动画组合到一起,比如行走的动画和持枪的动画组合到一起就是持枪行走动画
unity动画,动画,unity
在Animator中可以创建多个Layer,分别控制身体的不同部分,通过调整权重来实现不同层级之间动画的组合
多个Layer时,下面的Layer优先级更高
unity动画,动画,unity

Weight 当前动画层级的权重
Mask Avatar Mask 设置身体哪些部分受动画影响,不设置会影响全身,设置后会有个M标记
Blending Override 当前层级的动画覆盖上面层级的动画,比如玩家受伤后,受伤移动的动画替换原本正常移动的动画
Additive 当前层级的动画和上面层级的动画叠加,比如玩家运动起来,把疲劳喘息的动画叠加到原本的动画上。选择Additive该层级的Avatar Mask上的动画curve不能是平的,否则没效果
Sync 勾选后可以在Source Layer中选择当前层级要和哪个层级保持同步,会同步动画状态和它们之间的转换关系,但不会同步BlendTree。当前Layer和它同步Layer使用的动画时长可能不同,默认会对当前Layer的动画时长进行缩放,使其与同步Layer的动画时长一致
Timing 勾选后动画时长由当前Layer和同步Layer共同决定,根据当前Layer的权重计算
IK Pass 使用IK的话需要勾选

unity动画,动画,unity
右键创建Avatar Mask
unity动画,动画,unity
如果是人形动画,则在Humanoid中选择动画影响的部分,绿色表示受影响,红色不受影响,点击旁边空白处可以一次性选中或反选,图中的4个IK表示IK Goal,这里要播放手部动画,因此选择了手臂,手部及两个IK Goal
如果不是人形动画,在Transform中选择Avatar导入骨骼,勾选受影响的骨骼即可

1D混合树

unity动画,动画,unity
创建混合树,双击进入,默认创建1D混合树,也就是通过一个变量来混合
unity动画,动画,unity
点击 “+” 添加三个Root Motion动画
unity动画,动画,unity

Parameter 关联一个浮点型参数
三角形示意图 横轴是Speed的值,纵轴是片段的权重,随着Speed的值增大,第一个片段权重减小,第二个片段权重增加
Threshold 参数Speed为多少时,片段的权重为1
时钟符号 片段播放的速度
人形符号 是否要镜像动画,仅限人形动画使用
Automate Thresholds 取消勾选 Automate Thresholds就可以修改Threshold的值
Compute Thresholds 根据片段的一些属性重新计算Threshold,需要Root Motion动画
Speed 速度的绝对值
Velocity X/Y/Z 分别表示Root Motion在三个方向上的位移速度
Angular Speed(Rad)旋转速度,弧度每秒
Angular Speed(Deg)旋转速度,角度每秒
Adjust Time Scale Homogeneous Speed 自动计算动画播放速度,使多个动画的移动旋转速度相等,idle动画不需要计算,可排除
Reset Time Scale 将所有片段的速度设为1

上图中Compute Thresholds选择Velocity Z,即根据前进后退方向上的速度计算Threshold,动画前进的速度大约是1.745667,后退的速度大约是-1.426688。Adjust Time Scale选择Homogeneous Speed,使得动画速度一致
unity动画,动画,unity
Root Motion的速度不一定是匀速的,这里的1.745667是平均速度
unity动画,动画,unity
在Animation窗口中观察z方向移动的动画曲线,曲线分成多段并不是线性的

注意:Unity动画做混合时,包含非线性插值计算,无法保证参数Speed为1时,动画速度也为1,这时可以调整播放速度来控制移动速度,把播放速度改成 1/1.745667,这样前进速度就是1

unity动画,动画,unity
动画中前进后退的速度是针对原本骨骼的,使用Avatar复用动画后会根据骨骼的缩放值调整速度

public class PlayerMoveTest : MonoBehaviour
{
    private Animator _animator;
    private float _forwardSpeed = 1.745667f;
    private float _backwardSpeed = 1.426688f;
    private float _targetSpeed;
    private float _currentSpeed;
    void Start()
    {
        _animator = GetComponent<Animator>();
        //Root Motion会考虑物体的缩放值,humanScale记录了Avatar对骨骼的缩放
        //我们不希望整个animator的播放速度都受到影响,修改特定动画状态的Multiplier属性
        _animator.SetFloat("Multiplier",  1 / _animator.humanScale);
        Debug.Log("humanScale: " + _animator.humanScale);
    }
    
    void Update()
    {
        Move();
    }

    void Move()
    {
        _currentSpeed = Mathf.Lerp(_currentSpeed, _targetSpeed, 0.5f);
        _animator.SetFloat("Speed", _currentSpeed);
        Debug.Log("velocity.z: " + _animator.velocity.z);
    }

    public void PlayerMove(InputAction.CallbackContext callbackContext)
    {
        Vector2 movement = callbackContext.ReadValue<Vector2>();
        _targetSpeed = movement.y > 0 ? _forwardSpeed * movement.y : _backwardSpeed * movement.y;
    }
}

unity动画,动画,unity
这里使用了Input System

Root Motion与Rigidbody一起使用

引入Root Motion是为了避免实际位移和动画表现位移不同步,Root Motion解决的是同步问题,而不是位移,要控制位移就需要通过脚本的OnAnimatorMove方法,注意:animator的update mode改为animate physics,动画记得Bake into pose

public class PlayerMoveTest : MonoBehaviour
{
    private Animator _animator;
    private Rigidbody _rigidbody;
    private float _forwardSpeed = 1.745667f;
    private float _backwardSpeed = 1.426688f;
    private float _targetSpeed;
    private float _currentSpeed;
    void Start()
    {
        _animator = GetComponent<Animator>();
        _rigidbody = GetComponent<Rigidbody>();
        _animator.SetFloat("Multiplier",  1 / _animator.humanScale);
    }

    private void OnAnimatorMove()
    {
        Move();
    }

    void Move()
    {
        _currentSpeed = Mathf.Lerp(_currentSpeed, _targetSpeed, 0.5f);
        _animator.SetFloat("Speed", _currentSpeed);
        //物理引擎中会修改rigidbody在y方向上的速度
        Vector3 vector3 = new Vector3(_animator.velocity.x, _rigidbody.velocity.y, _animator.velocity.z);
        //用animator从Root Motion动画中提取值,传递给受物理引擎影响的rigidbogy
        _rigidbody.velocity = vector3;
    }

    public void PlayerMove(InputAction.CallbackContext callbackContext)
    {
        Vector2 movement = callbackContext.ReadValue<Vector2>();
        _targetSpeed = movement.y > 0 ? _forwardSpeed * movement.y : _backwardSpeed * movement.y;
    }
}

Root Motion与CharacterController一起使用

CharacterController是一个简单的角色控制组件,如果角色不需要做真实的物理模拟,可以通过CharacterController简单的处理移动和碰撞。CharacterController继承自Collider,本身就是一个多功能碰撞体

Slope Limit 最大爬坡角度
Step Offset 角色能登上的台阶高度
Skin Width 两个碰撞器相互穿透的深度与蒙皮宽度相同。Skin Width越大,抖动越小。Skin Width过低会导致角色卡住。较好的设置是将此值设为半径的 10%,当运动方向和碰撞方向一致时会起作用
Min Move Distance 如果角色试图移动的距离低于指定值,则根本不会移动。这可以用来减少抖动。在大多数情况下,该值应保持为 0
public class PlayerMoveTest : MonoBehaviour
{
    public float RotateSpeed = 1000;

    private Animator _animator;
    private CharacterController _characterController;
    private Vector2 _playerInputVec;
    private bool _isRunning;
    private Vector3 _playerMovement;
    private Transform _playerTransform;
    private float _currentSpeed;
    private float _targetSpeed;
    private float _walkSpeed = 1.5f;
    private float _runSpeed = 4.2f;

    void Start()
    {
        _animator = GetComponent<Animator>();
        _characterController = GetComponent<CharacterController>();
        _playerTransform = transform;
    }

    void Update()
    {
        RotatePlayer();
        MovePlayer();
    }

    public void GetPlayerMoveInput(InputAction.CallbackContext ctx)
    {
        _playerInputVec = ctx.ReadValue<Vector2>();
    }

    /// <summary>
    /// 按下奔跑键
    /// </summary>
    public void GetPlayerRunInput(InputAction.CallbackContext ctx)
    {
        _isRunning = ctx.ReadValue<float>() > 0;
    }

    void RotatePlayer()
    {
        if (_playerInputVec == Vector2.zero)
            return;

        _playerMovement.x = _playerInputVec.x;
        _playerMovement.z = _playerInputVec.y;

        Quaternion targetRotation = Quaternion.LookRotation(_playerMovement, Vector3.up);
        _playerTransform.rotation = Quaternion.RotateTowards(_playerTransform.rotation, targetRotation, RotateSpeed * Time.deltaTime);
    }

    void MovePlayer()
    {
        _targetSpeed = _isRunning ? _runSpeed : _walkSpeed;
        _targetSpeed *= _playerInputVec.magnitude;
        _currentSpeed = Mathf.Lerp(_currentSpeed, _targetSpeed, 0.5f);
        _animator.SetFloat("Speed", _currentSpeed);
    }

    private void OnAnimatorMove()
    {
        //使用Move方法需要手写重力
        //_characterController.Move(_animator.deltaPosition);

        //SimpleMove会默认添加重力
        _characterController.SimpleMove(_animator.velocity);
    }
}

2D Simple Directional

2D混合树根据两个变量进行混合
unity动画,动画,unity
2D简单方向混合,当你的动画代表不同方向时可以使用,如“向前走”、“向后走”、“向左走”和“向右走”
限制:同一个方向上不能有多个动画片段,如“向前走”,“向前跑”
unity动画,动画,unity
Pox X 和 Pos Y 分别表示横向纵向的值,需要在状态机中定义两个变量关联
导入相关的动画,在方形区域内,蓝点表示动画片段,红点表示当前参数所在的位置,注意idle需要归零
选择Velocity XZ,根据动画在XZ方向上的速度计算Threshold,如果数值异常,需要调整下动画的Based Upon
unity动画,动画,unity
修改两个参数的值调整红点位置,蓝色圆圈表示该动画在混合树中所占的权重,圆圈越大权重越大
unity动画,动画,unity
点击某个动画,蓝色区域表示该动画影响的区域
unity动画,动画,unity
点击没有蓝点的地方,就可以看到整个混合树权重的分布状态,蓝色越亮表示能在该区域施加影响的动画越少,颜色越黑表示能在该区域施加影响的动画越多
当原点处有动画片段,最多只能有三个动画片段上有权重,红点会被当作三角形加权重心,反推三个点的权重,它不允许同一个方向上有多个动画片段,因为这样可能找不到合适的三角形
unity动画,动画,unity
把idle动画移开原点位置,Unity会假设原点处有个动画片段,计算权重后,把原点处的权重平均分配给所有动画片段

2D Freeform Cartesian

当运动不代表不同方向时使用效果最佳。例如 “向前走不转弯”、“向前跑不转弯”
unity动画,动画,unity
它使用了梯度带算法,从红色到紫色,p1的影响值递减
unity动画,动画,unity
每个采样点有一个梯形区域显示影响范围

2D Freeform Directional

同一方向上有多个运动,例如“向前走”和“向前跑”
限制:必须包含(0,0)位置处的idle动画,计算量较大
unity动画,动画,unity
它使用极坐标下的梯度带算法
图(a)两个范例点p1和p2与原点距离一样角度不一样,梯度带沿着角度方向平均分布
图(b)两个范例点p1和p2角度一样,与原点距离不一样,影响值与长度成比例
图(c)其他情况两个范例点处于两条阿基米德螺旋线上,梯度带在它们之间均匀分布

参考

Unity动画系统详解文章来源地址https://www.toymoban.com/news/detail-764764.html

到了这里,关于Unity 动画系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity老动画系统Animation

    1、创建老动画系统 给要制作动画的GameObeject添加Animation组件 2、Animation参数 Animation:默认播放的动画 Animations:该动画组件可以控制的所有动画 Play AutoMatically:是否一开始就自动播放默认动画 Animate Physics:动画是否与物理交互 Culling Type:决定什么时候不播放动画     Alwa

    2024年02月06日
    浏览(43)
  • Unity中动画系统的性能优化

    降低骨骼数,减少面片数。 方法: 1.勾选Optimize Game Objects,以剔除骨骼节点对应的Transform节点 2.开启多线程渲染选项 主要影响的函数调用开销,可以在profiler中查看: Animators.Update MeshSkinning.Update Camera.Render 注意: 1.其中Animators.Update函数在骨骼节点优化后,场景内放一百个模

    2024年02月11日
    浏览(40)
  • Unity 3D 人形角色动画(Avatar)||Unity 3D 导航系统||Unity 3D 障碍物

    Mecanim 动画系统 适合人形角色动画的制作,人形骨架是在游戏中普遍采用的一种骨架结构。。 由于人形骨架在骨骼结构上的相似性,用户可以将动画效果从一个人形骨架映射到另一个人形骨架,从而实现动画重定向功能。 除了极少数情况之外,人物模型均具有相同的基本结

    2024年01月16日
    浏览(51)
  • Unity新动画系统之动画状态机Animator Controller

    1、创建动画状态机文件 (1)会在创建动画时自动创建 (2)Create----Animator Controller 2、动画状态机窗口相关 层级:可以在右侧齿轮设置参数大小   3、添加动画 为对象添加动画后会自动添加到状态机中 4、状态切换 动画会在1和2之间不断切换  添加条件 点击转换箭头  在这

    2024年02月05日
    浏览(48)
  • Unity动画系统学习笔记(二)根运动、动画事件与状态机行为

    在学习根运动前需要了解两个名词: 身体变换 :身体变换是角色的质心。它用于 Mecanim 的重定向引擎,并提供最稳定的移位模型。身体方向是相对于 Avatar T 形姿势的下身和上身方向的平均值。身体变换和方向存储在动画剪辑中(使用 Avatar 中设置的肌肉定义)。它们是动画

    2023年04月11日
    浏览(48)
  • 第三十二章 Unity Mecanim动画系统(上)

    在上一章节中,我们介绍了Unity的旧版动画系统,本章节来介绍新版的Mecanim动画系统。新版的Mecanim动画系统实际是对旧版动画系统的升级。新版的Mecanim动画系统仍然是建立在动画片段的基础上的,只不过它给我们提供了一个可视化的窗口来编辑动画片段之间的切换逻辑。接

    2024年02月08日
    浏览(52)
  • 【Unity】Unity使用动画实现场景转换

    哈喽,大家好,我是FEZ98. 由于今天需要实现一个小项目中的场景转换效果,于是使用了Animator简单的实现了这个需求,同时也与大家分享一下今日的收获,如果哪里有错误,还望朋友们指正。 使用动画实现简单的场景转换的思路是向场景中添加一个专门处理转换效果的 Imag

    2024年02月03日
    浏览(46)
  • 【Unity学习】Unity GetCurrentAnimatorStateInfo方法判断动画播放

    #好记忆不如烂笔头# 通过normalizedTime的来判断动画播放是否完成。这里是一个爆炸动画,爆炸结束后,动画消失。配合一个对象池管理器使用。

    2024年02月11日
    浏览(45)
  • unity动画_UI动画案例 c#

    首先我们打开一个项目 在这个初始界面我们需要做一些准备工作 创建基础通用包 在场景上创建一个Cube 选中Cube 在Window下点击Animation拖拽至运行窗口 点击创建 保存后 这个操作是给Cube添加了一个组件 对Cube_添加一个Position动画 设置几个帧位置的坐标(x,y,z)值 点击运行测试 再

    2024年02月03日
    浏览(32)
  • 【unity游戏开发教程】Unity+Umotion Pro+VRoid+Blender制作人物模型和动画,在unity中简单制作二次元人物动画

    大家好!本期教程教大家在unity中制作二次元人物模型和动画 1.下载VRoid Studio 1.搜索VRoid Studio下载即可,或者前往官网VRoid官网 VRoid Studio是由pixiv开发的一款3D人物建模软件,VRoid的主要特征就是通过类似绘画的方式进行人物的建模,使人们更为轻松地创造自己的虚拟人物。

    2024年02月10日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包