一、状态机的建立
大部分情况下,当游戏内玩家没有任何操作时,肯定都是站立不动的状态,然而事实上,玩家不可能和木头人一样完全静止,这样显得非常不真实,给玩家带来的体验当然也会很差,所以基本上所有有角色的游戏(纯2D游戏除外),角色的站立状态也都是有专门的动画的。
当然了,站立状态大部分情况下都会是默认状态,所以先设置一个站立的状态,并作为初始状态如下:
点击一下状态,添加动画并改名
- Motion:选择播放的动画
- Speed:动画播放速度(别忘了动画是否循环播放可以点击动画进行设置)
- Mirror:是否反转动画
- Cycle Offset:动画偏移
- Foot IK:足部修正,防止在奇怪地形上走路足部不自然
这样当进入游戏时,角色就会开始自动播放站立动画了
二、动画过渡
之后当然还需要添加跑步和倒退的动画,步骤如下:
1:新建两个状态,并设置好对应动画
2:将这三个状态相互连接起来,右键状态点击Make Transition即可创建出连线,可以看出这条线是有向的
下面这张图的含义就是:如果当前玩家在站立状态,当条件满足XXX时,就可以过渡到前进状态
3:设置触发条件,比如说当玩家按下W键进行移动时,动画由站立转为跑步
- Float:浮点类型参数,很少用
- Int:整型参数,例如设置Speed参数,当其为0时切换到站立动画,为2时触发跑步动画,为1时触发走路动画
- Bool:bool类型参数
- Trigger:触发器,相当于一瞬间的冲击,收到“冲击”时触发动画转换,很常用(特别是后面讲到的AnyState大法)
4:连线绑定条件
- Has Exit Time:当动画播放完毕时,播放下一个动画,除此之外勾选之后动画会强制播放完毕才转到下一个状态,哪怕是下面的条件触发
- Settings:动画过渡设置,例如玩家从攻击状态转为防御状态,这个过程既可以是平滑缓慢的,也可以是瞬间的,很难讲清楚具体设置方法建议自己调调看,一般来讲中间的蓝色范围越短动画转化的越迅速
- Conditions:触发状态切换条件(或运算)
- Solo/Mute:一般用于调试,Solo为当父状态有多条连线满足条件时,优先走这条,Mute是禁用
5:搞定
三、代码控制Animator
- Animator.SetInteger("参数名", 值):修改整型参数
- Animator.SetFloat("参数名", 值):修改浮点参数
- Animator.SetBool("参数名", true/false):修改Bool参数
- Animator.SetTrigger("参数名", true/false):触发器触发
然后就是写脚本苦力活了
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CdsLocation : MonoBehaviour
{
public enum MyState
{
none,
stand,
run,
back,
attack,
dead
};
MyState myState;
private Transform myTran;
private Animator myAnimator;
private Vector3 lastUpd, nowUpd;
void Start()
{
nowUpd = lastUpd = myTran.position;
}
void FixedUpdate()
{
nowUpd = myTran.position;
CheckRun(lastUpd, nowUpd);
lastUpd = myTran.position;
}
void CheckRun(Vector3 l, Vector3 r)
{
if (l == r || Time.time <= 0.2f) //如果两帧之间玩家位置没有改变,说明当前玩家是站立状态
{
if (myState != MyState.stand) //如果在之前不是站立状态,切换为站立状态并播放站立动画,下同
{
myAnimator.SetInteger("Speed", 0);
myState = MyState.stand;
}
}
else if (Vector3.Dot(myTran.forward, r - l) > 0) //将玩家正前方方向向量与玩家两帧之间位置差向量进行点积
{ //如果点积为正,说明玩家是向前移动,否则是向后移动
if (myState != MyState.run)
{
myAnimator.SetInteger("Speed", 4);
myState = MyState.run;
}
}
else
{
if (myState != MyState.back)
{
myAnimator.SetInteger("Speed", 2);
myState = MyState.back;
}
}
}
}