0
votes

I am making a 2d game. My problem is that while playing, if the player holds jump and is under a BoxCollider2D, the player will not fall until they release jump.

My player GameObject consists of a sprite renderer, a dynamic rigidbody2d with gravity on and a boxcollider2d.

Here are my movement scripts:

1:

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

public class JumpScript : MonoBehaviour {

    [Range(1, 10)]
    public float jumpVelocity;

    [Range(0,10)]
    public float speed;
    private bool jumpQueue = false;
    private bool boolin=false;
    void Update()
    {

        //Friggin fall, loser

        //Jumping
        ///*
        if (Input.GetButton("Jump")&& GetComponent<Rigidbody2D>                ().velocity.y==0)
        {
            GetComponent<Rigidbody2D>().velocity = Vector2.up *     jumpVelocity;
        }
        //*/
        //jumpQueue?
        /*
        if(Input.GetButtonDown("Jump"))
        {
            jumpQueue = true;
        }*/
        //Right Movement
        if (Input.GetKey(KeyCode.D))
        {
            GetComponent<Rigidbody2D>().velocity = new Vector2(1*speed,         GetComponent<Rigidbody2D>().velocity.y);
            boolin = true;
        }
        if(Input.GetKeyUp(KeyCode.D))
        {
            GetComponent<Rigidbody2D>().velocity = new Vector2(0,     GetComponent<Rigidbody2D>().velocity.y);
            boolin = false;
        }
        //Left Movement
        if (Input.GetKey(KeyCode.A))
        {
            GetComponent<Rigidbody2D>().velocity = new Vector2(-1*speed,     GetComponent<Rigidbody2D>().velocity.y);
            boolin = true;
        }
        if (Input.GetKeyUp(KeyCode.A))
        {
            GetComponent<Rigidbody2D>().velocity = new Vector2(0,     GetComponent<Rigidbody2D>().velocity.y);
            boolin = false;
        }
        //No movement?
        if (Input.GetKey(KeyCode.D) && Input.GetKey(KeyCode.A))
        {
            GetComponent<Rigidbody2D>().velocity = new Vector2(0,     GetComponent<Rigidbody2D>().velocity.y);
            boolin = false;

        }

        //Time to handle animation, boios.
        Rigidbody2D rb = GetComponent<Rigidbody2D>();

        bool schwomp = false;
        bool schwift = false;
        if(rb.velocity.y>0)
        {
            schwomp = true;
        }
        if(rb.velocity.y<0)
        {
            schwift = true;
        }
        Animator anim = GetComponent<Animator>();
        if (boolin)
        {
            anim.SetInteger("Boolin", 1);
            /*if (!anim.GetBool("expand"))
            {
                anim.SetBool("expand", true);
                anim.Play("running");
            }*/
        }
        else
        {
            anim.SetInteger("Boolin", 0);
            /*
            if(anim.GetBool("expand"))
            {
                anim.SetBool("expand", false);
                anim.Play("Idle");
            }*/
        }
        if(schwomp)
        {
            //anim.SetInteger("Boolin", 2);
        }
        if(schwift)
        {
            //anim.SetInteger("Boolin", 3);
        }
    }
}

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

public class BetterJumper : MonoBehaviour {

public float fallMultiplier = 2.5f;
public float lowJumpMultiplier = 2f;

Rigidbody2D rb;

void Awake()
{
    rb = GetComponent<Rigidbody2D>();

}

void Update()
{
    if(rb.velocity.y<0)
    {
        rb.velocity += Vector2.up*Physics2D.gravity.y*(fallMultiplier-1)*Time.deltaTime;

    }
    else if(rb.velocity.y>0&&!Input.GetButton("Jump"))
    {
        rb.velocity += Vector2.up * Physics2D.gravity.y * (lowJumpMultiplier - 1) * Time.deltaTime;
    }
}
}

Thank you so much in advance!

2
Please take a moment to format your code correctly.Soviut
You wrote what the problem is but did not provide what's the expected result....Programmer

2 Answers

3
votes

You're using Input.GetKey() which will poll the key every frame. This means more and more velocity is added the longer you hold jump. You've effectively built a jetpack rather than a jump force.

You should use Input.GetKeyDown() which will only fire once when a key is pressed down, then has to be released and pressed again in order to re-trigger. You then need to apply a single sufficiently strong vertical force using RigidBody.AddForce() to make the character jump, rather than adding continuously to the velocity.

Additionally, you should really be caching the result of your GetComponent<Rigidbody2D>() call when the script either wakes up or starts so that you're not calling it continuously; Each one of those calls takes processing time. Also, you should be using FixedUpdate() for physics.

public class ExampleClass : MonoBehaviour {
    public float thrust;
    public Rigidbody rb; // make the rigidbody variable available anywhere in the class

    void Start() {
        // cache the rigidbody component to the variable once on start
        rb = GetComponent<Rigidbody>();
    }

    void FixedUpdate() {
        // use the variable reference from now on rather than making GetComponent calls
        rb.AddForce(transform.up * thrust);
    }
}
0
votes

Soviut's answer explains it quite nicely, but there's more that you need to know. You're directly manipulating the velocity, which overrides the effect of any forces, including gravity(despite the fact you're applying it manually). See the documentation.

As demonstrated in Soviut's answer you should be applying forces and impulses, letting the physics engine determine the velocity. The only time you should set velocity directly is when you're building a simulation that intentionally has unrealistic physics(i.e. retro platformers). Even in that case, bear in mind that doing so creates a lot more work, because you'll need to factor in every little thing that creates movement. This means you're essentially re-inventing the physics engine.