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);
        }

    }
   
}

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;
		}
	}

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;
}

}
`

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;
		}
	}
}

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.

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, Unity - Scripting API: Physics.BoxCast
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.