Before you start! Take a look at the existing project setup and code, try it out and make sure (1) it works and (2) you understand it. It's mostly bringing over things we've already done, but there are a few new things:
As a quick exercise, update the input controls callback to set direction to a new Vector2 with only the horizontal component of the input. Since different controller types might send a range of values 0.0f - 1.0f, normalize the resulting vector.
In this stage, you will implement gravity and basic platform collision. Your character will fall under gravity, stop when hitting platforms, and only allow movement when grounded.
To get started, just try adding gravity. Integrate a constant downward acceleration vector every frame to add more and more downward velocity to the player entity. The formula to update velocity from acceleration is the same as the formula to update position from velocity.
Here is the complete algorithm (with the existing code in it) to implement this Stage. Ignore the "user input" line as we've upgraded that to the new input system callbacks. Note that we have two different cases to deal with - behavior in the air and behavior on the ground. Splitting entity behavior up into states like this, controlled by a condition, is a key pattern in game code.
Implementation details below.
You'll need to implement ground checking using Unity's raycast system to detect when your character is touching a platform.
To use raycast, you need to first set up the Ground/Platform entities:
BoxCollider2D
components to the Ground and Platform entities in the sceneIs Trigger
box
Once those steps are complete, you can put in the code to do the raycast and note whether the Player character is grounded or not.
Raycast down from the player to find the closest Platform/Ground:
layerMask
SELF_EXTENTS
to calculate where the bottom of the sprite is)RaycastHit2D
object (doc here: https://docs.unity3d.com/ScriptReference/RaycastHit2D.html)
collider
is null, no hitdistance
is very small (like 0.001f), meaning it's right there under youUsing the results of the ground check raycast you can complete the algorithm given above.
In this stage, you will implement smooth player movement and jumping mechanics. The player will have acceleration-based movement instead of instant velocity changes.
To implement acceleration-based player movement, replace the line that sets constant velocity based on user input (in the grounded branch) with this algorithm:
Jumping applies vertical force to the entity, resulting in vertical acceleration. However, in almost all cases a simpler model called impulse is sufficient. Impulse means that we apply instantaneous velocity to the object. This is how we were doing movementt, what we did with collision, and how you do jumping, knockback, and any other sudden movement.
When the player hits the jump key, immediately add some JUMP_SPEED constant to the velocity.y
component and the player will start moving upward. That will switch
them to the non-grounded state and acceleration due to gravity will kick in to bring them back down in a nice, familiar hyperbolic arc. Be sure to leave horizonal
velocity alone so that they don't stop on a dime and jump straight up.
The input system callback for jump is already in place. In the callback, set a boolean to let you know in the next FixedUpdate that you should make them jump. Make sure they can only jump when grounded and that you clear the jump boolean so that they don't keep jumping (or immediately jump back up when they land).
In this stage, you will implement full collision response to prevent overlaps with platforms. Your character will no longer sink into platforms or walk through them.
Unity's collision system efficiently checks for overlaps in the colliders on all entities that are hooked into the system. To enable collision checks for our Player entity,
add a Rigidbody2D
component and set the Body Type
to Kinematic
. This tells Unity to perform collision detection, but not collision
response. We are still controlling what happens after the collision is detected.
Now add BoxCollider2D
components to the Player and to the platform and ground prefabs.
With the rigidbody in place, Unity checks for overlap between the Player collider and any trigger collider on any other entity. If detected, it will call
the method OnTriggerStay2D
on all components that implement it on whichever entity in the collision has the rigidbody (which could be both).
The argument to the callback is the collider component from the other entity, so that you know what you hit.
Add the following method to your PlatformPlayer
script to respond to collisions by moving the Player entity out of overlap.
Add more platforms and test out the code. In the collision response algorithm above, shorter overlap distance is used as an approximation for collision response. This approximation creates an edge case where it can fail to identify whether you hit the side or the top of the platform. If you jump at the corners enough, you can trigger it, and this would be unacceptable to your players.
Draw out the different cases of hitting the top vs. side of the platform and implement a better strategy to detect which part of the platform the player hit.