3 核心
约 4418 字大约 15 分钟
2025-05-31
制作动画时:记录在固定时间点对象挂载的脚本的变量变化 播放动画时:将制作动画时记录的数据在固定时间点进行改变,产生动画效果
动画中的帧: 假设某个动画的帧率为60帧每秒,意味着该动画1秒钟最多会有60次改变机会 每一帧的间隔时间是1s/60=16.67毫秒 也就是说我们最快可以每16.67毫秒改变一次对象状态
关键帧: 动画在时间轴上的某一个时间节点上处于的状态
动画的层级 动画的层级并不是决定动画覆盖的要素 权重是动画覆盖的要素,权重高的层级的动画会覆盖权重低的层级的动画
动画事件
可以在动画播放的某一节点设置事件,当动画播放到这一节点时就会启动这一事件,可以在这个事件上添加调用函数
有限状态机
有限状态机(Finite-state machine,FSM) 又称有限状态自动机,简称状态机 是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型
有限:表示是有限度的不是无限的 状态:指所拥有的所有状态
Animation Controller
unity中的动画状态机
网格化布局区域: 主要用于编辑状态之前的切换关系
- 窗口中的每一个矩形表示一个状态
- 窗口中的每一个箭头表示一个切换条件 默认三大矩形: 绿色Entry矩形:进入状态机流程 红色Exit矩形:退出状态机流程 AnyState:任意状态,代表状态机中的任意状态 橙色矩形:一开始的默认状态动画,和Entry相连表示一开始播放的动画 灰色矩形:自己添加的某一种动作状态
条件 float,int,bool值的条件都是设置为某个值或者满足大于小于等条件可以切换到指定状态 trigger是将其设置为true后它会又变回false,常用于进入到某个状态执行完毕后再回来本状态的情况
动画系统
Unity中有两套动画系统 新:Mecanim动画系统一主要用Animator组件控制动画 老:Animation动画系统一主要用Animation组件控制动画(Unity4之前的版本可能会用到)
目前我们为对象在Animation窗口创建的动画都会被新动画系统支配 有特殊需求或者针对一些简易动画,才会使用老动画系统
旧动画系统
[!important] Title 在创建动画之前为对象添加Animation组件之后再制作动画,这时制作出的动画和之前的动画格式是有区别的
Animation组件函数
函数 | 作用 |
---|---|
Play | 播放动画,传入动画名字符串 |
CrossFade | 淡入播放动画,传入的也是动画名字符串。在播放时产生过渡效果(与之前物体的状态之间切换产生的效果) |
PlayQueued | 如果当前有动画在播放那么此函数播放的动画会等待上一个动画播放完再播放,不会产生过渡效果 |
CrossFadeQueued | 能够产生过渡效果 |
Stop | 停止所有动画 |
IsPlaying | 判断某个动画是否在播放 |
AddMixingTransform | 设置混组相关骨骼信息 |
属性 | 作用 |
---|---|
wrapMode | 播放模式 |
layer | 动画的层级 |
weight | 动画权重 |
blendMode | 混合模式,是叠加还是混合 |
新动画系统
Animator组件
函数 | 作用 |
---|---|
SetFloat/Integer/Bool | 参数一:条件名,参数二:条件 |
SetTrigger | 参数条件名 |
GetFloat/Integer/Bool | 获取条件名对应的值 |
Play | 直接切换状态 |
模型
unity支持很多模型格式 官方建议是将模型在建模软件中导出为FBX格式后再使用 使用FBX模型格式的优势
- 减少不必要数据,提升导入效率
- 不需要再每台计算机上安装建模软件的授权副本
- 对unity版本无要求,使用原始3D模型格式可能会因为版本不同导致错误或意外
Rig操纵页签
如何将骨骼映射到导入模型中的网格,以便能够将其动画化 对于人形角色模型,需要分配或创建Avatar(替身信息) 对于非人形角色模型,需要在骨骼中确定根骨骼
Rig页签主要是设置骨骼和替身系统相关信息的,设置了他们,动画才能正常的播放
Avatar化身系统
3D动画的本质也是骨骼动画 为制作好的模型绑定骨骼制作动画是模型动画的制作流程
对于人来说 人的整体结构都是一致的 另一个人能做的动作理论上来说我们是完全可以模仿出来的 而化身系统的本质,就是动作的模仿(复用) 我们可以把一个标准人形动作通过化身系统复用到其它人形模型上 只要保证他们的关节点对应关系是一致的
设置人形模型在化身系统中关节的对应关系
动画分层
3D游戏中我们常常会面对这样的需求 人物站立时会有开枪动作 人物跑动时会有开枪动作 人物蹲下时会有开枪动作 从表现上来看光是开枪动作可能就有3种 如果做3种开枪动作费时又费资源
可以让开枪动画只影响上半身 下半身根据实际情况播放站立,跑动,蹲下动作 通过上下半身播放不同的动画就可以达到动画的组合播放
动画分层的主要就是达到这两个目的
- 两套不同层动作的切换
- 结合动画遮罩让两个动画叠加在一起播放 提升动画多样性,节约资源
反向动力学IK
在骨骼动画中,构建骨骼的方法被称为正向动力学 它的表现形式是,子骨骼(关节)的位置根据父骨骼(关节)的旋转而改变 用我们人体举例子 当我们抬起手臂时,是肩部关节带动的整个手臂的运动,用父子骨骼理解的话就是父带动了子
而Ik全称是InverseKinematics,翻译过来的意思就是反向动力学的意思 它和正向动力学恰恰相反 它的表现形式是,子骨骼(关节)末端的位置改变会带动自己以及自己的父骨骼(关节)旋转 用我们人体举例子 当我们拿起一个杯子的时候是用手掌去拿,以杯子为参照物,我们移动杯子的位置,手臂会随着杯子一起移动 用父子骨骼理解的话就是子带动了父
换装
相同psb文件换装
在骨骼编辑面板中将不同的装备命名不同的label,并将同类型的装备分到同一个类型组中 要换装时在类别中选择不同的label即可
SpriteLibrary一精灵资料库,确定类别分组信息 SpriteResolver一精灵解算器,用于确定部位类别和使用的图片 SpriteLibraryAsset一精灵资料库资源,具体记录类别分组信息的文件 SpriteResolver
函数 | 作用 |
---|---|
GetCategory | 获取当前部件默认的类型名 |
SetCategoryAndLabel | 设置当前想要切换的类别信息 |
不同psb文件换装
不同文件如果要换装骨骼信息必须统一,需要使用骨骼编辑中的复制粘贴
手动添加关键组件和数据文件
- 首先创建spriteLibraryAsset数据文件
- 为跟对象添加spriteLibrary并关联数据文件
- 为换装部位关联SpriteResolver
动画
动画分层和遮罩
动画分层后,如果几个层的动画都符合运行条件那么就看每层的权重以及混合方式,权重越高的层级播放的动画特性越多
代码设置某层动画的权重
animator.SetLayerWeight(animator。GetLayerIndex(层级名),权重)
动画混合
高级版的动画过渡
1d混合和2d混合 1D混合是用一个参数控制动画的混合,之所以叫1D是因为一个参数可以看做是1维线性的 2D混合可以简单理解是用两个参数控制动画的混合,之所以叫2D是因为两个参数可以看做是2维平面xy轴的感觉
2d混合的分类
- 2D Simple Directional2D简单定向模式运动表示不同方向时使用比如向前、后、左、右是
- 2D Freeform Directional2D自由形式定向模式 同上 运动表示不同方向时使用 但是可以在同一方向上有多个运动比如向前跑和走
- 2D Freeform Cartesian2D自由形式笛卡尔坐标模式 运动不表示不同方向时使用 比如向前走不拐弯 向前跑不拐弯,向前走右转向前跑右转
- Direct直接模式自由控制每个节点权重,一般做表情动作等
子状态机
子状态机顾名思义就是在状态机里还有一个状态机 它的主要作用就是某一个状态是由多个动作状态组合而成的复杂状态 比如某一个技能它是由3段动作组合而成的,跳起,攻击,落下 当我们释放这个技能时会连续播放这3个动作 那么我们完全可以把他们放到一个子状态机中
Ik
3d IK和2d Ik一样 在动画层级中必须开启ik通道
继承MonoBehavior的类中 Unity定义了一个Ik回调函数:OnAnimatorIK 我们可以在该函数中调用Unity提供的Ik相关API来控制IK
Animator中的ik相关api
函数 | 作用 |
---|---|
SetLookAtWeight | 设置头部IK权重weight:LookAt全局权重01<br>bodyWeight:LookAt时身体的权重o1 headWeight:LookAt时头部的权重e1<br>eyesWeight:LookAt时眼镜的权重e1 clampWeight:0表示角色运动时不受限制,1表示角色完全固定无法执行LookAt,0.5表示只能够移动范围的一半 |
SetLookAtPosition | 设置头部IK看向位置 |
SetIKPositionWeight | 设置Ik位置权重 |
SetIkRotationWeight | 设置Ik旋转权重 |
SetIKPosition | 设置IK对应的位置 |
SetIKRotation | 设置IK对应的角度 |
AvatarIKGoal | 枚举四肢末端IK枚举 |
我们可以简单理解这两个函数是两个和动画相关的特殊生命周期函数 他们在update之后LateUpdate之前调用 他们会在每帧的状态机和动画处理完后调用 OnAnimatorIK在onAnimatorMove之前调用 OnAnimatorIk中主要处理IK运动相关逻辑 OnAnimatorMove主要处理动画移动以修改根运动的回调逻辑 他们存在的目的只是多了一个调用时机,当每帧的动画和状态机逻辑处理完后再调用
动画目标匹配
动画目标匹配主要指的是 当游戏中角色要以某种动作移动,该动作播放完毕后,人物的手或者脚必须落在某一个地方 比如:角色需要跳过踏脚石或者跳跃并抓住房梁
Unity中的Animator提供了对应的函数来完成该功能 使用步骤是
- 找到动作关键点位置信息(比如起跳点,落地点,简单理解就是真正可能产生位移的动画表现部分)
- 将关键信息传入MatchTargetAPI中 调用匹配动画的时机有一些限制
- 必须保证动画已经切换到了自标动画上
- 必须保证调用时动画并不是处于过度阶段而真正在播放目标动画 如果发现匹配不正确,往往都是这两个原因造成的
- 需要开启Apply Root Motion
参数一:目标位置 参数二:目标角度 参数三:匹配的骨骼位置 参数四:位置角度权重 参数五:开始位移动作的百分比 参数六:结束位移动作的百分比
状态机脚本
状态机行为脚本时一类特殊的脚本,继承指定的基类 它主要用于关联到状态机中的状态矩形上 我们可以按照一定规则编写脚本 当进入、退出、保持在某一个特定状态时我们可以进行一些逻辑处理 简单解释就是为Animator Controller状态机窗口中的某一个状态添加一个脚本 利用这个脚本我们可以做一些特殊功能 比如
- 进入或退出某一状态时播放声音
- 仅在某些状态下检测一些逻辑,比如是否接触地面等等
- 激活和控制某些状态相关的特效
脚本要继承StateMachineBehaviour基类
实现其中的特定方法进行状态行为监听
函数 | 作用 |
---|---|
OnStateEnter | 进入状态时,第一个update中调用 |
OnStateExit | 退出状态时,最后一个update中调用 |
OnStateIK | OnAnimatorIk后调用 |
OnStateMove | OnAnimatorMove后调用 |
OnStateUpdate | 除第一帧和最后一帧,每个Update上调用 |
OnStateMachineEnter | 子状态机进入时调用,第一个update中调用 |
OnStateMachineExit | 子状态机退出时调用,最后一个Update中调用 |
角色控制器
Character Controller 角色控制器是让角色可以受制于碰撞,但是不会被刚体所牵制 如果我们对角色使用刚体判断碰撞,可能会出现一些奇怪的表现 比如:
- 在斜坡上往下滑动
- 不加约束的情况碰撞可能让自己被撞飞 等等 而角色控制器会让角色表现的更加稳定 Unity提供了角色控制器脚本专门用于控制角色
注意: 添加角色控制器后,不用再添加刚体 能检测碰撞函数 能检测触发器函数 能被射线检测
函数 | 作用 |
---|---|
SimpleMove | 不受重力影响的移动 |
Move | 受重力影响的移动(两个移动都要使用物体自身的朝向而不是世界的坐标的朝向) |
isGrounded | 是否接触地面 |
OnControllerColliderHit | 碰撞到别的碰撞器 |
OnCollisionEnter | 碰撞器触发,自身不能检测到别的物体,但别的物体可以通过这个函数检测 |
OnTriggerEnter | 触发器触发 |
导航寻路系统
让角色能够从一个起点准确的到达另一个终点 并且能够自动避开两个点之间的障碍物选择最近最合理的路径进行前往
Unity中的导航寻路系统的本质 就是在A星寻路算法的基础上进行了拓展和优化
组件
- 导航网格(NavMesh)的生成一严要想角色能够在场景中自动寻路产生行进路径,那么必须得先有场景地形数据,导航网格生成就是生成用于寻路的地形数据
- 导航网格寻路组件(NavMeshAgent)一寻路组件就是帮助我们根据地形数据计算路径让角色动起来的关键
- 导航网格连接组件MeshLink当批形中邮有新层相鱼色能从个平面跳向另一个平面,网格连接组件时关键
- 导航网格动态障碍物组件(NavMesh Obstacle)一地形中可能存在的可以移动或动态销毁的障碍物需要挂载的组件
页签
- object页签一设置参与寻路烘焙的对象
- Bake页签一导航数据烘焙页签,设置寻路网格具体信息
- Areas页签一导航地区页签,设置对象的寻路消耗
- Agents页签一代理页签,设置寻路代理信息
导航网格寻路组件
寻路组件的本质就是根据烘焙出的寻路网格信息 通过基于A星寻路的算法计算出行进路径让我们在该路径上移动起来 Nav Mesh Agent (导航网格代理)
变量 | 作用 |
---|---|
isStopped | 停止寻路 |
speed | 速度 |
acceleration | 加速度 |
angularSpeed | 旋转速度 |
hasPath | 是否有路径 |
destination | 代理目标点 |
path | 当前路径 |
pathPending | 路径是否在计算中 |
pathStatus | 路径状态 |
updatePosition | 是否更新位置 |
updateRotation | 是否更新角度 |
velocity | 代理速度 |
函数 | 作用 |
---|---|
SetDestination | 设置目标点 |
CalculatePath | 计算生成路径 |
SetPath | 设置新路径 |
ResetPath | 清除路径 |
Warp | 调整指定位置 |
网格外连接
我们在烘焙地形数据的时候 可以生成网格外连接 但是它是满足条件的都会生成 而且是要在编辑模式下生成
如果我们只希望两个未连接的平面之间只有有限条连接路径可以跳跃过去 并目运行时可以动态添加 就可以使用网格外连接组件 达到“指哪打哪”的效果
导航动态障碍物
- 为需要进行动态阻挡的对象添加NavMeshobstacle组件
- 设置相关参数
- 代码逻辑控制其的移动或者显隐
贡献者
版权所有
版权归属:PinkDopeyBug