1 基本准备
在前几篇里面,已经搞定了基本的角色控制,已经设置好了角色不同状态的动画效果。
但是会发现,在进行跳跃的时候也依旧是闲置状态下的动画,那么这一篇要解决的就是不同动作下的状态切换。
2 为不同动画状态切换设置参数
点击之前在Assets->Animation->Player里面创建的Player(Animator类型)的文件,就会看到下图中间这个Animatior面板。这里面会看到之前我们为Player设置的run、idle等动画状态。
每个状态可以通过右键点击Make Transition来创建一个箭头,连接其它的模块,这里也就是不同状态转移方向的设置。
然后结合之前写的代码,写了左右移动和跳的控制,那么我就连接好idle、jump和run的动画,来配合我们之前写的代码。
接下来,设置动画之间转移需要的控制参数,通过下图框选的地方就可以新建一个参数了。先点击Parameters-> + ->选择参数的类型。
新建了ground(bool)和speed(float)两种变量。ground用来判断角色是否在地上,speed用来记录角色左右移动速度。
然后点击之前创建的Transition,为每一个Transition添加参数控制。
点击Transition后,右边会出来一个面板,红色框框的地方:
Has Exit Time(是否有退出时间),这个不勾选的,勾选代表这个动画必须播完才能下一个动画,不勾选代表这个动画可以被打断;
Transition Duration(过渡的时间),设置为0,从A动画过渡到B动画需要的时间,如果设勾选了Fixed Duration,那么这个时间以秒为单位,否则的话以A的时间为基础(百分比时间);
Conditions,用来添加参数判断。
上图的参数ground要勾选,角色一开始是在地面上,ground初始值应该是true。
参数判断:
- idle->run:speed速度大于0.001
- run->idle:speed速度小于0.001
- run->jump:ground等于false
- jump->idle:ground等于true
- idle->jump:ground等于false
3 代码控制参数实现动画状态切换
初始的代码思路:每次更新后,更新速度,通过y轴速度来判断是否处于跳跃状态。
遇到的问题:
- 跳跃不能通过y轴速度不为零来判断,因为上下坡也会有y轴速度的变化。在按下跳跃键后就让jump动画转换,需要来判断是否碰到地面落地来结束jump动画,这也是为什么我要添加ground(前面动画状态切换的参数)。
- 如果只判断是否碰到地面的时候需要二段跳的时候才会有动画转变,大概是因为按下跳跃按键后ground刚转换为false,又立马检测是否碰到地面,结果有修改为了true。
修改后的代码思路:每次更新后,更新速度,按下跳跃键后就转变动画,在下落状态的时候判断是否有没有触碰到地面。
介绍一下Layer:通常是逻辑用到的,用来判断碰撞,触发检测的掩盖用的。(需要用这个来判断是否碰到了地面)Layer只有32层,官方占了前8个(不可更改)。通常代码里面会用LayerMask来开启和关闭Layer,使用方式(LayerMask mask = 1 << 你需要开启的Layers层,LayerMask mask = 0 << 你需要关闭的Layers层)。
代码前期工作:为TileMap修改Layer,添加Ground的Layer,然后把TileMap的Layer修改为Ground。
代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
private float moveSpeed;//移动速度
private float jumpForce;//跳跃力
private Rigidbody2D rig;//刚体
private Animator Anim;//角色的Animator
private Collider2D coll;//角色的碰撞器
public LayerMask ground;//用来开启layer
private bool falling=false;//用来标记是否是下落状态
//初始化
void Start () {
rig = GetComponent<Rigidbody2D>();//获取主角刚体组件
Anim = GetComponent<Animator>();//获取主角动画组件
coll = GetComponent<Collider2D>();//获取角色碰撞器
ground = 1<<8;//开启Ground的layer层,Ground在layer8
jumpForce = 575f;
moveSpeed = 500f;
}
//固定的时间间隔执行,不受游戏帧率的影响
void FixedUpdate()
{
Move();
changeAnimator();
}
//控制移动
void Move()
{
float moveMultiple = Input.GetAxis("Horizontal");
float faceDirection = Input.GetAxisRaw("Horizontal");
//角色左右移动
if (moveMultiple!=0)
{
rig.velocity = new Vector2(moveMultiple * moveSpeed * Time.deltaTime, rig.velocity.y);//输入x,y向量,数值*方向
}
//角色朝向修改
if(faceDirection!=0)
{
transform.localScale = new Vector2(faceDirection, 1);
}
//角色跳跃
if (Input.GetButtonDown("Jump"))
{
rig.velocity = new Vector2(rig.velocity.x, jumpForce * Time.deltaTime);
Anim.SetBool("ground", false);
}
}
void changeAnimator()
{
Anim.SetFloat("speed", Mathf.Abs(rig.velocity.x));//速度是向量
if (Anim.GetBool("ground")==false&&rig.velocity.y<0)
{
falling = true;
}
else if (coll.IsTouchingLayers(ground)&&falling)
{
Anim.SetBool("ground", true);
falling = false;
}
/*if (coll.IsTouchingLayers(ground))
{
Anim.SetBool("ground", true);
Debug.Log("你碰地了!");
}
//会有一个问题,只有第二次跳才会有动画,
*/
/*if (Mathf.Abs(rig.velocity.y) > 0.001)
{
Anim.SetBool("ground",false);
}
else {
Anim.SetBool("ground", true);
}
//会有问题,斜坡走的时候,y轴也会发生速度的变化
*/
}
}
4 调整TileMap碰撞点
在进行爬坡测试的时候,出现了一个问题就是斜坡的瓦片碰撞点不能和瓦片重合,且凹凸不平,运行体验不佳。
不是正方形的瓦片的话,TileMap的碰撞点自动设置可能很奇怪,直接TileMap设置碰撞器的话,可能会有凹凸不平的情况,且凹凸不平的形状不能和瓦片完全重合。
出现这个问题可能需要回到一开始编辑图片,在Sprite Editor里面,左边的红框选择第三个Custom Physics Shape,然后点击需要修改碰撞点的方形块,然后点击Generate就可以修改碰撞点。