Featured image of post 麦田物语开发日记(四)

麦田物语开发日记(四)

完成人物的动画制作与替换效果

人物动画

制作Player动画

  • 思路
  1. 构建一个基础的四方向行动的AnimeController,该控制器包含每个每个方向的站立,走路,跑步的动画,然后基于该baseController构建每个身体部位的动画控制器
  2. 为每个部位的各个动画组件构建对应的动画,并将对应对应到身体各个部位的动画控制器上
  3. 最后在角色移动的代码中增加动画的控制器,并设置切换代码

基础Controller通过Blend Tree来控制多个方向的站立和跑动,因此站立和跑动都应该是一个Blend Tree。在站立中,由于是面向某个方向,因此对应的方向应该是只是个普通的动画;

在移动中,由于涉及走路和跑动的改变,因此需要基础的Blend Tree内部嵌套BlenderTree

image-20230120154300215

在跑动的Blend Tree中,需要嵌套Blend Tree的移动

image-20230120155610944

且每个具体的动动作都需要设置对应的阈值,且方向与input移动的轴的方向相统一(左侧则阈值为负数)

然后使用Animator Override Controller创建每个身体部位对应的控制器,并创建每个身体部位对应的动画,将其挂载到控制器中。

  • 修改人物移动代码

由于有多个animator,因此需要通过循环来让每个控制器都设置我们的输入,让其控制动画进行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
private void SwitchPlayerAnima()
    {
        
        foreach (var anima in _animations)
        {
            anima.SetBool("IsMoving", _isMoving);
            if (_isMoving)
            {
                anima.SetFloat("InputX", _inputX);
                anima.SetFloat("InputY", _inputY);
            }
        }
    }

该部分需要在update中执行,其中_isMoving的赋值人物控制的代码中进行判断的

实现物体举起动画

**拓展:**通过该方法的学习,能够了解如果实现切换衣服和装备等

实现思路:

  1. 首先创建一个用于承接所有被举起物品的Sprite,当物品被选中时,就使该图片出现
  2. 为了实现动画的切换,我们需要设置每套独立的动画控制器
  3. 用一个独立的代码来控制不同种类和不同动画控制器的对应关系
  4. 为了正确找到不同的动画,我们需要为每个待切换的动画设置对应的类别,以便寻找,(因此采用枚举的方式来这是不同的动画种类和承接动画的部位名称;用字典来绑定动画种类和动画控制器
  5. 用事件中心的方式来通知切换动画
  6. 当需要切换动画的时候,通过字典来得到的承接动画的部位类型来找出需要被切换的动画
  • 添加切换状态
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/// <summary>
/// 角色所处的状态
/// </summary>
public enum PartType
{
    None, Carry, Break, Hoe
}

/// <summary>
/// 角色的身体部位
/// </summary>
public enum PartName
{
    Hair, Body, Arm
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/// <summary>
/// 每个动画控制器与角色的状态对应关系
/// </summary>
[System.Serializable]
public class AnimatorType
{
    public PartType partType;
    public PartName partName;

    public AnimatorOverrideController overrideController;

}
  • 独立代码绑定动画到字典,字典的key是身体部位的name,value是当前对应的身体GO
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// DataConllection.cs
public class AnimatorOverride : MonoBehaviour
{
    private Animator[] _animators;
    public SpriteRenderer holdItem;

    [Header("角色动画与当前状态的关系")] public List<AnimatorType> animatorTypes;

    public Dictionary<string, Animator> AnimatorNameDict = new Dictionary<string, Animator>();
    private void Awake()
    {
        _animators = GetComponentsInChildren<Animator>();
        foreach (var anim in _animators)
        {
            AnimatorNameDict.Add(anim.name, anim);
        }
    }
}
  • 添加切换事件到事件中心
1
2
3
4
5
6
7
// EventHandler.cs
public static event Action<ItemDetails, bool> ItemSelectedEvent;

public static void CallItemSelectedEvent(ItemDetails itemDetails, bool isSelected)
{
    ItemSelectedEvent?.Invoke(itemDetails, isSelected);
}
  • 激活事件
1
2
3
4
5
6
// slotUI.cs
/* 当物品被点击的时候,背包中的物品会被举起 */
            if (slotType == SlotType.Bag)
            {
                EventHandler.CallItemSelectedEvent(slotItemDetails, isSelected);
            }
  • 切换动画的具体过程

首先我们需要通过得到当前点击的物品来了解我们应该处于什么状态,然后根据这个状态,来从animatorType中找到我们预先设定好的用来替换当前动画的的controller

而通过字典寻找切换状态的方式是,保证构建的GO和animatorType中定义的替换部位的枚举类型name一致,这就可以通过字典进行查询。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
private void OnItemSelectedEvent(ItemDetails itemDetails, bool isSelected)
{
    /*当点击时,根据当前的物品类型获得人物应该处于的状态*/
    var currentType = itemDetails.itemType switch
    {
            ItemType.Seed => PartType.Carry,
            ItemType.Commodity => PartType.Carry,
            _ => PartType.None

    };
    /* 执行动画的切换 */
    SwitchAnimator(currentType);
}

从我们的可替换列表中找出所有当前状态可替换的动画类型,然后通过该动画类型对应的身体部位GO,替换其正在运行的动画控制器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
private void SwitchAnimator(PartType partType)
    {
        /* 从所有待备选方案中找出需要用来替换的animator */
        foreach (var animatorType in animatorTypes)
        {
            if (animatorType.partType == partType)
            {
                // 此时的字典的key对应的是承接动画的身体部位的name
                AnimatorNameDict[animatorType.partName.ToString()].runtimeAnimatorController 
                    = animatorType.overrideController;
            }
            
        }
    }
  • 优化

保证是isSelected和当前的状态应该是Carry的情况下,才能显示被举起的图片

Built with Hugo
Theme Stack designed by Jimmy