Sharpevil Sharpevil - 3 months ago 22
C# Question

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

Answer

Building on Max's answer...

You should use FixedUpdate() for physics stuff like applying a force to a rigidbody as it runs 100 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, and apply the physics in FixedUpdate(), and check for input in Update().

Comments