- Home /
How do I stop jumping mid air?
I know I need to do something with "isGrounded" but i just don't know what to do Here is my code
using UnityEngine;
using System.Collections;
public class Playermovement : MonoBehaviour
{
public Rigidbody rb;
public float forwardForce = 200f;
public float sidewaysForce = 250f;
public float jumpHeight = 250f;
public float rotationForce = 50f;
void FixedUpdate()
{
rb.AddForce(0, 0, forwardForce * Time.deltaTime);
if (Input.GetKey("d"))
{
rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0);
transform.Rotate(-Vector3.forward * rotationForce * Time.deltaTime);
}
if (Input.GetKey("a"))
{
rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0);
transform.Rotate(-Vector3.back * rotationForce * Time.deltaTime);
}
if (Input.GetKeyDown("w"))
{
rb.AddForce(0, jumpHeight, 0);
}
}
}
Answer by N1warhead · Mar 01, 2017 at 08:48 AM
I've encountered this before, so far the best way I've found to getting around it is to do this.
// Not tested - but it's roughly if not exactly what I did in the past.
// Use a timer inside Update, when the timer tops - the force stops and you drop down.
// Only problem with doing it this way is each jump will ALWAYS be the same height.
// But it should be easy to modify this to work any way you desire.
float jumpTime = 2.5f;
bool isGrounded;
public Rigidbody rb;
public float jumpHeight = 250f;
void Update(){
if (Input.GetKeyDown (KeyCode.W)) {
isGrounded = false;
}
if (!isGrounded) {
jumpTime -= Time.deltaTime;
}
}
void FixedUpdate(){
if (!isGrounded && jumpTime > 0) {
rb.AddForce (0, jumpHeight, 0);
}
}
void OnCollisionEnter(Collision col){
if (col.gameObject.tag == "Map") {
jumpTime = 2.5f;
isGrounded = true;
}
}
Answer by DragonGamingYT · Nov 05, 2017 at 10:17 PM
The easiest way i found was to set isGrounded false when jumping and set it true when touching the ground`using UnityEngine;
public class Jump : MonoBehaviour {
[Range(1, 10)]
public float jumpVelocity;
private bool isGrounded;
void Update()
{
if (Input.GetButtonDown("Jump") && isGrounded == true)
{
GetComponent<Rigidbody>().velocity = Vector3.up * jumpVelocity;
isGrounded = false;
}
}
void OnCollisionEnter()
{
isGrounded = true;
}
} `
This is the method that I would personally go with - this is the most lightweight implementation and it always works great for me. Here is a version with a few amendments:
public float jumpVelocity;
private bool isGrounded;
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.W) && isGrounded)
{
rb.velocity = Vector3.up * jumpVelocity;
isGrounded = false;
}
}
void OnCollisionEnter()
{
isGrounded = true;
}
Answer by BhargavChauhan · Mar 01, 2017 at 08:46 AM
First set your ground tag as a Ground Tag and make changes on your code below. This will prevent your player to mid air jump.
using UnityEngine;
using System.Collections;
public class Playermovement : MonoBehaviour
{
public Rigidbody rb;
public float forwardForce = 200f;
public float sidewaysForce = 250f;
public float jumpHeight = 250f;
public float rotationForce = 50f;
bool isGrounded;
void FixedUpdate()
{
rb.AddForce(0, 0, forwardForce * Time.deltaTime);
if (Input.GetKey("d"))
{
rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0);
transform.Rotate(-Vector3.forward * rotationForce * Time.deltaTime);
}
if (Input.GetKey("a"))
{
rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0);
transform.Rotate(-Vector3.back * rotationForce * Time.deltaTime);
}
if (Input.GetKeyDown("w"))
{
if (isGrounded) {
rb.AddForce (0, jumpHeight, 0);
isGrounded = false;
}
}
}
void OnCollisionEnter(Collision other){
if (other.gameObject.tag == "Ground") {
isGrounded = true;
}
}
}
But wouldn't making isGrounded false stop the force from working? Add Force is meant to gradually add force over a period of time, so you might get 0.005 meters off the ground before it's then false, which I would think would kill the force before ever getting high enough.
Answer by CaffeineAndCoffee · Mar 01, 2017 at 02:01 PM
Create a bool:
bool isGrounded;
Then you will need to create a raycast hit,
RaycastHit hitInfo;
Then call a raycast inside of an if loop,
if (Physics.Raycast (transform.position, Vector3.down, out hitInfo, 0.2f)) {
isGrounded = true;
} else {
isGrounded = false;
}
If the object is more than 0.2 units off the ground, then
isGrounded will be set to false.
how may i use this in my code
using UnityEngine; using System.Collections;
public class Jump : $$anonymous$$onoBehaviour {
public float jump;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void update()
{
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Space))
{
GetComponent<Rigidbody>().AddForce(new Vector3(0, jump, 0));
}
}
}
You can use isGrounded as a condition for being able to jump,
if (isGrounded == true) {
if (Input.Get$$anonymous$$eyDown ($$anonymous$$eycode.Space)) {
GetComponent().AddForce(new Vector3(0, jump, 0)
}
}
so id put the raycast call code in void update?
Answer by jjcrawley · Mar 02, 2017 at 01:18 PM
There are several ways to handle this ability, and the path you take will ultimately come down to how your jump is designed.
First things first: be wary of OnCollisionEnter. The solution will work if your tags are setup properly, but would require additional tag filters if you had platforms tagged as the floor. If the tags weren't setup correctly you would hit your head on the platform, tagged as floor, and your jump would reset. Not what you're after.
One way to fix this problem is to use a physics raycast that aims downwards. If necessary, you could use an Overlap box instead, this may be better as you can then still jump if you're right on the edge of a platform. Have a peak at the API, https://docs.unity3d.com/ScriptReference/Physics.BoxCast.html There are a ton of detection functions to choose from.
These casts would be done in the downwards direction, Vector3.down and you can use a collision mask to filter the cast. Using a mask allows you to cull out certain physics layers using the casting function, rather than constantly checking for tags in OnCollisionEnter, although the messages would be filtered by the collision matrix anyway.
In terms of code, it would be something along the lines of:
using UnityEngine;
using System.Collections;
public class Playermovement : MonoBehaviour
{
public Rigidbody rb;
public float forwardForce = 200f;
public float sidewaysForce = 250f;
public float jumpHeight = 250f;
public float rotationForce = 50f;
//private so you can't change it externally by accident, use a getter to see it.
private bool isGrounded;
void FixedUpdate()
{
//do checks first, so if you need it later, it's all done
Vector3 feetPos = transform.position + offset; //offset is defined by you, this is just a safety check to ensure that the ray doesn't hit the player. You could avoid offset completely by using a layer mask, with the player being on its own layer.
Ray myRay = new Ray(feetPos, Vector3.down); //the origin and direction will differ depending on needs
float maxDistance = 2; //just a guess, tweak as needs dictate
int layerMask = LayerMask.GetMask("Floor", "Any other jumpable things"); //The mask used will depend on your project, also may want to cache on Awake so you're not constantly remaking it.
isGrounded = Physics.RayCast(myRay, maxDistance, layerMask); //true if the raycast hits something, should be only 'ground' objects if the mask is setup correctly
//check boxcast info if you'd rather use a box cast, similar principle just a few additional params
rb.AddForce(0, 0, forwardForce * Time.deltaTime);
if (Input.GetKey("d"))
{
rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0);
transform.Rotate(-Vector3.forward * rotationForce * Time.deltaTime);
}
if (Input.GetKey("a"))
{
rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0);
transform.Rotate(-Vector3.back * rotationForce * Time.deltaTime);
}
bool movingUpwards = rb.velocity.y > 0;
//moving upwards can be used to prevent the player from hitting the jump button again if they just pressed it, as a force is applied the moment you press the button so if the velocity is > 0, then you're moving upwards. This solution may not work with moving platforms, going up. You could use a timer coroutine instead, start the coroutine the moment you press the button and don't let it be pressed again until it finishes, have a 'finished jumping' flag, false when just pressed, true when finished and 'time till next press' variable, defines how long until next press.
if (Input.GetKeyDown("w") && isGrounded && !movingUpwards)
{
rb.AddForce(0, jumpHeight, 0);
}
}
}
One final thing before concluding, may may want to use the input checks in Update. Fixed update is called consistently, however, you want to detect the press immediately and, unless I'm mistaken, Unity updates the input stuff, in the Update loop. As a consequence you may miss the press in Fixed update.
Hopefully this will lead you in the right direction.