6.1 — Gravity & Jump: The First Flick
The cave is the first place in this game where down means something. Walk off the edge of the floor and you do not fall — you keep walking, level. Today you turn gravity back on for one scene, and use the same body to throw the character into the air.
The character falls, and then it jumps. "Make the player jump" is really two mechanisms wearing one name: a world that pulls you down, and one instant where the body is handed an upward velocity that the pulling-down then spends. Neither half exists in the cave today, and the same prefab must keep NOT falling in the world you built it for.
First, before any code: cut that into parts small enough that you could look each one up on its own.
- Give the Player a body that falls in this sceneBody Type Dynamic and Gravity Scale above zero - it takes both. Gravity Scale multiplies the project gravity Physics 2D has at
-9.81on Y. Your body has been Dynamic with Gravity Scale 0 since 2.1.Read: therb.gravityScalerow of the quick reference. - Tell the script which world it woke up inThe same prefab is played in both worlds, so "am I in the cave?" is a fact about the scene: one serialized
bool, ticked on the cave copy and left alone on the Overworld copy - thehasAxeshape from 5.1, pointed at the world.Read: the[SerializeField] private boolrow in the quick reference. - Turn gravity on once, when the scene loadsA gated write in
Start(): if the flag is on, hand the body a gravity scale. Once, before the first frame - inUpdate()the same number is written sixty times a second.Read: thevoid Start()row of the quick reference. - Notice one press of the jump key
Input.GetKeyDown(KeyCode.Space)inside theUpdate()you have been adding to since 1.4. True on the single frame the key goes down;GetKeyis true on every frame it is held - a jump is a moment, not a state.Read: theInput.GetKeyDown(KeyCode.Space)row of the quick reference. - Hand the body one upward flick, and let gravity spend it
AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse): one instant change in momentum. The height is the impulse divided by mass, the rise is paid for by the gravity from part 1, and the apex is the frame the vertical velocity reaches zero.Read: therb.AddForce(... ForceMode2D.Impulse)row of the quick reference.
Three of those five parts are work you have already done: a Dynamic body is 2.1, a serialized slot is 1.3 and 5.1, a once-only write in Start() is 3.3. The other two have no precedent, which is why this lesson walks every line.
The test: could you look this part up on its own, right now, in one search? "Make the player jump" cannot be looked up - there is no such API. "Push a rigidbody upward once" can.
Your turn
The flag in part 2 is the first thing you have ever stored about the world rather than about the player. Name one other fact about the scene in your game, and say where you would keep it.
Part 4 notices a key press; part 5 moves the body. Nothing in the file measures time, and yet the arc has a height. Where does the height come from - and which part would you change first if the jump felt wrong?
-
Project window → open
Assets/_Scenes/Platformer.unity— the cave — then Game view → press Play and walk off the edge of the floor. Nothing falls, and that is not a bug: the Rigidbody2D you gave the Player in 2.1 has Gravity Scale 0, because a top-down character who obeys gravity falls through the world forever. You were right then. The cave is the first place where you are wrong. -
Hierarchy → select the Player, then
Inspector → Rigidbody2D → Gravity Scale. Set it to
1while the game is running and watch the character drop. Then try0.2and describe the difference out loud. -
Game view → stop Play, then Inspector → Gravity Scale:
it is back to
0. Inspector edits made during Play are thrown away on Stop (1.2) — which is why the cave's gravity has to end up in code. -
Hierarchy → open the
Overworldscene — the top-down hub — select its Player, and set Inspector → Gravity Scale to1. Game view → press Play: you have just broken the hub. Write down what it cost, then set it back to0. - Hierarchy → back in the cave, select the Player and read Inspector → Player Controller. There is a leftover override called Is Platformer that no field in your script matches yet. Leave it — step 1 of the walkthrough below is about it.
-
Once the walkthrough is done — Hierarchy → the Player standing in the
cave, Inspector → Player Controller → Is Platformer, and tick
it. Confirm the
Overworld's copy is unticked, then Game view → press Play in both: the cave falls, the hub does not.
Two lookups and two decisions: what the Rigidbody2D offers, and the four ways a body can leave the ground.
| Field on the Rigidbody2D | What it actually does |
|---|---|
Body Type |
Dynamic bodies fall and are pushed. Kinematic bodies move only where code puts them, and ignore gravity, forces and mass entirely — if your character stands still in mid-air with Gravity Scale 5, look here first. |
Gravity Scale |
A multiplier on the project-wide gravity (Project Settings, Physics 2D, Y at -9.81). 0 is off, 1 is undiluted. Means nothing on a Kinematic body. |
Mass |
How much the same force moves you. Gravity pulls harder on a heavy body, so mass cancels out in a fall — but a force you apply by hand divides by mass. |
Constraints |
Freeze Rotation Z, set in 2.2 so the character stops tumbling. It matters in the air too: an unfrozen body spins when it clips a corner mid-jump. |
| Technique | What it requires | What it costs |
|---|---|---|
AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse) |
A Dynamic body and Gravity Scale above 0. | Mass divides into it, so retuning mass silently retunes every jump. Clean parabola — the row the walkthrough builds. |
linearVelocity = new Vector2(x, jumpSpeed) |
A Dynamic body and Gravity Scale above 0. | Identical height every time, to the pixel — and it erases whatever vertical motion was already there: a platform's lift, a knockback, a bounce. |
AddForce(Vector2.up * thrust, ForceMode2D.Force) every frame while held |
A Dynamic body; some rule that stops it — fuel, ceiling, timer. | A rocket, not a jump. Height depends on how long you hold — and this is what you get by accident if you forget the force mode. |
MovePosition() in steps |
A Kinematic body, moved in FixedUpdate(). |
It ignores gravity, so it never falls, and it only collides with Dynamic bodies — so no floor is solid to it, and no OnCollisionEnter2D(Collision2D collision) fires against those static colliders. The cave door runs on that callback and would go silent. |
- (a) Ask the scene its name —
SceneManager.GetActiveScene().nameagainst"Platformer". Readable; breaks silently if someone renames the scene. - (b) Ask the scene its build index — the cave is index 2. Survives a rename; lies when the build order changes.
SceneSwitch.csalready does this. - (c) A serialized bool, ticked per scene instance — visible in the Inspector without pressing Play. Costs a tick on every new Player somebody places.
- (d) A component that only exists on the cave's Player — the component's presence is the flag. Costs one more file and one more lookup.
- Whatever you pick, reuse a scene-mode flag you already built this year: two flags meaning "which world am I in" is how a project starts rotting.
- Where does the cave's gravity get turned on? Name the exact point in the lifecycle — a field default,
Start(), or every frame — and say what breaks at the other two. - Which key, and which of
GetKeyorGetKeyDown? Say what holding the key for two seconds does under each. - Is your jump force a serialized field or a magic number? Does its name say force or speed — and what does the name make the next reader believe?
- How do you know the jump worked? Name what you would print, and what it proves.
Socratic: Gravity Is a Number You Own
- Real gravity is a constant of the universe. Unity ships it as an Inspector field. Why would an engine make a law of physics editable per object?
- Same Player prefab, same script, two worlds: the hub needs Gravity Scale 0 and the cave needs it above 0. Where should that difference live — the script, the scene, or both?
- A Kinematic body ignores gravity, forces and mass entirely. Set Body Type to Kinematic in the cave, and what would your jump code have to do instead to look like a jump?
The question this answers“how does my script know it is in the cave?”
You are editing Assets/Scripts/PlayerController.cs. The cave and the Overworld play the same prefab, so "which world am I in" cannot live on the prefab: it is a fact about the scene, and it has to reach the script before the first frame runs. One field, one gate, one line.
Step 1Declare the flag, and get its starting value right
One field, in the class body beside moveSpeed - the [SerializeField] private pattern from 1.3, in the exact shape of hasAxe from 5.1.
[SerializeField] private bool isPlatformer = false;- 1Which world this Player woke up in.
falseis the default, so a Player in any scene nobody has ticked keeps the top-down behaviour it has had since 2.1.The name is not free, and you can check why. Click the cave's Player and look atPlayerController: the scene has carried an override calledisPlatformersince before this course existed - a leftover from the version of this script that shipped with the project. Unity stores overrides by field name, so this spelling picks the tick back up whereinCavewould lose it. Check the box either way.
Step 2Hand the body a gravity scale, once, and only in this world
The body lookup you have had in Start() since 2.2 is unchanged. What is new is one line underneath it, wrapped in the flag.
body = GetComponent<Rigidbody2D>();
if (isPlatformer)
{
body.gravityScale = 1f;
}- 1The reference you already cache here - the body about to be given a gravity scale. It sits on the same GameObject as this script, which is why the plain lookup finds it.
- 3The gate. Read it as "if this Player is standing in the cave". It is the only thing separating the two worlds.Read once, in a method that runs once.
Start()is the once-only setup method from 1.3, and a fact about the scene belongs there. - 5The whole of turning gravity on.
body.gravityScaleis the Rigidbody2D property behind the Inspector field you have been reading all year, and1fmeans "the project gravity, undiluted".Why this is code and not a number in the Inspector. You could set the cave copy to 1 by hand and write nothing - but that number is invisible to a reader of your script and has to be repeated on every new Player anyone places.
Check your work: the finished filebuild it as you read — then open this to check every line
Compare against your own file rather than copying it. The walkthrough wrote an if that only touches the cave; this version decides the number for both worlds in one ternary - the same behaviour and a different argument: "the Overworld keeps 0 because I said so" rather than "because I never mentioned it". Both are right; pick the one you can defend.
// ------------------------------------------------------------------
// REFERENCE FILE — Assets/Scripts/PlayerController.cs
// Written to be read, not pasted. Build it with the walkthrough
// above, one step at a time, then open this and compare.
// If it is sitting in your project unchanged, that is the thing
// to go and do now — the walkthrough is still above you.
// ------------------------------------------------------------------
using UnityEngine;
// PlayerController.cs - the gravity half, complete. Everything from 1.4 to 5.3
// (input, movement, animation, coins, health) stays exactly as you wrote it;
// the flag and the one line under it are the whole of what is new.
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f; // your number from 2.2
[SerializeField] private bool isPlatformer = false; // which world did I wake up in?
private Rigidbody2D body;
void Start()
{
body = GetComponent<Rigidbody2D>(); // looked up once, per 2.2
// Decided once, for both worlds. The Overworld's 0 is written here
// rather than inherited from the prefab, so the decision is visible
// to anyone reading this file instead of only to the Inspector.
body.gravityScale = isPlatformer ? 1f : 0f;
}
void Update()
{
// ... the input, movement and animation lines from 1.4, 1.6, 2.2 and 5.3 ...
}
}The question this answers“how do I make the character leave the ground?”
You are editing Assets/Scripts/PlayerController.cs. There is no Jump() in Unity, and nobody is going to give you one. The gravity half is already in your file, so what is left is a number to tune, a key check, one push, and a way to see that it worked. The push is where every mistake in this lesson happens.
Step 1Declare how hard the flick is
One field, in the class body next to moveSpeed - and one for the same reason: it is a number a designer tunes, not a number you type into a condition.
[SerializeField] private float jumpForce = 7f;- 1How hard the flick is. Named
jumpForcebecause that is what it becomes - a force - so no reader mistakes it for the speed the character leaves the ground at.A starting guess, not a value. The number that makes a jump feel right is found in the tuning lab at the bottom of this page. And a force is divided by mass before it becomes motion, so the height7fbuys you depends on the mass the Inspector shows.
Step 2Notice the press, once, at the bottom of Update()
Four lines at the end of the Update() you have been adding to since 1.4 - after your movement and animation lines, beside the key check you wrote for the lever in 5.2.
if (Input.GetKeyDown(KeyCode.Space))
{
body.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}- 1
Inputis the class from 1.4,KeyCode.Spacenames the key, andGetKeyDownis true on the single frame the key goes down.Input.GetKey(KeyCode.Space)here is the wrong one, and it fails in the loudest way there is. Without theDownit is true on every frame the key is held, so half a second of holding Space applies thirty pushes and the character leaves the top of the level. The jump looks broken; the condition is. And the check belongs inUpdate():FixedUpdate()is the physics clock, which can run several times in one frame or skip frames, so a one-frame press can be counted twice or missed. - 3The flick.
Vector2.upis(0, 1)- straight up - scaled by the field from step 1. Read the call as a sentence: add a force, upward, of this size, as an impulse.The second argument is the whole lesson, and leaving it out is the classic bug. WithForceMode2D.Impulsethis is one hit, spent at the next physics step. Without it the default is a push that keeps applying while the calls keep coming - and since this line sits inside a check true on exactly one frame, you get a dribble so small the character twitches and settles. Nothing errors, nothing warns, and "my jump does nothing" is what you write in the group chat. Calling it fromUpdate()is fine, though: the engine queues forces and spends them on its own clock.
Step 3Prove the arc in the Console, then take the proof out
There is no UI for vertical velocity, so the Console is your instrument. One temporary print, at the bottom of Update() where every frame runs.
Debug.Log("v.y = " + body.linearVelocity.y);
// Delete the print before you move on- 1At the bottom of
Update(), outside the key block, with no condition on it.body.linearVelocityis the movement method you chose in 2.2, read instead of written, and.yis the half a jump cares about.That number is the parabola. It jumps to a peak when you press Space, shrinks as gravity takes it back, crosses zero at the top of the arc, and grows negative all the way down. The whole mathematics of a jump, watched rather than written: the apex is not a place in your code, it is the frame this number passes through nothing. - 2An instrument, not a feature. A print left here fills the Console with a thousand lines a minute and buries the next real error under them.
Check your work: the finished filebuild it as you read — then open this to check every line
Compare against your own file rather than copying it. Two differences are worth naming, and neither is a mistake. First the shape: the walkthrough wrote the push inline inside the key check, and this file gives it a method called Jump() - the same line, with a name you can point at when 6.2 and 6.3 start asking what a jump is allowed to do. Second the gravity line: this file decides the number for both worlds with a ternary where the walkthrough only wrote it for one. Your key, your number and the names of your own methods are yours.
// ------------------------------------------------------------------
// REFERENCE FILE — Assets/Scripts/PlayerController.cs
// Written to be read, not pasted. Build it with the walkthrough
// above, one step at a time, then open this and compare.
// If it is sitting in your project unchanged, that is the thing
// to go and do now — the walkthrough is still above you.
// ------------------------------------------------------------------
using UnityEngine;
// PlayerController.cs - gravity for the cave, and one flick upward.
// The gravity half came first; the jump assumes it. Up, apex, down: the
// only line that makes the arc is the force, and gravity does the rest.
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f; // your number from 2.2
[SerializeField] private float jumpForce = 7f; // how hard the flick is
[SerializeField] private bool isPlatformer = false; // which world did I wake up in?
private Rigidbody2D body;
void Start()
{
// Looked up once, never inside Update() - the rule from 2.2.
body = GetComponent<Rigidbody2D>();
// Decided once, for both worlds.
body.gravityScale = isPlatformer ? 1f : 0f;
}
void Update()
{
// ... input, movement and animation, from 1.4 to 5.3 ...
if (Input.GetKeyDown(KeyCode.Space))
{
Jump();
}
}
// The whole jump. One impulse, and gravity spends it over the next half
// second - which is why there is nothing here about coming back down.
private void Jump()
{
body.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}
}Change one number at a time and write one sentence of feel for each, in a file you keep. Three knobs, and the third one is the interesting one.
| Knob | Try |
|---|---|
jumpForce — Inspector → Player Controller | half, then double |
Gravity Scale — Inspector → Rigidbody2D | 0.2, then 1, then 4 |
Mass — Inspector → Rigidbody2D | 1, then 5 — watch the jump and the fall |
Checkpoint — before moving on, you must be able to:
- Explain Gravity Scale, Body Type and Mass as three separate ideas, not one
- Say where the cave's gravity gets turned on, and prove the top-down world still works
- Compare the four ways to leave the ground and defend the one you wrote
- Explain Force versus Impulse in feel-words, and the parabola gravity spends
- Commit and push
Reference Docs
Need a deeper explanation? These pages cover the same concepts:
- Unit 6: Jumping — the flick, the tuning triangle and the parabola in depth
- Unity + C# Quick Reference — Rigidbody2D, AddForce() with a force mode, and Body Type
- How do I…? index — find this lesson again by the question you were asking
Next: 6.2 — Ground Checks: No Infinite Jumps, where you discover that your jump works perfectly in mid-air too.
Saved on this device only — the Dashboard tracks your progress.