Problem with OnCollisionEnter2D and OnCollisionExit2D

I’m trying to make the Player not jump continuously so I use isOnGrounded variable to check if the player is on the ground or not. Here is my code:

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

public class PlayerController : MonoBehaviour
{
    //REFERENCES
    private Rigidbody2D rb2D;
    //VARIABLES
    [SerializeField] float moveSpeed = 0;
    private float moveX;

    [SerializeField] bool isOnGrounded = true;
    [SerializeField] float jumpY;
    // Start is called before the first frame update
    void Start()
    {
        rb2D = GetComponent<Rigidbody2D>();
    }
    // Update is called once per frame
    void Update()
    {
        moveX = Input.GetAxis("Horizontal");
        PlayerJump();
    }
    private void FixedUpdate()
    {
        PlayerMove();

    }
    void PlayerMove()
    {
        rb2D.velocity = new Vector2(moveX * moveSpeed * Time.fixedDeltaTime, rb2D.velocity.y);

    }
    void PlayerJump()
    {
        if (Input.GetKeyDown(KeyCode.Space) && isOnGrounded == true)
        {
            rb2D.AddForce(new Vector2(rb2D.velocity.x, jumpY));
        }
    }
    private void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.CompareTag("Ground"))
        {
            isOnGrounded = true;
        }
    }
    private void OnCollisionExit2D(Collision2D other)
    {
        if (other.gameObject.CompareTag("Ground"))
        {
            isOnGrounded = false;
        }
    }
}

Picture of my project: https://i.stack.imgur.com/STlnE.png

The problem is when the Player is standing on Platform01 so obviously isOnGrounded = true and when the Player moves out of Platform01 isOnGrounded = false, I suppose when move in Platform02 it will automatically check the Ground and isOnGrounded = true but it still false and everything just messing up.

The problem that you have here is that this logic in general works but only if you never touch 2 “Ground” objects at the same time. If you exit collision 1 then isOnGrounded will be set to false because you do not keep a reference if you are in touch with 1 or more Ground objects.

You can either solve this by using OnCollisionStay to remind your script that you are still in touch with something or you can simply create a List of colliders.

    private List<Collider> groundCollidersTouching = new List<Collider>();

that you fill when Colliding:

    //onCollisionEnter:
    //if Ground
    if(!groundCollidersTouching.Contains(other.Collider))
           groundCollidersTouching.Add(other.Collider);

and empty when Leaving COllisions:

    //onCollisionExit:
    //if Ground
    if(groundCollidersTouching.Contains(other.Collider))
           groundCollidersTouching.Remove(other.Collider);

Then you can have your isGrounded as a function:

  public bool isGrounded()
  {
        return groundCollidersTouching.Count > 0;
  }

or even as getter:

  public bool isGrounded {get {return groundCollidersTouching.Count > 0;}}

This should solve your issue.
Code not tested as written there, can contain typos and/or pseudo code.
Let me know if something is unclear.

I’ve had issues with doing ground check like this myself, what I use instead now is isTouching

Just be sure not to call it too often for performance.

Here is probably the quickest and most simple way to go about doing this:

Try using OnCollisionStay, which will be called while the object is reacting with a collider, rather than the first time.

private void OnCollisionStay2D(Collision2D collision)
{
       if(collision.gameObject.tag == "ground")
       {
               isGrounded = true;
       }
}
private void OnCollisionExit2D(Collision2D collision)
{
      if(collision.gameObject.tag == "ground")
      {
            isGrounded = false;

     } 
}

void Update()
{
      if(isGrounded)
      {
              
               // your jump detection 

      }
}