实现Unity2D游戏中跳跃功能和相关问题解决

Posted 超级开朗的网友

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现Unity2D游戏中跳跃功能和相关问题解决相关的知识,希望对你有一定的参考价值。

一、跳跃功能基本实现

二、跳跃bug解决

三、跳跃优化

一、跳跃功能基本实现

在unity中我们要实现跳跃功能基本依赖代码实现。在这里我们先构建场景,笔者在这里使用tilemap构建地面,创建正方形代表物体。如图所示

我们要为其添加代码,我在这创建名为Control.cs的C#脚本,用来控制正方形的行为,将其绑定到正方形组件上,同时为正方形添加rigidbody2d和boxcollider组件,将rigidbody2d中z轴锁定。并且也为tilemap添加组合碰撞体和tilemapcollider,将tilemapcollider中Use by Composite打钩,使用tilemap组合碰撞体,调整碰撞区域,锁定x,y,z轴。同时为了方便,引入Cinemachine跟随正方形,以便实时观察。

Control.cs的代码如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Control : MonoBehaviour

    //声明刚体组件
    Rigidbody2D rigidbody;
    //力大小
    float force = 300.0f;
    void Start()
    
        //获取刚体组件
        rigidbody = GetComponent<Rigidbody2D>();
    

    void Update()
    
        
        //如果按下W,实现跳跃功能
        if (Input.GetKeyDown(KeyCode.W))
        
            Jump();
        

    

    void Jump()
    
        //对物体施加方向向上的力,也可以对rigidbody.velocity进行操作,但是不推荐
        rigidbody.AddForce(Vector2.up * force);
    

这样基本的跳跃功能我们就实现了。

二、跳跃bug解决

在运行中,我们很快就能发现一个问题,只要我们多次按W键,它就能一直跳跃,这当然不符合实际情况。我们需要代码监测它是否在地面上。我们可以重载OnCollisionEnter2D和OnCollisionExit2D来监测它是否在地面上。

首先,我们要把tilemap的tag设置为Ground,没有的自行添加。

 将代码修改为:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Control : MonoBehaviour

    //声明刚体组件
    Rigidbody2D rigidbody;
    //力大小
    float force = 300.0f;
    //设置是否可以跳跃的bool值,初始值为true
    bool jumpable = true;
    void Start()
    
        //获取刚体组件
        rigidbody = GetComponent<Rigidbody2D>();
    

    void Update()
    
        
        //如果按下W,实现跳跃功能
        if (Input.GetKeyDown(KeyCode.W))
        
            Jump();
        

    

    void Jump()
    
        if (jumpable)
        
            //对物体施加方向向上的力,也可以对rigidbody.velocity进行操作,但是不推荐
            rigidbody.AddForce(Vector2.up * force);
        
    

    //与地面碰撞,jumpable为true
    private void OnCollisionEnter2D(Collision2D collision)
    
        //如果碰撞体的tag为Ground,设置jumpable
        if(collision.gameObject.tag == "Ground")
        
            jumpable = true;
        
    

    //离开地面,jumpable为false
    private void OnCollisionExit2D(Collision2D collision)
    
        if (collision.gameObject.tag == "Ground")
        
            jumpable = false;
        
    

这样就可以解决这个问题了。

在很多游戏中,我们要设置多段跳功能。所以我们要设置一个int存放当前跳跃次数。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Control : MonoBehaviour

    //声明刚体组件
    Rigidbody2D rigidbody;
    //力大小
    float force = 300.0f;
    //设置是否可以跳跃的bool值,初始值为true
    bool jumpable = true;
    //设置n段跳
    int n;
    void Start()
    
        //获取刚体组件
        rigidbody = GetComponent<Rigidbody2D>();
    

    void Update()
    
        
        //如果按下W,实现跳跃功能
        if (Input.GetKeyDown(KeyCode.W))
        
            Jump();
        

    

    void Jump()
    
        //二段跳 要放在update里面 因为没fixedDeltaTime
        if (jumpable)
        
            n = 1;//踩在地面上的时候,可以跳n+1次,想要设置三段跳只要改为2即可
        
        if (Input.GetKeyDown(KeyCode.W) && n >= 0)
        
            rigidbody.AddForce(Vector2.up * force);
            n--;
        
    

    //与地面碰撞,jumpable为true
    private void OnCollisionEnter2D(Collision2D collision)
    
        //如果碰撞体的tag为Ground,设置jumpable
        if(collision.gameObject.tag == "Ground")
        
            jumpable = true;
        
    

    //离开地面,jumpable为false
    private void OnCollisionExit2D(Collision2D collision)
    
        if (collision.gameObject.tag == "Ground")
        
            jumpable = false;
        
    

墙体是2d游戏中很常见的情景,我们当前的代码只能监测物体的碰撞,如果他碰撞到墙体,jumpable=true,那么它还能进行跳跃,这也不符合生活实际,解决这个问题有些困难,由于各种原因,以下的方法不一定能成功解决,请大家一一测试再应用。

第一种方法:可以通过射线监测,从中心点发射一条竖直向下,固定长度的射线,如果射线碰撞到地面设置jumpbable = true。

