目录
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角色的动画来谈谈如何实现他的动画过渡。
第一章就简单谈一谈,对于一个传统的RPG 2D小游戏,玩家操控的主角角色在游戏场景中会需要哪些动画。
如果一个游戏视角是俯视的上帝视角,角色就只有向上、向下、向左、向右四个方向的行走空间,一般如果改变方向,直接瞬间切换。
还需要注意的一点是,既然行走有四个方向,那就决定了接下来的所有动作,四个方向都应该有不同的表现过程,因此一般动画片段每个状态都会由Left、Right、Up、Down四组组成。
为了让细节感更足,很多游戏会把人物停止不动时喘气动作做出来,就会有起伏感。因此除了行走动画,还会有人物停止不动时的动画效果。
当然,停留动画对于四个不同的方向都需要有自己的动画片段。
除了基本的移动动画,一般角色还有发射炮弹、飞镖等等攻击时的动画效果,而且是在发射炮弹的瞬间触发的,例如下面这个向右发射的动作演示。
攻击动画与上述行走、停留动画不同的是,攻击动画属于触发型动画,由于攻击这个动作具有瞬时性,因此在角色脚本中一般以一个bool变量体现。
同样的,攻击也需要有四个方向不同的动画。
一般RPG会有敌人和陷阱的设置,场景中如果角色触碰到敌人、受到敌人炮弹攻击、误入陷阱等,都会受到伤害,此时也需要一个受到伤害瞬间的动画效果。
与攻击动画相同,受伤也属于触发型动画,在角色脚本中一般以一个bool变量体现。
同样的,受伤也需要有四个方向不同的动画。
对于一些2D横轴游戏,玩家角色一般会把移动分为左右行走、向上跳跃和下蹲的四种运动状态。
这里我认为跳跃是一种长久的状态,在角色从离开地板到落向地板的过程中都会维持一个跳跃的姿势。
下蹲也是横轴游戏一个常见的动作状态,一般是长按某个键一直处于下蹲动作状态。
游戏中不可避免会遇到处理动作过渡的情况,这也是Unity中Blend Tree混合树的最大的功能——通过某些参数处理动画的混合。
下面是我正在学习教程中角色混合树中动作片段之间的Transition关系:
其中:Moving、Idle、Hit、Launch分别表示移动(行走)、停留、受伤、攻击的动作,可见动作之间的混合情况是非常多的,例如:
我们需要梳理清楚,采用什么变量来进行两个动作间的过渡判断才合适呢?
这个很好解决,当移动速度大于0时就判断在行走,不移动时判断为停留。
前面提到了受伤和攻击其实都是一个瞬时的东西,因此其实在判断是否过渡的时候用一个bool变量就可以跟其他动画相互跳转。
创建了4个混合树并按需命名
右键Make Transition创建混合树之间的联系。
由上面讨论的过渡的判断逻辑可知,本实例所需变量有:当前移动速度Speed、攻击和受伤的触发bool变量Hit和Launch。
同时,由于玩家角色做某种动作的时候还需要一个变量控制他面朝的方向,因此还需要一个Vector2类型的变量,这里分别创建一个Look X和Look Y,二者组成了二维变量(Look X, Look Y)
Animator窗口中指向Hit的Transition,还需要调用上面创建的Trigger也就是bool类型的变量Hit,
点击箭头,进入Transition属性栏,在Conditions中加入Hit变量
状态idle判断的条件是看Speed是否接近于0(由于浮点数没办法全等于0),因此可以设定某个限值,例如0.1,条件给Speed < 0.1即可,
在混合树的属性栏添加变量控制的逻辑——Run
Run的判断条件是,Speed > 0.1
这里就是将每个混合树代表的动作合集,与其关联的动作片段,通过变量联系在一起。
例如停止状态idle,它包含四个不同方向idle的动作效果,因此需要通过(Look X, Look Y)这个二维变量的值来控制。
其他三个状态同理,都是基于(Look X, Look Y)这个二维变量的值来控制的。
首先,玩家操作的角色和场景中不需要被操作的角色不同,还需要将不同状态的动画与玩家键盘输入的轴值关联在一起,才能实现动作与玩家移动角色同步。
项目中的玩家角色都会有一个专门控制其移动的脚本,例如实例项目中就有Ruby Controller这个脚本。
注意:以下出现的脚本代码只会展示当前涉及到的代码段,篇幅原因省略了其余的代码内容~
与修改和操作其余任何组件一样,动画对于游戏对象来说也是由Animator组件控制的,因此在进行所有操作之前,需要先获取当前游戏对象的动画组件。
public class RubyController : MonoBehaviour
{
Animator animator;
private void Start()
{
animator = GetComponent();
}
}
这里需要定义2个变量:
public class RubyController : MonoBehaviour
{
//当前移动使的轴输入
Vector2 move;
//移动时的面朝向,初始朝向右
Vector2 lookDirection = new Vector2(1, 0);
}
由于玩家操作轴是在Update()中完成的,因此需要在Update()里加入定义的变量move、look与BlendTree中的几个变量的逻辑关系。
public class RubyController : MonoBehaviour
{
void Update()
{
//确定静止时的面朝向
//确定当前的移动的朝向,通过按键确定
move = new Vector2(horizontal, vertical);
//如果当前Ruby正在移动:
//Approximately表示判断浮点数是否近似相等
if (!Mathf.Approximately(move.x, 0.0f) || !Mathf.Approximately(move.y, 0.0f))
{
//赋予移动时当下的朝向
lookDirection.Set(move.x,move.y);
//归一化
//blend tree 中表示方向的参数范围是[-1,1],因此需要归一化
lookDirection.Normalize();
}
//动画
//传递面朝方向
animator.SetFloat("Look X", lookDirection.x);
animator.SetFloat("Look Y", lookDirection.y);
//传递矢量长度,作为速度
animator.SetFloat("Speed", move.magnitude);
}
}
当前没有涉及到攻击的设定,因此先不考虑角色攻击的效果,仅考虑受伤害时的动画。受伤混合树中定义的bool变量Hit控制玩家是否触发受伤动画。
脚本中,在减血的方法中添加下列语句
//更改生命值
//amount是游戏中加血/减血的操作
public void ChangeHealth(int amount)
{
if (amount < 0)//if >0加血,则不进入无敌时间
{
//受伤的动画
animator.SetTrigger("Hit");
}
}
定义动画组件中的变量值,调用格式:
animator.SetTrigger(String)
animator.SetFloat(String, value)
给某个Vector变量直接赋值
vector2.Set(x, y)
vector2.magnitude
返回一个浮点数,表示当前相对速度大小(保留大小丢失方向信息)
vector2.Normalize()
将一个向量归一化操作,变成大小为1仅表示方向的单位向量(保留方向丢失大小信息)
Mathf.Approximately(float, float)
浮点数中近似相等比较,由于浮点数有很多位小数点,如果直接用全等判断“==” 就永远不可能相等,这里相当于给判断多了一个Epsilon的误差值。
由于Vector2不能像方法一样使用,一般给一个Vector2类型的变量赋某个二维值的时候需要用到,例如:
Vector2 sample = new Vector2(1, 0)