【Unity基础详解】(7)Unity核心:动画系统

目录

[1 动画系统概述](#1 动画系统概述)

[2 Animation Clip](#2 Animation Clip)

[2.1 在Unity中制作动画](#2.1 在Unity中制作动画)

[2.1.1 录制关键帧](#2.1.1 录制关键帧)

[2.1.2 手动创建关键帧](#2.1.2 手动创建关键帧)

[2.1.3 使用曲线编辑动画](#2.1.3 使用曲线编辑动画)

[2.1.4 编辑关键帧](#2.1.4 编辑关键帧)

[2.1.5 动画循环](#2.1.5 动画循环)

[3 Animator Component](#3 Animator Component)

[4 Animator Controller](#4 Animator Controller)

[4.1 Animator的组成](#4.1 Animator的组成)

[4.1.1 Layers](#4.1.1 Layers)

[4.1.1.1 Layers介绍](#4.1.1.1 Layers介绍)

[4.1.1.2 Layers示例](#4.1.1.2 Layers示例)

[4.1.2 Parameters面板](#4.1.2 Parameters面板)

[4.1.3 网格化布局区域](#4.1.3 网格化布局区域)

[4.2 状态(States)](#4.2 状态(States))

[4.3 状态机过渡(Transitions)](#4.3 状态机过渡(Transitions))

[4.4 混合树(BlendTree)](#4.4 混合树(BlendTree))

[4.4.1 BlendTree简介](#4.4.1 BlendTree简介)

[4.4.2 BlendTree的核心工作原理](#4.4.2 BlendTree的核心工作原理)

[4.4.3 BlendTree示例](#4.4.3 BlendTree示例)

[5 Avatar](#5 Avatar)

[5.1 Avatar简介](#5.1 Avatar简介)

[5.2 设置Avatar](#5.2 设置Avatar)

[5.2.1 导入AB角色](#5.2.1 导入AB角色)

[5.2.2 制作A Avatar](#5.2.2 制作A Avatar)

[5.2.3 把模型B按如上配置一遍。](#5.2.3 把模型B按如上配置一遍。)

[5.2.4 配置复用动画](#5.2.4 配置复用动画)


1 动画系统概述

要在 Unity 中为游戏对象(GameObject)添加动画效果,需要为其添加 Animator 组件(注意是 Animator 而非 Animation)。每个 Animator 组件都会关联一个 Animator Controller(动画控制器),而每个控制器又可以调用多个 Animation Clip(动画片段)。

最基本的单位是 Animation Clip,它相当于动画系统中的最小组成部分。游戏中的角色动作,如跑步、跳跃、攻击或摔倒,都可以用一个完整的 Animation Clip 来表现,相当于一段完整的动画片段。这些动画片段既可以自行创建,也能导入外部资源。最便捷的方式是直接使用 Unity Asset Store 上的现成资源,但更多情况下需要从美术团队获取。通常这些资源会与游戏模型打包在一起,比如 FBX 格式文件中就可能包含人物模型、对应动画片段以及骨骼信息。

此外,还需要通过 Animator Controller(动画控制器)来统一管理所有关联的 Animation Clip。动画控制器负责定义不同动画状态之间的转换规则,每个动画状态都对应一个动画片段。需要注意的是,即使只有一个动画状态,也必须使用动画控制器。

在使用时,只需将创建好的 Animator Controller 文件添加到角色对象的 Animator 组件中即可控制角色动作。

注意区分:

  • **Animator Controller :**项目中的资源文件
  • **Animation Clip :**项目中的资源文件
  • Animator :附加在游戏对象(GameObject)上的组件

2 Animation Clip

Unity的骨骼动画数据分为静态和动态两部分:静态数据存储在SkinedMeshRender 组件中,而动态关键帧数据则保存在AnimationClip中。

动画关键帧数据来源于FBX、OBJ等模型文件。导入后,可以在Animation选项卡中查看动画细节。Unity将动画预览界面分为四个区域,支持播放动画并查看特定帧的信息。

在Unity中创建动画需要使用Animation窗口,可通过菜单栏Window > Animation打开。该窗口支持以下功能:

  • 创建和编辑动画
  • 查看导入的动画

注意:

  • Animation窗口一次只能编辑或查看单个Clip的动画
  • 适合处理单个物体及其子物体的动画
  • 对于更复杂的场景动画(如多对象协同、音频配合等),建议使用Timeline系统

2.1 在Unity中制作动画

在Unity中制作动画一般分为以下几个步骤:

1、打开Animation窗口

2、点击要制作动画的物体,创建新的动画Clip

这时候Animation窗口会有以下两种状态:

**状态1:**该物体上没有动画,可以点击Animation窗口中间的Create按钮创建动画Clip。

**状态2:**该物体上已经有动画,会在窗口中显示一段动画的关键帧。可以通过左上角的菜单切换预览动画、创建新动画。可以点击Create New Clip来创建新的动画Clip。

创建新的动画Clip时,系统会弹出文件对话框用于设置保存路径。保存完成后,原本没有动画的游戏物体会自动添加Animator组件。

Animation Clip本质上是动画数据,可以理解为类似视频文件的资源。Animator组件则相当于播放器,负责控制动画的播放流程以及多个动画片段之间的切换。

3、编辑、预览、修改动画

创建了Animation Clip后,就可以开始制作动画了。Animation窗口有两种模式:录制模式和预览模式

**录制模式:**对物体所做的任何修改(包括移动、旋转、缩放或属性调整)都会在当前时间点自动生成关键帧来记录这些变化。

**预览模式:**所有物体修改都不会自动创建或更新关键帧。如需记录关键帧,需要手动点击添加关键帧按钮进行操作。

2.1.1 录制关键帧

开始录制后,系统将进入录制模式。您可通过以下方式调整时间轴位置:

  1. 直接在时间轴上拖动滑块定位
  2. 在帧数输入框中输入具体数值

系统采用60帧/秒的默认帧率,因此输入30帧即对应0.5秒的时间点。

在录制模式下,无论是移动、旋转或缩放场景中的物体,还是在Inspector面板中调整支持动画的组件属性,Unity都会自动在当前时间点插入关键帧记录这些修改。

完成动画编辑后,再次点击录制按钮即可退出录制模式,防止后续操作被误记录。此时可以看到Animation窗口中左侧列出了所有被记录的属性。如需添加新的动画属性,可点击下方的Add Property按钮进行手动添加。

2.1.2 手动创建关键帧

当未启用录制模式时,对物体的修改不会自动记录到动画Clip中。如需保存这些更改,需手动添加关键帧。在Inspector中修改物体属性时,该属性的背景色会从浅蓝变为浅红,表示已发生修改。此时,右键点击该属性并选择"Add Key"即可添加关键帧,将修改后的数值保存到动画Clip中。

若在当前帧修改了多个属性值,可通过以下两种方式批量保存:

  • Key All Modified:记录所有被修改的属性
  • Key All Animated:记录属性列表中的所有属性(包括数值未发生变化的属性)

也可以通过Animation窗口左侧的Add Keyframe按钮记录关键帧:若选中了特定属性则记录对应属性,未选中时则记录全部属性。

**K(Key All Animated):**与上述功能相同,记录选中属性或全部属性的关键帧。

**Shift+K(Key All Modified):**记录动画属性列表中所有被修改过的属性值作为关键帧。

2.1.3 使用曲线编辑动画

在Animation窗口中,默认以DopeSheet模式显示关键帧点。点击底部的"Curves"按钮可切换至曲线模式,用于调整关键帧间的过渡效果。进入曲线模式后,您可以从左侧属性列表中选择单条或多条曲线进行编辑。

F键可以让曲线充满整个窗口。

2.1.4 编辑关键帧

编辑关键帧时支持多选操作(Curve编辑同理):

  • 按住Shift或Ctrl键单击可选择多个关键帧
  • 直接框选可快速选中范围内的关键帧
  • 配合Shift或Ctrl键框选可增减选择范围

Ripple Edit(波纹编辑)功能:

  • 默认拖动关键帧时,后方关键帧不会联动
  • 按住R键拖动关键帧时,后方关键帧将跟随移动(类似于音视频编辑软件中的波纹编辑效果)
  • 缩放操作同样适用该功能

2.1.5 动画循环

选中要重复播放的动画,右侧选项中,点击Animation,勾选 Loop Time 即可实现动画的重复播放,如果Rotation和Position修改了,也应勾选。

3 Animator Component

Controller:放置动画控制器 Animator Controller

Avatar:放置模型的骨骼

Apply Root Motion:使用根动画,勾选此项会根据动画产生实际的位移

Update Mode:更新模式

  • Normal:表示使用Update进行更新
  • Animate Physics:表示使用FixedUpdate进行更新(一般用在和物体有交互的情况下)

4 Animator Controller

Unity中的动画状态机(Animator Controller)是管理角色或对象动画状态及过渡的核心工具。它能够帮助动画师和开发者构建复杂的动画逻辑,实现如行走、跑步、跳跃、攻击等多种动作间的平滑转换。

Unity提供两种动画控制方式:

Animation组件:

  • 操作简单,直接调用Play("Idle")或CrossFade("Idle")即可播放动画

Animator组件(Unity 5.x后推荐使用):

  • 支持混合动画功能
  • 可实现更流畅的动画过渡效果

创建动画片段时,Unity会自动生成Animator Controller。但为了更好的项目管理,建议手动创建:

  1. 在Project窗口中右键
  2. 选择Create > Animator Controller

4.1 Animator的组成

4.1.1 Layers

4.1.1.1 Layers介绍

在 Animator Controller 中,Layers 视图支持层的创建、查看和编辑功能。通过这种方式,单个动画控制器可以同时运行多个动画层,每个层都拥有独立的状态机。Unity 利用动画层机制来有效管理不同身体部位的复杂状态机。

例如:可以设置下身层控制行走/跳跃动作,而上身层则负责投掷物体/射击动作。如需调整层设置,只需点击窗口右侧的齿轮图标即可。

在每个层上,可以指定遮罩和混合类型。

遮罩功能 (Mask)

通过遮罩可限定动画影响范围。例如,若需让角色上半身执行投掷动作,同时保持下半身正常行走、奔跑或站立,只需在投掷动画所在图层应用遮罩,并指定上半身为作用区域。

混合模式 (Blending)

动画叠加需满足条件:当前图层动画必须包含与前一层相同的属性参数。

混合类型选项:

  • 覆盖(Override):完全替换前一层动画效果

  • 叠加(Additive):在当前层动画基础上叠加前一层效果

  • 同步(Sync):支持跨图层复用相同状态机结构

同步功能(Sync)

同步功能适用于特殊场景,如创建"受伤"状态下的行走/奔跑/跳跃动画变体(区别于"健康"状态)。操作步骤:

  1. 勾选目标图层的Sync选项

  2. 选择要同步的基准图层

  3. 同步后,状态机结构相同但使用不同动画剪辑 (图层侧栏显示"S"标识同步状态)

时间调节 (Timing)

动画控制器可基于权重调整同步层动画时长:

  • 禁用Timing:强制同步层动画时长与原始层一致(自动拉伸)

  • 启用Timing:基于权重平衡两图层动画时长

注意:无论Timing设置如何,控制器都会调整动画时长。未启用时以原始层为基准;启用后采用折中方案。

4.1.1.2 Layers示例

在游戏中,当一个角色需要同时执行多个动作(例如边走路边射击)时,可以使用Layer功能来实现。

具体实现步骤如下:

1.准备两个人物动画:行走和射击

2.在动画状态机中创建两个Layer:

  • Base Layer控制行 走动作
  • 新建的New Layer控制其他动作

3.通过调整层的权重(Weight)控制动画的混合程度:

  • 权重为0时,仅播放基础层动画(行走)。
  • 权重为0.5时,行走和舞蹈动画各占一半。
  • 权重为1时,完全覆盖基础层,仅播放新层动画(舞蹈)。

4.若需仅让特定身体部位播放动画(如下半身行走、上半身跳舞),需创建Avatar Mask:

  1. 右键Project视图,选择 Create → Avatar Mask,命名为UpMask。
  2. 在UpMask中勾选下半身骨骼,屏蔽上半身动画。
  3. 将UpMask赋给New Layer的Mask属性,使该层仅影响下半身。

通过调整层权重和局部遮罩,可灵活组合动画,实现复杂的角色动作效果。

4.1.2 Parameters面板

Parameters 视图用于创建、查看和编辑 Animator Controller 中的参数。这些参数作为变量定义,为状态机提供输入数据。在 Animator Controller 中定义的动画参数可通过脚本访问和修改,从而实现对状态机流程的控制。

您可以使用以下 Animator 类函数从脚本设置参数值:

  • SetFloat
  • SetInteger
  • SetBool
  • SetTrigger
  • ResetTrigger

例如:

animator.SetFloat("参数名",1.5f);

animator.SetInt("参数名",1);

animator.SetBool("参数名",true);

4.1.3 网格化布局区域

布局区域的深灰色网格是 Animator Controller 的核心工作区,用于创建、组织和连接各种状态。

操作方法:

  • 右键点击网格可添加新状态节点
  • 使用鼠标中键或 Alt/Option 键拖动可平移视图
  • 点击选中状态节点进行编辑
  • 拖拽状态节点可调整其在状态机中的位置

4.2 状态(States)

状态机基础概念

状态是动画状态机的基本组成单位,每个状态通常绑定一个动画片段或混合树,用于控制角色动作的播放逻辑。状态之间的过渡连接决定了动画切换的流畅性。

核心节点功能

  • Entry:状态机的起始节点,默认指向初始状态(例如待机状态 Idle)。
  • Exit:终止状态机运行的节点,可用于结束特定动画流程。
  • Any State:特殊节点,允许从任何状态直接触发过渡条件,适用于全局触发的动作(如受击、死亡)。

视图操作快捷键

  • 选中状态后按 F 键,快速聚焦到该状态。

  • A 键自动调整所有状态在 Animator Controller 视图中的布局。

  • 组合键 A + F 实现选中状态与全局视图的快速切换,提升编辑效率。

状态过渡要点

过渡条件需通过参数(如布尔值、浮点数)驱动,确保动画切换自然。混合树可用于处理多方向运动的平滑融合(如行走、奔跑)。

可以通过创建新的空状态,给其添加动画片段。每个动画片段都有以下属性。

|----------------|--------------------------------------------------------------------|
| 属性 | 描述 |
| Motion | 指定给该状态的动画片段或混合树。 |
| Speed | 此状态的默认运动速度。勾选Parameter可以使用脚本中的自定义值修改速度。例如,可以将速度与自定义值相乘,以减速或加速播放速度。 |
| Motion Time | 用于播放此状态的运动的时间。 勾选Parameter可以使用脚本中的自定义值控制运动时间。 |
| Mirror | 此属性仅适用于具有类人动画的状态。启用以镜像此状态的动画。 勾选Parameter可以启用或禁用脚本中的镜像。 |
| Cycle Offset | 添加到运动的状态时间的偏移。此偏移不会影响Motion Time。 勾选Parameter可以指定脚本的周期偏移。 |
| Foot IK | 此属性仅适用于具有类人动画的状态。启用以注重此状态的Foot IK。 |
| Write Defaults | 动画状态是否为未通过其运动设置动画的特性写入默认值。 |
| Transitions | 源自此状态的转换列表。 |

4.3 状态机过渡(Transitions)

动画过渡用于控制状态机中不同动画状态之间的切换或混合效果。它不仅能定义状态转换所需的时间,还可设定触发条件。用户可以指定参数值来控制过渡是否生效,这些参数在Animator Controller中进行配置。

注意:系统同一时间只允许存在一个活跃的过渡效果,但当前活跃的过渡可能会被优先级更高的新过渡打断。

(1)过渡属性

|----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 属性 | 描述 |
| Has Exit Time | Exit Time是一种不依赖参数的特殊过渡。但它依赖状态的标准化时间。选中此选项可在Exit Time指定的具体时间进行过渡。 |
| Settings | 包含详细过渡设置的折叠菜单(如下所示)。 |
| Exit Time | 如果选中 Has Exit Time,此值表示过渡可以生效的确切时间。 该时间以标准化时间表示(例如,退出时间为0.75 表示,在已播放 75% 动画的第一帧上,Exit Time 条件为 true, 在下一帧上,该条件为 false)。 对于循环动画,每个循环都会评估退出时间小于 1 的过渡,因此可使用此选项在每个循环的动画中以适当时机对过渡进行计时。 对 Exit Time 大于 1 的过渡仅评估一次,因此此类过渡可用于在固定循环次数后的特定时间退出。 例如,过渡的退出时间为 3.5 的情况下,在三个半循环后对该过渡评估一次。 |
| Fixed Duration | 选中Fixed Duration复选框,则以秒为单位解读过渡时间。 未选Fixed Duration复选框,则过渡时间解读为源状态的标准化时间的一部分。 |
| Transition Duration | 相对于当前状态持续时间的过渡持续时间,以标准化时间或秒为单位(具体取决于Fixed Duration模式)。 此时间在过渡图中显示为两个蓝色标记之间的部分。 |
| Transition Offset | 过渡到的目标状态的起始播放的时间偏移。 例如,值为 0.5 表示目标状态在其时间轴的 50% 处开始播放。 |
| Interruption Source | 此选项用于控制该过渡可能中断的情况。参考下表中的过渡中断。 |
| Ordered Interruption | 确定当前过渡是否可在不考虑顺序的情况下被其他过渡中断。 选中:已找到有效过渡或当前过渡。 取消选中:已找到有效过渡。 |
| Conditions | 一个过渡可以具有单个条件、多个条件或根本没有条件。 如果过渡没有条件,Unity Editor 只会考虑 Exit Time,并在达到退出时间时发生过渡。 如果过渡有一个或多个条件,则必须满足所有条件才能触发过渡。 一个条件包含: * 一个事件参数(在条件中考虑其值)。 * 条件谓词(需要时填写,例如,浮点数的"小于"或"大于")。 * 一个参数值(需要时填写)。 如果为该过渡选择 Has Exit Time 并有一个或多个条件,请注意 Unity Editor 在 Exit Time 之后考虑条件是否为 true。这样可确保在动画的特定部分中进行过渡。 |

(2)过度中断

利用Interruption Source和Ordered Interruption属性可以精确控制过渡中断的方式。从概念上看,中断过程类似于将这些过渡按顺序排队,最终解析为一个有效的过渡序列,从第一个插入的过渡一直到最后一个过渡。

通过Interruption Source属性进行配置:AnyState中的过渡总是优先排在队列最前面,其他过渡则根据Interruption Source的具体值来排序。

|-------------------------------|--------------------------|
| 值 | 功能 |
| None | 不再添加任何过渡。 |
| Current State | 将当前状态的过渡排队。 |
| Next State | 使下一状态的过渡进行排队。 |
| Current State then Next State | 将当前状态的过渡排序,然后将下一状态的过渡排序。 |
| Next State then Current State | 将下一状态的过渡排队,然后将当前状态的过渡排队。 |

(3)过渡图

要手动调整以上列出的设置,可直接在字段中输入数字或使用过渡图。在操作视图元素时,过渡图会修改上述值。

左边为进入,右边为退出。

(4)条件

在Unity动画状态机中,过渡可以配置为无条件、单条件或多条件触发。

无条件过渡: 依赖Exit Time触发。当动画播放到预设的退出时间时,自动执行过渡,无需额外条件判断。

有条件过渡

需满足所有关联条件才会触发。每个条件包含以下要素:

  • 事件参数:指定监听的参数(如Bool、Float、Trigger等)。
  • 条件谓词:定义比较规则(如浮点数的"大于"或"小于")。
  • 参数值:设置比较的目标值(如Float参数需满足>1.5)。

Exit Time与条件的协同

若同时启用Has Exit Time和条件检测,系统会先在动画到达退出时间后,再检查条件是否全部满足。此机制确保过渡仅在动画的特定阶段生效。

关键设计逻辑

  • 无条件过渡完全由时间控制。
  • 多条件过渡要求逻辑与(AND)关系。
  • Exit Time优先于条件检测,避免动画中途意外跳转。

4.4 混合树(BlendTree)

4.4.1 BlendTree简介

BlendTree是Unity Animator Controller中的一个状态类型,它允许你将多个动画片段(如走路、跑步、跳跃)组合成一个动态混合状态。通过调整参数值(如速度),BlendTree自动计算每个动画片段的权重,实现无缝过渡。这避免了动画的突兀切换,提升了游戏的真实感和流畅度。

4.4.2 BlendTree的核心工作原理

参数驱动:BlendTree由一个或多个参数控制(通常是浮点数),例如角色速度。当参数变化时,Unity计算每个子动画的混合权重。

混合类型:BlendTree支持不同类型:

  • 1D BlendTree:基于单个参数(如速度)进行线性混合。例如,速度v从0到5时,权重从走路动画过渡到跑步动画。
  • 2D BlendTree:基于两个参数(如速度和方向)进行二维混合,适合复杂场景(如角色在8方向移动)。

权重计算:Unity使用插值算法自动计算权重。

4.4.3 BlendTree示例

(1)添加一个人物角色,添加Character Controller组件、Animator组件(添加上Animator Controller)。

(2)在动画状态机中,创建混合树。

(3)使用一个float类型参数Speed来控制混合。

(4)双击进入混合树,给角色添加静止、行走、奔跑三个动画。Blend Type使用默认的1D方式,Threshold阈值分别设置为0、10、25:

(5)给角色添加该脚本

cs 复制代码
public class CharacterMovement : MonoBehaviour
{

    [Header("移动设置")]
    public float walkSpeed; //行走速度
    public float runSpeed; // 奔跑速度
    public float rotationSpeed; //旋转速度

    private Animator animator; //Animator组件
    private CharacterController controller;//CharacterController组件
    private float currentSpeed; //当前速度
    private Vector3 movement;  //位移朝向

    // 动画状态机中速度参数
    private readonly string speedParameter = "Speed";

    void Start()
    {
        // 获取组件
        animator = GetComponent<Animator>();
        controller = GetComponent<CharacterController>();

        // 如果没有CharacterController,自动添加一个
        if (controller == null)
        {
            controller = gameObject.AddComponent<CharacterController>();
        }
    }

    void Update()
    {
        HandleInput();
        HandleMovement();
        UpdateAnimator();
    }

    void HandleInput()
    {
        // 获取WASD输入
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        // 计算移动方向
        Vector3 inputDirection = new Vector3(horizontal, 0, vertical);

        // 判断是否在移动
        bool isMoving = inputDirection.magnitude > 0.1f;

        // 判断是否在奔跑(按下左Shift)
        bool isRunning = Input.GetKey(KeyCode.LeftShift);

        // 计算目标速度
        float targetSpeed = 0f;

        if (isMoving)
        {
            if (isRunning)
            {
                targetSpeed = runSpeed; // 奔跑速度
            }
            else
            {
                targetSpeed = walkSpeed; // 行走速度
            }
        }
        else
        {
            targetSpeed = 0f; // 静止
        }
        // 平滑过渡速度
        currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed, Time.deltaTime * 100f);
        // 计算最终移动向量
        movement = inputDirection * currentSpeed;
        // 只在水平方向有明显输入时旋转(避免微小移动导致抖动)
        if (Mathf.Abs(horizontal) > 0.1f || Mathf.Abs(vertical) > 0.1f)
        {
            Quaternion targetRotation = Quaternion.LookRotation(movement);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);
        }
    }

    void HandleMovement()
    {
        // 应用重力
        if (!controller.isGrounded)
        {
            movement.y -= 9.81f * Time.deltaTime;
        }

        // 移动角色
        controller.Move(movement * Time.deltaTime);
    }
    // 更新动画状态机
    void UpdateAnimator()
    {
        if (animator != null)
        {
            // 根据当前速度设置Animator参数
            float animatorSpeedValue = 0f;

            if (currentSpeed <= 0.1f)
            {
                animatorSpeedValue = 0f; // 静止
            }
            else if (currentSpeed <= walkSpeed * 1.1f)
            {
                animatorSpeedValue = 10f; // 行走
            }
            else
            {
                animatorSpeedValue = 25f; // 奔跑
            }
            //给速度参数赋值
            animator.SetFloat(speedParameter, animatorSpeedValue);
        }
    }

    // 在Inspector中显示当前状态(调试用)
    void OnGUI()
    {
        GUIStyle style = new GUIStyle();
        style.fontSize = 20;
        style.normal.textColor = Color.red;

        string state = "静止";
        if (currentSpeed > 0.1f && currentSpeed <= walkSpeed * 1.1f)
            state = "行走";
        else if (currentSpeed > walkSpeed * 1.1f)
            state = "奔跑";

        GUI.Label(new Rect(10, 10, 200, 30), "状态: " + state + "   " + style);
        GUI.Label(new Rect(10, 40, 200, 30), "速度: " + currentSpeed + "   " + style);
    }
}

脚本介绍:

组件要求

角色需要有Animator组件

脚本会自动添加Character Controller组件用于移动

参数设置

walkSpeed: 行走速度(对应阈值10)

runSpeed: 奔跑速度(对应阈值25)

rotationSpeed: 角色旋转速度

控制方式

WASD: 移动方向

左Shift + WASD: 奔跑

松开所有键: 静止

动画状态对应

Speed = 0 → 静止动画

Speed = 10 → 行走动画

Speed = 25 → 奔跑动画

将脚本挂载到角色上后,确保Animator Controller中的Speed参数名称与脚本中的变量一致(默认为"Speed")。

5 Avatar

5.1 Avatar简介

Unity的Avatar系统和动画重定向技术能让开发者将同一套动画应用于不同的人物模型。该技术的关键在于骨架匹配度------不同模型必须具有相似或相同的骨骼结构。通过Avatar定义角色的骨骼体系,Unity就能实现动画在不同角色间的无缝转换。

Avatar实质上是Unity内置的骨骼映射系统。创建Avatar的过程就是将角色骨骼与Unity标准骨骼体系进行对应匹配。当多个模型都完成这种映射后,角色A的动画就能直接应用到角色B身上,这就是动画重定向原理。在此过程中,每个角色只需维护自己的Avatar映射关系即可。

5.2 设置Avatar

在Unity中设置Avatar的步骤如下:

确保人物模型有骨架绑定和蒙皮:在3D建模软件中创建自定义的人形网格,并进行骨架绑定(Rigging)和蒙皮(Skinning)。

确保配置Skinned Mesh Renderer:选择模型并检查Skinned Mesh Renderer组件,配置网格和材质,并设置骨骼。

5.2.1 导入AB角色

https://www.mixamo.com/中,下载一套人物模型和配套动画作为角色A,在Unity商城中下载一个角色,作为角色B。

mixamo模型导入后,命名为A,显示材质丢失,需要在检视面板导出贴图,导入至创建好的文件夹中,整个角色贴图就会正常。同样的方式再将材质也重新导出即可。

如果角色是半透明状态,则需要选中所有的材质,再检视面板,将渲染模式改为不透明:Opaque即可。

给A添加Animator组件,创建Animator Controller,添加至A,并将一个动画导入该动画状态机中,运行游戏,则A自动播放该动画。

5.2.2 制作A Avatar

(1)选中A的模型资源,在检视面板,找到Rig,选择Humanoid。

None:表示不需要播放任何动画。

Legacy:历史遗留旧版动画,不用管。

Generic:表示通用动画,不是人形,例如飞鸟猛兽就可以用这个动画

Humanoid:表示人形动画。

Create From This model:从这个模型本身创建Avatar,根据模型A的骨骼建立一个与Unity肌肉对应的关系。

Copy From Other Avatar:选择另一个已经配置好的Avatar。

Skin Weights:表示每一个模型的蒙皮或者说Mesh上的节点可以被几个骨骼影响,这里默认就好。

Optimize Game Objects:优化游戏对象,当使用了Avatar之后,播放动画就与模型文件上的骨骼无关了,动画就会从Avatar骨骼上读取信息,选中的话,模型上的骨骼就会被删除掉,这里默认就好。

(2)点击Apply之后就会生成一个Avatar,点击Configure Avatar就可以配置骨骼。

Mapping:骨骼映射

Muscles & Settings:肌肉设置

虚线表示并非必选包含的骨骼,实线表示这块必选包含的骨骼。Unity中Avatar系统对骨骼和肌肉做对应关系时,至少需要人体模型上有十五块符合排列规则的骨骼

(3)导入Unity创建Avatar:首先,需要为两个模型分别创建自己的Avatar。这可以在模型文件的Inspector面板中的Rig选项卡完成。设置Animation Type为Humanoid,然后点击Configure按钮进入Avatar配置界面,确保骨骼映射正确。

Mapping功能

Clear:清除所有

Automap:可以自动的进行匹配

Save:会把这里匹配方式保存在一种叫human template的模板当中

Load:就是读取我们在其他地方保存模板

Pose功能

Reset:会将模型摆回初始状态

Sample Bind-Pose:会将模型摆回绑定时的初始状态

Enforce T-Pose:会将模型强制摆成T pose

Muscles & Settings

这里可以看到模型在肌肉拉升到极限是一种什么样的状态,如果对拉伸的程度不满意的话,可以对每一个肌肉做出限制。

5.2.3 把模型B按如上配置一遍。

5.2.4 配置复用动画

选择需要复用的动画,修改为Copy From Other Avatar,选择A的Avatar导入至Source,点击Apply。然后将A的动画状态机拖入角色B的Animator即可。

相关推荐
我的golang之路果然有问题3 小时前
mac M系列芯片 unity 安装会遇到的错误以及解决
经验分享·学习·macos·unity·游戏引擎
Hody911 天前
【XR开发系列】2025 年 XR 开发入门,我该选择 Unity 还是 Unreal Engine?
unity·xr·虚幻
DvLee10241 天前
UnityGLTF 材质创建与赋值流程
unity·材质
HahaGiver6661 天前
从0到1做一个“字母拼词”Unity小游戏(含源码/GIF)- 字母拼词正确错误判断
unity·游戏引擎·游戏程序
一个小狼娃2 天前
Android集成Unity避坑指南
android·游戏·unity
极客柒2 天前
Unity 协程GC优化记录
java·unity·游戏引擎
黄思搏2 天前
Unity SpriteRenderer 进度条 Shader 实现
unity·游戏引擎
猫屋小鱼丸2 天前
手把手教你在unity中实现一个视觉小说系统(一)
unity
国服第二切图仔2 天前
Rust开发实战之简单游戏开发(piston游戏引擎)
开发语言·rust·游戏引擎