2D Mobile Game: Player Jump!
In this article, I will cover one way to create a jump mechanic to a 2D platformer using Raycast and a bool to track whether the player is grounded or not.
We are going to initialize some variables, the first being a float variable, _jumpForce, which will determine how high we jump and a bool variable, _grounded, that will determine if the player is on the ground or not.
In OnUpdate, we are checking for two conditions to be true: the space bar is press and _grounded is true. When both of those conditions are met, we set the Rigidbody’s velocity to a new velocity by setting a new Vector2 and keeping the current velocity on the X but setting the Y velocity to the _jumpForce value.
We are going to use RaycastHit2D to detect whether the player is on the ground or not. RaycastHit2D allows us to draw a line that can detect contact with Colliders. This line can be drawn from a location, in a direction, and a certain distance. We are drawing this line from the player’s position, going down, a distance of 1 unit.
Using Debug.DrawRay, we can see this line by giving it the same location, direction and a color for us to see in the Scene view.
The RaycastHit2D returns any collision with Colliders in the scene in the hitInfo variable. The ground tiles in the scene all have Colliders, so if the hitInfo.collider is not Null, meaning it detects the ground Colliders and the player is on the ground, we will set _grounded true.
You can see, when the game is started, grounded is true and we can jump, but grounded remains true even the Raycast is not colliding with the ground. The Raycast can detect any Colliders, so we must be hit something and we can figure out what exactly using a debug.
We are going to Log the name of the Collider the Raycast is detecting, so we can determine what Collider it is hitting besides the ground Colliders.
The Collider that is constantly returning a hit is the player’s Collider. This is the reasons _grounded remains true even if the Raycast is not touching the ground.
What we want is the Raycast to only detect things on the Ground Layer of the tilemap.
Creating a Layer
We are going to create a Layer for the Raycast to only detect and we are creating on the Grid > Floor tilemap that houses all of the ground Colliders.
In the Floor tilemap, select Layer and we will add a New Layer.
This will be Layer 8 and we will call it “Ground”.
In the Script, we will create a LayerMask variable, _groundLayer, that will store the Ground Layer 8 and we will Serialize it so we can assign it in the Inspector.
In the Inspector, we will select the Ground layer we created.
Back in the Script with the RaycastHit2D, we can pass in a Layer Int which will only cast on that Layer and we want that to be our _groundLayer.value, which is the Layer 8. This has the Raycast only being casted on the Ground Layer and no other.
We can see that the Raycast is now detecting the Floor Colliders and no longer the player collider.
The next issue is the Raycast still detects the ground even after we have jumped and it takes a double jump to become ungrounded. So, lets shorten the Raycast distance to half a unit.
This shorten the Raycast to the point it no longer detects the ground since Grounded remains false even though we are not jumping. We can try to extend it a bit further so it hits the ground, but once we jump it doesn’t.
The line will be .6 of a unit.
We are now grounded at the start, but we run into the issue as before. We are still detecting the ground even when we jump. This is due to the program running at 60 frames per second, so as we jump the program is drawing the line too fast to avoid the ground.
When the jump happens, we are going to create a jump reset time, to give the program enough time to perform the jump before drawing the the ray to detect the ground.
Lets declare a bool that will let us know that we need to wait some time before drawing the raycast again.
When we jump, we set this bool true.
Then, we can only set _grounded to true when _resetJumpNeeded is false.
This prevent us from double jumping, but since _resetJumpNeeded is never set back to false, we can only jump once.
This is where an IEnumerator comes in handy, because it allow us to create pause of 0.1 second before setting _resetJumpNeeded back to false which will allow the Raycast to detect the ground again.
All we have left to do is Start the Coroutine after the _resetJumpNeeded to true inn the Jumping logic.
In the next article, we will talk about a more optimized way of creating a jump mechanic.