简体   繁体   中英

My character sometimes fails to jump - Unity2D

So, I've set up a basic script in Unity to move around a 2D sprite, and it works pretty well, except for the fact that occasionally the player-character will not jump when told to. It seems to only happen while or shortly after the character moves horizontally. I really have no idea why this is happening. Hopefully someone else can shed some light on this. Here is the controller script. Any feedback is helpful, even if it's unrelated to the question, I'm doing this as a learning exercise.

using UnityEngine;
using System.Collections;

public class PlayerControlsCs : MonoBehaviour {

public KeyCode walkLeft;
public KeyCode walkRight;
public KeyCode jumpUp;

public float speed = 5;
public float jumpForce = 750;
public int jumpCapacity = 1;
public int extraJumps = 0;

public bool facingRight = true;
public bool grounded = false;
private Transform groundCheck;
private Animator anim;

void Awake () {
    groundCheck = transform.Find("GroundCheck");
    anim = GetComponent<Animator>();
}

void Update () {
    grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Terrain"));

    if(grounded){
        anim.SetTrigger("Grounded");
        anim.ResetTrigger("Falling");
        extraJumps = jumpCapacity;
    }
    else {
        anim.ResetTrigger("Grounded");
        anim.SetTrigger("Falling");
    }

}

void FixedUpdate () {
    anim.SetFloat("Speed", Mathf.Abs(rigidbody2D.velocity.x));
    anim.SetFloat("Ascent", rigidbody2D.velocity.y);

    if(Input.GetKey(walkLeft))
    {
        if(facingRight){
            Flip();
        }
        rigidbody2D.velocity = new Vector2(-speed, rigidbody2D.velocity.y); 
    }
    else if(Input.GetKey(walkRight))
    {
        if(!facingRight){
            Flip();
        }
        rigidbody2D.velocity = new Vector2(speed, rigidbody2D.velocity.y);  
    }
    else
    {
        rigidbody2D.velocity = new Vector2(0, rigidbody2D.velocity.y);  
    }

    if(Input.GetKeyDown(jumpUp) && grounded)
    {
        anim.SetTrigger("Jump");

        rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, 0);

        rigidbody2D.AddForce(new Vector2(0f, jumpForce));
    }
    else if(Input.GetKeyDown(jumpUp) && extraJumps > 0) 
    {
        anim.SetTrigger("Jump");

        rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, 0);

        rigidbody2D.AddForce(new Vector2(0f, jumpForce));

        extraJumps -= 1;
    }

}

void Flip ()
{
    // Switch the way the player is labelled as facing.
    facingRight = !facingRight;

    // Multiply the player's x local scale by -1.
    Vector3 theScale = transform.localScale;
    theScale.x *= -1;
    transform.localScale = theScale;
}
}

If it helps at all, here is what I have made:

https://www.dropbox.com/s/ka4vgc0s0205sbd/test.html

https://www.dropbox.com/s/40i8kltwfz1jgyu/test.unity3d

Update and FixedUpdate aren't guaranteed to happen every time one after another. I haven't ran into this kind of bugs, so I can't say for sure, but you may experience a situation where your grounded state is incorrect. Instead of saving this value as a field, try checking for it every time you need it — at least a separate check in Update and FixedUpdate.

Building on Max's answer...

You should use FixedUpdate() for physics stuff like applying a force to a RigidBody as it runs 50 times a second regardless of how fast the game is running. This makes it frame rate independent .

See the documentation .

Update() runs once per frame, so is frame rate dependent . In here is where most of your non-physics stuff should go, checking for inputs for example.

This video is a good explanation of the difference.

The link in the comment is also correct:

You need to call this function from the Update function, since the state gets reset each frame

So check if is grounded only when the player presses jump as ray/linecasts are computationally expensive, apply the physics in FixedUpdate() , and check for input in Update() .

Input should be handeled in Update, because update runs every frame, while fixed update isn't like update and it doesn't run every frame so when input is handeled in fixed update it might miss the input and it won't jump ! I suggest you cut and paste all the input code from fixed update to update !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM