Unity2D角色跳跃


文章目录

  • Unity2D角色跳跃
  • 思路
  • 事前准备
  • 通过速度判断状态
  • 通过位置判断状态



思路来自B站麦扣的第一期教程:https://www.bilibili.com/video/BV1z4411o7W4

思路

跳跃的动作可以拆分为两个动作,即上升动作和下落动作。

玩家可以在站立过程中起跳,也可以在移动过程中起跳。所以在动画控制器中,待机和移动都可以起跳,转变为上升状态,而下落状态则只能通过上升状态过渡。当玩家角色下落至地面时,应该由下落状态转变为待机,当然也可以转变为移动。

事前准备
public Rigidbody2D rb = GetComponent<RigidBody2D>(); // 获取物体的刚体
public CircleCollider2D cirColl = GetComponent<CircleCollider2D>(); // 获取圆形碰撞体
public Animator anim = GetComponent<Animator>(); // 获取动画控制器
public LayerMask floor; // 获取图层,这个建议自己到Inspector中选
public float jumpForce; // 起跳时的速度

请在你的角色的Game Object添加这些Component。

你需要有四个Anim文件,我的命名为StandAnim,RunAnim,UpAnim,DownAnim。分别对应待机动画,移动动画,上升动画和下落动画。

通过速度判断状态

先配置一下Animator:

创建一个float类型的Parameter命名为velocity

  1. StandAnim和RunAnim到UpAnim的Transition:velocity 大于 0
  2. UpAnim到DownAnim的Transition : velocity 小于0
  3. DownAnim到StandAnim的Transition : velocity 大于 -0.1; velocity 小于0.1

要实现跳跃,先要对角色的位置进行判定,如果在地面上则能够进行跳跃,如果不在地面上则不能进行跳跃。二段跳的设置在此不作讨论。在Unity中,我们可以通过RigidBody来对碰撞进行检测,通过IsTouchingLayers来检测当前刚体是否与图层发生碰撞,这个方法返回一个布尔值,发生碰撞返回true,不发生碰撞返回false。该方法的蚕食是一个LayerMask,指的是Inspector窗口中右上角的Layers,与Sorting Layers不同,Layers常用于碰撞检测,而Sorting Layers则控制物体在相机中的渲染层次。在创建LayerMask以后,通过GetMask方法来赋值,或者在Inspector中选择。

// Checks whether this collider is touching any colliders on the specified layerMask or not
bool Collider2D.IsTouchingLayers(int LayerMask)

如果角色在地面上,当玩家按下跳跃按钮时,给角色一个向上的速度。要给角色添加一个速度或者说力有很多种方法,在这里我采用的是直接为RigidBody的Velocity赋值,在2D游戏中,rb.velocity是一个Vector2的对象,但在3D游戏中,是一个Vector3的对象。在跳跃时,保持x的速度不变,让y轴随时间进行变化。

rb.velocity = new Vector2(rb.velocity.x, jumpForce*Time.deltaTime);

velocity指的是刚体的速度,为正值时速度方向延坐标轴正方向,就是说如果velocity.y的值为正值,即y轴速度大于0,那么角色就会向上移动。角色在起跳时速度向上,为正值,下落时速度向下,就是负值。在Animator中我们在设置Animation之间的Transition时,可以通过这个方法来判断。当y轴的速度大于0时,动画从待机转换为上升;当y轴的速度小于0时,动画从上升转换为下降。

这样就实现了从待机到上升再到下降的动画转换。但是在落地时角色会保持下降的动画而不会转换回待机。当角色在地上待机时y轴速度为0,我们可以设置当y轴速度为0时,动画从下落转换为待机。但是Animator的Condition并没有提供相等的判断,所以我选择的是大于-0.1,小于0.1,当y轴速度在这个区间内时,就切换动画。虽然角色在到达最高点时也会有一瞬间速度为0,但是Animator中上升是无法转换为待机的,所以不会出现在空中播放待机动画的场景。

以下是实现跳跃的逻辑:

void Jump()
    {
        anim.SetFloat("velocity", rb.velocity.y);// 监测角色的速度
        if (cirColl.IsTouchingLayers(floor))	// 判断角色是否在地面上,就是判断与tilemap的碰撞
        {
            if (Input.GetButtonDown("Jump") )	// 监听跳跃按钮
            {
                rb.velocity = new Vector2(rb.velocity.x, jumpForce*Time.deltaTime);             
            }
        }
    }

以上方法就实现了角色跳跃和动画的切换。但是有一个严重的缺陷,我们是通过y轴的速度来判断运动状态的,如果角色在斜坡上运动,y轴的速度也会变化。就会出现虽然是在上坡,但是动画却是上升的动画。要想避免这个问题,建议不使用速度作为判断标准。


通过位置判断状态

在Animator中创建三个布尔型参数,命名为up,down和stand。

  1. 在StandAnim和RunAnim到UpAnim的Transition中添加条件:当up是True时转换。
  2. 在UpAnim到DownAnim的Transition中添加条件:当down是True时转换。
  3. 在DownAnim到StandAnim的Transition中添加条件:当stand是True时转换。

下面是在代码中实现的逻辑:

  1. 对角色位置进行判断,在地面则可以起跳,不在地面则不可以起跳。
  2. 当角色起跳时,将up的值设置为True,将stand的值设为false。
  3. 当y轴速度小于0时,将down的值设置为true,并把up值改为false。
  4. 当角色落到地面时,将stand的值设置为True,将down的值设为false。

代码样例:

void Jump()
    {
        if (cirColl.IsTouchingLayers(floor))
        {
            anim.SetBool("stand",true);
            anim.SetBool("down",false);
            if (Input.GetButtonDown("Jump") )
            {
                rb.velocity = new Vector2(rb.velocity.x, jumpForce*Time.deltaTime);
                anim.SetBool("up",true);
                anim.SetBool("stand",false);
            }
        }
        else
        {
            if (rb.velocity.y<0)
            {                
                anim.SetBool("down",true);
                anim.SetBool("up", false);
            }
        }
    }

因为从待机到上升,上升到下落,下落到待机,这三个过程都是单向的,所以可以通过三个bool类型的参数进行判断。这样就避免了由于y轴速度变化导致的动画转换出错。