本文实现比较流畅的跑和跳跃
跑的动画需要从idle经历到walk再到run的过程,这个过程可以用融合树实现
也可以让玩家在按下按键时先固定播放完一个walk的动画,然后再自动切换到run的状态。
只不过在任何状态时,只要玩家松开了按键,就让玩家回到idle状态。
这个状态机如下:
对于跳跃的这个状态,我们使用一个子状态机来做,将和跳跃有关的状态都放在里面而不是外面。
从任何状态都可以进入到跳跃状态,跳跃动画播放完毕则无条件进入坠落状态。
遇到地面时,则让坠落状态立马切换为着陆状态,着陆状态动画完整播放完毕则再次进入idle状态。
使得玩家移动起来的代码方式需要用刚体,那么就有两种方式。一个是给予刚体力,一个是直接赋予刚体速度。给力的方式类似物理效果,但是实际移动不需要那么真实。使用赋予速度的方法即可。
代码很简单此处略。
判断着陆
判断着陆核心思想是使用OnCollisionEnter和OnCollisionExit,碰撞的时候并判断与玩家所接触的物体的Layer是否是特定的地面。是的话则判断玩家不在地面上了。
但是光这样还不够,如果玩家是从上往下接触地面,那么此时是正常落地。但是如果玩家从下往上接触地面,比如从下面的格子跳到上面的格子中,此时不能判断玩家落地了。我们可以通过函数来判断玩家和层接触是从下往上还是从上往下。
使用到了下面这个api
代码如下:
当被碰撞的物体满足下面这个代码条件时,我们则认为玩家是从上往下着陆的
col.contacts[0].normal == Vector2.up
private void OnCollisionEnter2D(Collision2D collision)
{
Grouding(collision, false);
}
private void OnCollisionStay2D(Collision2D collision)
{
Grouding(collision, false);
}
private void OnCollisionExit2D(Collision2D collision)
{
Grouding(collision, true);
}
private void Grouding(Collision2D col, bool exitState)
{
if (exitState)//离开为真
{
if (col.gameObject.layer == LayerMask.NameToLayer("Terrain"))
isOnGround = false;
}
else
{
if (col.gameObject.layer == LayerMask.NameToLayer("Terrain") && !isOnGround && col.contacts[0].normal == Vector2.up)//从上往下
{
characterEffect.DoEffect(CharacterEffect.EffectType.FallTrail, true);
isOnGround = true;
JumpCancle();
}
else if (col.gameObject.layer == LayerMask.NameToLayer("Terrain") && !isOnGround && col.contacts[0].normal == Vector2.down)
{
JumpCancle();
}
}
animator.SetBool("isOnGround", isOnGround);
}
然后还需要设定动画机中的触发跳跃动画的trigger取消防止其再次进入。
private void JumpCancle()
{
animator.ResetTrigger("jump");
jumpTimer = 0.25f;
}
Cinemachine中的dead zone代表的是玩家在这个范围内移动,相机不会也跟着一起移动: