1、目标
当点击库存栏上可以carry的道具时,首先arms替换为carry状态,同时手上拿着被点击的道具。当再次点击同一个道具时,ams替换为idle状态,手上放下之前的道具。
这个最主要的是要学会使用AnimatorOverrideController类。
2、概念
AnimatorOverrideController类:用于控制动画其重写控制器的接口。
动画器重写控制器的用途是重写某个控制器的动画剪辑,从而为给定化身定制动画。在运行时基于相同的AnimatorController交换Animator.runtimeAnimatorController和AnimatorOverrideController不会重置状态机的当前状态。
(1)一般使用方法
定义变量:AnimatorOverrideController animatorOverrideController;
初始化变量:animatorOverrideController = new AnimatorOverrideController(animator.runtimeAnimatorController);
animator.runtimeAnimatorController = animatorOverrideController;
通过上面的赋值,后续对animatorOverrideController的修改将直接作用于animator.runtimeAnimatorController(运行态的动画控制器)。
运行中更新动画:animatorOverrideController["shot"] = weaponAnimationClip[weaponIndex];
(2)每帧更新多个动画剪辑
使用AnimatorOverrideController.ApplyOverrides方法,它能够将动画器剪辑绑定重新分配的数量减少到每次调用只有一个。
定义新老动画的映射:List<KeyValuePair<AnimationClip, AnimationClip>> clipOverrides;
初始化:animatorOverrideController.GetOverrides(clipOverrides);
运行中更新动画:animatorOverrideController.ApplyOverrides(clipOverrides);
其中ApplyOverrides函数:对该动画器重写控制器应用写列表
GetOverrides函数:获取该动画器重写控制器中当前定义的动画剪辑重写的列表。
3、思路
首先,创建SO_AnimationType类描述所有的动画剪辑。
其次,创建CharacterAttribute类定义想要替换的动画信息。
然后,基于AnimatorOverrideController类,根据CharacterAttribute类定义的动画信息,将Player下所有当前状态的动画替换为CharacterAttribute类定义的动画。
最后,如果是carry状态,给Player下的equippedItem对象赋以点击道具的图像。
4、创建可交互的动画的描述类
在Assets -> Scripts -> Animation下创建SO_AnimationType.cs脚本。
[CreateAssetMenu(fileName = "so_AnimationType", menuName = "Scriptable Objects/Animation/Animation Type")]
public class SO_AnimationType : ScriptableObject
{
public AnimationClip animationClip; // a reference to the actual animation clip 动画剪辑
public AnimationName animationName; // an enum of the animation name like "AnimationName.IdleUp" 动画名称
public CharacterPartAnimator characterPart; // the gameobject name the Animator is on that controls these animation clips e.g. "arms" 动画位置对象
public PartVariantColour partVariantColour; // to enable colour variations on a animation type to be specified e.g. "none", "bronze", "silver", "gold" 动画颜色变化
public PartVariantType partVariantType; // the variant type to specify what variant this animation type refers to e.g. "none", "carry", "hoe", "pickaxe", "axe"..etc 动画类型
}
5、创建一个角色属性结构描述想要交换的动画
在Assets -> Scripts -> Animation 下创建CharacterAttribute.cs脚本,目标动画剪辑的属性结构。
[System.Serializable]
public struct CharacterAttribute
{
public CharacterPartAnimator characterPart; // 示例: CharacterPartAnimator.arms 动画位置对象
public PartVariantColour partVariantColour; // 示例: ParVariantColour.none 动画颜色变化
public PartVariantType partVariantType; // 示例: PartVariantType.carry 动画类型
public CharacterAttribute(CharacterPartAnimator characterPart, PartVariantColour partVariantColour, PartVariantType partVariantType)
{
this.characterPart = characterPart;
this.partVariantColour = partVariantColour;
this.partVariantType = partVariantType;
}
}
6、创建Enum对象
在Assets -> Scripts -> Enums -> Enums.cs 中增加如下信息:
public enum AnimationName
{
idleDown,
idleUp,
idleLeft,
idleRight,
walkUp,
walkDown,
walkLeft,
walkRight,
runUp,
runDown,
runLeft,
runRight,
useToolUp,
useToolDown,
useToolLeft,
useToolRight,
swingToolUp,
swingToolDown,
swingToolLeft,
swingToolRight,
liftToolUp,
liftToolDown,
liftToolLeft,
liftToolRight,
holdToolUp,
holdToolDown,
holdToolLeft,
holdToolRight,
pickUp,
pickDown,
pickLeft,
pickRight,
count
}
public enum CharacterPartAnimator
{
body,
arms,
hair,
tool,
hat,
count
}
public enum PartVariantColour
{
none,
count
}
public enum PartVariantType
{
none,
carry,
hoe,
pickaxe,
axe,
scythe,
wateringCan,
count
}
7、创建动画重写控制器AnimationOverrides
流程:
1)创建2个动画剪辑的映射,第1个是 动画剪辑 到 动画描述类的映射,第2个是 动画表示名 到 动画描述类的映射。
2)通过配置的动画描述信息,分别填充上一步的两个映射表。
3)输入characterAttributesList,需要的动作的动画描述信息,比如partVariantType为carry的动画描述。
4)根据characterPart(比如arm)扫描当前角色下已有的动画剪辑,找到characterPart这个名称的动画剪辑为currentAnimator
5)找到characterPart对应controller下所有的动画剪辑,得到animationsList列表
我们找到了arms的animatorController,
再点击进入控制器的Run分类,
点击RunRight,其对应的动画剪辑为ArmsNoneNoneRunRight = characterPart + partVariantColour + partVariantType + animationName。
6)在animationsList列表中,依次遍历得到动画剪辑animationClip对应的动画描述类so_AnimationType(已有的动画)
7)然后根据characterAttribute(目标动画属性结构)中的信息+ 动画名称(比如RunRight)搜索目标动画剪辑swapSO_AnimationType
8)然后将animationClip 和 swapSO_AnimationType.animationClip的动画剪辑KeyValuePair<AnimationClip, AnimationClip>结构的animsKeyValuePairList中
9)通过aoc.ApplyOverrides让这些动画剪辑替换生效。
代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimationOverrides : MonoBehaviour
{
[SerializeField] private GameObject character = null;
[SerializeField] private SO_AnimationType[] soAnimationTypeArray = null;
private Dictionary<AnimationClip, SO_AnimationType> animationTypeDictionaryByAnimation;
private Dictionary<string, SO_AnimationType> animationTypeDictionaryByCompositeAttributeKey;
private void Start()
{
// Initialise animation type dictionary keyed by animation clip
animationTypeDictionaryByAnimation = new Dictionary<AnimationClip, SO_AnimationType>();
foreach(SO_AnimationType item in soAnimationTypeArr