• 【Unity入门计划】Unity2D动画(2)-脚本与混合树实现玩家角色动画过渡


    目录

    1 玩家角色移动伴随的简单动画 

    1.1 行走

    1.2 停留

    1.3 攻击敌人(触发型)

    1.4 受伤(触发型)

    1.5 跳跃

    1.6 下蹲

    2 动画间的过渡

    3 过渡的判断逻辑

    3.1 行走与停留:移动速度

    3.2 受伤&攻击:bool变量

    4 根据实例展示Blend Tree与脚本的协作

    4.1 在状态机中创建BlendTree

    4.2 创建连接:Make Transition

    4.3 创建所需变量并在Transition中加入逻辑

    4.4 搭建每个混合树变量与Motion的关系

    4.5 脚本中加入玩家键盘控制与角色动作的逻辑关系

    1 获取动画组件

    2 定义变量

    3 Update()中定义当前变量与BlendTree变量相关联的逻辑

    4 在脚本中关联bool变量Hit

    5 效果展示

    5 涉及到的Unity中C#用法

    5.1 animator.SetTrigger/SetFloat

    5.2 .Set()

    5.3 .magnitude

    5.4 .Normalize()

    5.5 Mathf.Approximately()

    5.6 new


    学习的教程

    【unity2021入门教程】80-2D游戏开发教程系列-03-RubyAdventure2DRpg官方教程-28-添加Ruby动画控制脚本_哔哩哔哩_bilibili

    本篇博客依旧是建立在RubyAdventure项目上来写的,2D动画内容很多、覆盖面很广,因此以下局的一些动画例子几乎都是这个项目里涉及到的,没办法涵盖完全,以后有机会会补充清楚,这里就先围绕着Ruby角色的动画来谈谈如何实现他的动画过渡。 

    1 玩家角色移动伴随的简单动画 

    第一章就简单谈一谈,对于一个传统的RPG 2D小游戏,玩家操控的主角角色在游戏场景中会需要哪些动画。

    1.1 行走

    如果一个游戏视角是俯视的上帝视角,角色就只有向上、向下、向左、向右四个方向的行走空间,一般如果改变方向,直接瞬间切换。

    还需要注意的一点是,既然行走有四个方向,那就决定了接下来的所有动作,四个方向都应该有不同的表现过程,因此一般动画片段每个状态都会由Left、Right、Up、Down四组组成。

    1.2 停留

    为了让细节感更足,很多游戏会把人物停止不动时喘气动作做出来,就会有起伏感。因此除了行走动画,还会有人物停止不动时的动画效果。

    当然,停留动画对于四个不同的方向都需要有自己的动画片段。

    1.3 攻击敌人(触发型)

    除了基本的移动动画,一般角色还有发射炮弹、飞镖等等攻击时的动画效果,而且是在发射炮弹的瞬间触发的,例如下面这个向右发射的动作演示。

    攻击动画与上述行走、停留动画不同的是,攻击动画属于触发型动画,由于攻击这个动作具有瞬时性,因此在角色脚本中一般以一个bool变量体现。

    同样的,攻击也需要有四个方向不同的动画。

    1.4 受伤(触发型)

    一般RPG会有敌人和陷阱的设置,场景中如果角色触碰到敌人、受到敌人炮弹攻击、误入陷阱等,都会受到伤害,此时也需要一个受到伤害瞬间的动画效果。

    与攻击动画相同,受伤也属于触发型动画,在角色脚本中一般以一个bool变量体现。

    同样的,受伤也需要有四个方向不同的动画。

    1.5 跳跃

    对于一些2D横轴游戏,玩家角色一般会把移动分为左右行走、向上跳跃和下蹲的四种运动状态。

    这里我认为跳跃是一种长久的状态,在角色从离开地板到落向地板的过程中都会维持一个跳跃的姿势。

    1.6 下蹲

    下蹲也是横轴游戏一个常见的动作状态,一般是长按某个键一直处于下蹲动作状态。 

    2 动画间的过渡

    游戏中不可避免会遇到处理动作过渡的情况,这也是Unity中Blend Tree混合树的最大的功能——通过某些参数处理动画的混合。

    下面是我正在学习教程中角色混合树中动作片段之间的Transition关系:

    其中:Moving、Idle、Hit、Launch分别表示移动(行走)、停留、受伤、攻击的动作,可见动作之间的混合情况是非常多的,例如:

    • 走着走着停下来
    • 停下来的时候受到攻击、受伤后停下来
    • 走着走着开始攻击敌人

    我们需要梳理清楚,采用什么变量来进行两个动作间的过渡判断才合适呢?

    3 过渡的判断逻辑

    3.1 行走与停留:移动速度

    这个很好解决,当移动速度大于0时就判断在行走,不移动时判断为停留。

    3.2 受伤&攻击:bool变量

    前面提到了受伤和攻击其实都是一个瞬时的东西,因此其实在判断是否过渡的时候用一个bool变量就可以跟其他动画相互跳转。

    4 根据实例展示Blend Tree与脚本的协作

    4.1 在状态机中创建BlendTree

    创建了4个混合树并按需命名

    4.2 创建连接:Make Transition

    右键Make Transition创建混合树之间的联系。

    4.3 创建所需变量并在Transition中加入逻辑

    • 在Animator窗口左侧的变量区,新建混合所需变量

    由上面讨论的过渡的判断逻辑可知,本实例所需变量有:当前移动速度Speed、攻击和受伤的触发bool变量Hit和Launch。

    同时,由于玩家角色做某种动作的时候还需要一个变量控制他面朝的方向,因此还需要一个Vector2类型的变量,这里分别创建一个Look X和Look Y,二者组成了二维变量(Look X, Look Y)

    • 还需要在混合树的属性栏添加变量控制的逻辑——Hit

    Animator窗口中指向Hit的Transition,还需要调用上面创建的Trigger也就是bool类型的变量Hit,

    点击箭头,进入Transition属性栏,在Conditions中加入Hit变量 

    •  在混合树的属性栏添加变量控制的逻辑——Idle

    状态idle判断的条件是看Speed是否接近于0(由于浮点数没办法全等于0),因此可以设定某个限值,例如0.1,条件给Speed < 0.1即可,

     在混合树的属性栏添加变量控制的逻辑——Run

    Run的判断条件是,Speed > 0.1

    4.4 搭建每个混合树变量与Motion的关系

    这里就是将每个混合树代表的动作合集,与其关联的动作片段,通过变量联系在一起。

    例如停止状态idle,它包含四个不同方向idle的动作效果,因此需要通过(Look X, Look Y)这个二维变量的值来控制。

    其他三个状态同理,都是基于(Look X, Look Y)这个二维变量的值来控制的。

    4.5 脚本中加入玩家键盘控制与角色动作的逻辑关系

    首先,玩家操作的角色和场景中不需要被操作的角色不同,还需要将不同状态的动画与玩家键盘输入的轴值关联在一起,才能实现动作与玩家移动角色同步。

    项目中的玩家角色都会有一个专门控制其移动的脚本,例如实例项目中就有Ruby Controller这个脚本。

    注意:以下出现的脚本代码只会展示当前涉及到的代码段,篇幅原因省略了其余的代码内容~

    1 获取动画组件

    与修改和操作其余任何组件一样,动画对于游戏对象来说也是由Animator组件控制的,因此在进行所有操作之前,需要先获取当前游戏对象的动画组件。

    1. public class RubyController : MonoBehaviour
    2. {
    3. Animator animator;
    4. private void Start()
    5. {
    6. animator = GetComponent();
    7. }
    8. }

    2 定义变量

    这里需要定义2个变量:

    • 一个获取当前角色移动时轴输入值的二维变量move
    • 一个用以储存移动时当前面朝向的二维变量lookDirection
    1. public class RubyController : MonoBehaviour
    2. {
    3. //当前移动使的轴输入
    4. Vector2 move;
    5. //移动时的面朝向,初始朝向右
    6. Vector2 lookDirection = new Vector2(1, 0);
    7. }

    3 Update()中定义当前变量与BlendTree变量相关联的逻辑

    由于玩家操作轴是在Update()中完成的,因此需要在Update()里加入定义的变量move、look与BlendTree中的几个变量的逻辑关系。

    1. public class RubyController : MonoBehaviour
    2. {
    3. void Update()
    4. {
    5. //确定静止时的面朝向
    6. //确定当前的移动的朝向,通过按键确定
    7. move = new Vector2(horizontal, vertical);
    8. //如果当前Ruby正在移动:
    9. //Approximately表示判断浮点数是否近似相等
    10. if (!Mathf.Approximately(move.x, 0.0f) || !Mathf.Approximately(move.y, 0.0f))
    11. {
    12. //赋予移动时当下的朝向
    13. lookDirection.Set(move.x,move.y);
    14. //归一化
    15. //blend tree 中表示方向的参数范围是[-1,1],因此需要归一化
    16. lookDirection.Normalize();
    17. }
    18. //动画
    19. //传递面朝方向
    20. animator.SetFloat("Look X", lookDirection.x);
    21. animator.SetFloat("Look Y", lookDirection.y);
    22. //传递矢量长度,作为速度
    23. animator.SetFloat("Speed", move.magnitude);
    24. }
    25. }

    4 在脚本中关联bool变量Hit

    当前没有涉及到攻击的设定,因此先不考虑角色攻击的效果,仅考虑受伤害时的动画。受伤混合树中定义的bool变量Hit控制玩家是否触发受伤动画。

    脚本中,在减血的方法中添加下列语句

    1. //更改生命值
    2. //amount是游戏中加血/减血的操作
    3. public void ChangeHealth(int amount)
    4. {
    5. if (amount < 0)//if >0加血,则不进入无敌时间
    6. {
    7. //受伤的动画
    8. animator.SetTrigger("Hit");
    9. }
    10. }

    5 效果展示

    5 涉及到的Unity中C#用法

    5.1 animator.SetTrigger/SetFloat

    定义动画组件中的变量值,调用格式:

    animator.SetTrigger(String)

    animator.SetFloat(String, value)

    5.2 .Set()

    给某个Vector变量直接赋值

    vector2.Set(x, y)

    5.3 .magnitude

    vector2.magnitude

    返回一个浮点数,表示当前相对速度大小(保留大小丢失方向信息)

    5.4 .Normalize()

    vector2.Normalize()

    将一个向量归一化操作,变成大小为1仅表示方向的单位向量(保留方向丢失大小信息)

    5.5 Mathf.Approximately()

    Mathf.Approximately(float, float)

    浮点数中近似相等比较,由于浮点数有很多位小数点,如果直接用全等判断“==” 就永远不可能相等,这里相当于给判断多了一个Epsilon的误差值。

    5.6 new

    由于Vector2不能像方法一样使用,一般给一个Vector2类型的变量赋某个二维值的时候需要用到,例如:

    Vector2 sample = new Vector2(1, 0)

  • 相关阅读:
    纯音乐 Heaven & Earth
    GridSearchCV 工具介绍
    2019年Java面试题汇总
    智加科技多项成果亮相ITS World Congress 两款智能重卡计划量产
    Linux | vim的入门手册
    【Jetson】Jetson TX2 ubuntu18.04安装PyTorch
    【20221201】【每日一题】二维数组中的查找
    【Django笔记】5 Django模板
    问 ChatGPT 关于 GPT 的事情:数据准备篇
    [element-ui]el-dialog弹窗table表格多选并标记数据联动
  • 原文地址:https://blog.csdn.net/qq_41835314/article/details/126271280