使用前检查sprite的中心点,射线从此处发射的。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Control : MonoBehaviour

    //声明刚体组件
    Rigidbody2D rigidbody;
    //力大小
    float force = 300.0f;
    //设置是否可以跳跃的bool值,初始值为true
    bool jumpable = true;
    //设置n段跳
    int n;
    //设置射线长度
    float length = 1.0f;
    void Start()
    
        //获取刚体组件
        rigidbody = GetComponent<Rigidbody2D>();
    

    void Update()
    
        //创建射线
        RaycastHit2D info = Physics2D.Raycast(rigidbody.position, -Vector2.up, length);
        if (info.collider != null)
        //如果发生了碰撞
            GameObject obj = info.collider.gameObject;
            if (obj.CompareTag("Ground"))//用tag判断碰到了什么对象
                jumpable = true;

            //如果按下W,实现跳跃功能
            if (Input.GetKeyDown(KeyCode.W))
            
                Jump();
            

        

        void Jump()
        
            //二段跳 要放在update里面 因为没fixedDeltaTime
            if (jumpable)
            
                n = 1;//踩在地面上的时候,可以跳n+1次,想要设置三段跳只要改为2即可
            
            if (Input.GetKeyDown(KeyCode.W) && n >= 0)
            
                rigidbody.AddForce(Vector2.up * force);
                n--;
            
        

    

但是这会使得射线长度难以确定,长度过长,还没有跳到地面上就就可以跳起了;长度过短,射线监测不到,就跳不起来。这个长度需要反复调试,并且改变参数可能还需要重新调试,所以我不太推荐这种方法。

第二种方法:在物体脚下设置触发器。再添加一个boxcollider,勾选Is Trigger,代表这个碰撞区域是触发器。如图所示

 需要注意的是,触发器的宽度要比原本的碰撞体小,下方可以突出一点,以便代码更好的监测。

在代码中我们通过重载OnTriggerEnter2D和OnTriggerExit2D来监测是否在地面

代码如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Control : MonoBehaviour

    //声明刚体组件
    Rigidbody2D rigidbody;
    //力大小
    float force = 300.0f;
    //设置是否可以跳跃的bool值,初始值为true
    bool jumpable = true;
    //设置n段跳
    int n;
    void Start()
    
        //获取刚体组件
        rigidbody = GetComponent<Rigidbody2D>();
    

    void Update()
    
        //如果按下W,实现跳跃功能
        if (Input.GetKeyDown(KeyCode.W))
        
            Jump();
        
    

    void Jump()
    
        //二段跳 要放在update里面 因为没fixedDeltaTime
        if (jumpable)
        
            n = 1;//踩在地面上的时候,可以跳n+1次,想要设置三段跳只要改为2即可
        
        if (Input.GetKeyDown(KeyCode.W) && n >= 0)
        
            rigidbody.AddForce(Vector2.up * force);
            n--;
        
    

    //重载函数来监测
    private void OnTriggerEnter2D(Collider2D collision)
    
        if(collision.gameObject.tag == "Ground")
        
            jumpable = true;
        
    

    private void OnTriggerExit2D(Collider2D collision)
    
        if (collision.gameObject.tag == "Ground")
        
            jumpable = false;
        
    

这种方法实现可能性较大。

在测试中,跳到墙面上,在添加了移动代码之后跳到墙面上,有可能出现按方向键,物体没有掉下来的情况。我们需要设置物理材料。

在Project视图中,添加物理材料。

 打开物理材料,将摩擦力设置为0

 将物理材料拖拽到rigidbody中。

 就可以有效解决这个bug了。

三、跳跃优化

跳跃的功能完成了,但是运行时感觉距离现实情况仍有些距离。

事实上,如果你让物体从高处落下,你会发现在下落过程中,它的速度并没有增加,更像是匀速下降。所以我们要为其添加重力。

注:此处修改代码来自B站“更好的跳跃”

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Control : MonoBehaviour

    //声明刚体组件
    Rigidbody2D rigidbody;
    //力大小
    float force = 300.0f;
    //设置是否可以跳跃的bool值,初始值为true
    bool jumpable = true;
    //设置n段跳
    int n;
    void Start()
    
        //获取刚体组件
        rigidbody = GetComponent<Rigidbody2D>();
    

    void Update()
    
        //如果按下W,实现跳跃功能
        if (Input.GetKeyDown(KeyCode.W))
        
            Jump();
        
        //上升和下落过程中,手动改变速度
        if(rigidbody.velocity.y < 0)
        
            rigidbody.velocity -= Vector2.up * Physics2D.gravity.y * Time.deltaTime;
        
        else if(rigidbody.velocity.y > 0)
        
            rigidbody.velocity += Vector2.up * Physics2D.gravity.y * Time.deltaTime;
        
    

    void Jump()
    
        //二段跳 要放在update里面 因为没fixedDeltaTime
        if (jumpable)
        
            n = 1;//踩在地面上的时候,可以跳n+1次,想要设置三段跳只要改为2即可
        
        if (Input.GetKeyDown(KeyCode.W) && n >= 0)
        
            rigidbody.AddForce(Vector2.up * force);
            n--;
        
    

    //重载函数来监测
    private void OnTriggerEnter2D(Collider2D collision)
    
        if(collision.gameObject.tag == "Ground")
        
            jumpable = true;
        
    

    private void OnTriggerExit2D(Collider2D collision)
    
        if (collision.gameObject.tag == "Ground")
        
            jumpable = false;
        
    

运行后,会发现更加贴近生活生活实际了。

最后,感谢你看完我的文章。本人是大一学生,文章难免有不足之处,恳请专业人士批评指正。

以上是关于实现Unity2D游戏中跳跃功能和相关问题解决的主要内容,如果未能解决你的问题,请参考以下文章

(转)CocosCreator零基础制作游戏《极限跳跃》制作游戏障碍物实现碰撞检测

unity2d游戏开发系列教程:四一个2D游戏所需要的主要功能(游戏框架)

Unity2D 小游戏之 RocketMouse

1.Unity2D 横版 移动+跳跃+跳跃优化+长按高跳

UnityUnity实现2D平台游戏带跳跃的自动寻路功能

unity2D背景移动补偿从而获得3d错觉效果