◀ 6.36.46.5 ▶

6.4 — Boots: Double Jump

The potion raised a number that already had a ceiling. The boots change something else entirely: they change what your level design is allowed to ask for. One pickup that grants a second jump in mid-air rewrites every gap in the cave — including the gaps you have not built yet. Your goal: a character that can jump a second time in the air, but only after picking up a pair of boots.

In this lesson you will be able to answer“how do I make a double jump?”Outline only
Break It Down~10 minOutline only

Tap the key in mid-air and jump a second time — but only while you are carrying the boots. As one problem it is not startable, because the question your jump has been asking since 6.2 ("am I standing on something?") has a false answer in exactly the situation the second jump happens in.

First, before any code: cut that into parts small enough that you could look each one up on its own.

  1. Count the jumps you have leftwhat does this part do?Read: 2.1 — Coins: Triggers, Tags & Your First Stat: the count field you declared in the class body, and the rule that state which has to survive a frame belongs to the object
  2. Spend one at the instant the jump fireswhat does this part do?Read: the "spend rule" you wrote for the coyote window in 6.3 — jump and the window is gone — and the jump line itself in 6.1
  3. Give it back the moment you land, in the one place the ground check already runswhat does this part do?Read: 6.2 — Ground Checks: No Infinite Jumps: the check itself, and the rule from 6.3 that it is computed in exactly one place
  4. Let the jump condition ask about the counterwhat does this part do?Read: the compound condition you wrote in 6.2 and the grace window you added to it in 6.3
  5. Build the pickup that changes the numberwhat does this part do?Read: 2.1 — Coins: Triggers, Tags & Your First Stat (tag, trigger, callback, destroy) and 2.3 — Healing Pickups & the Max-Health Cap (the pickup that moves a ceiling)
  6. Put the boots where the level can ask for themwhat does this part do?Read: the prefab-versus-instance rule and the placement work in 2.1, and the playtest habits from 2.4

Five of those six parts are things you have already built, and the sixth is arithmetic on a number. What is genuinely new is small enough to miss: a jump is now legal in the one situation where the ground check says no, so the ground check stops being the whole answer and becomes one term in a question about how many. Choosing the field that matches that question — instead of re-arranging a boolean until it fits — is the whole lesson. The code is four lines; the decision is the work.

The test for a finished split: does the part name something you could point at — a field, a line, a branch, an object in the Hierarchy? "Make a double jump" points at nothing. "Where the counter goes back up" points at one branch of one method, and that is a part.

Your turn

Pick two of the parts above and say in one line what each one actually does.

The counter and the maximum are two fields. Which one belongs in the Inspector and which one stays private? Say what a designer can do to your game with each of those two answers.

There is exactly one moment in the whole game where the count should go back up. Name it before you read on — and say what goes wrong the day it gets decided in two places.

In the Editor ~25 min
  1. Edit → Project Settings → Tags and Layers → add a tag called Boots. Read the list while you are in there: it ships six tags, and every one is a name somebody has to remember.
  2. Hierarchy → right-click → 2D Object → Sprites → Square, and rename it Boots. Then Project window → Assets/Artwork, pick a sprite you are not using, and drop it into Inspector → Sprite Renderer → Sprite. There is no boots art anywhere in this project — no file matching boot, no prefab — so tint it with Sprite Renderer → Color until it could not be mistaken for a coin. That is greyboxing, and it is what 2.3 did for the potion.
  3. Inspector → Add Component → Box Collider 2D. Decide whether Is Trigger is ticked before you leave this step, and be ready to defend the answer: a solid pair of boots is something you trip over, and your player already carries the Dynamic body a trigger pair needs.
  4. Inspector → Tag → Boots. Then Project window → drag the object out of the Hierarchy and into Assets/Prefabs: it is a prefab now, and the copy still standing in the cave is an instance of it.
  5. Scene view → move that instance somewhere a tester has to walk. Then Project window → Assets/Prefabs → drag Coin into the Hierarchy, and Scene view → put it on a ledge one jump cannot reach.
  6. Game view → press Play twice — once straight at the coin, once after collecting the boots — and time how long a tester needs to work out what the boots are for. Then GitHub Desktop → commit.
Test the whole loop, including death. Grab the boots, then die on purpose. If your death rule from 2.2 reloads the scene, the Player is rebuilt from the prefab — so where do the boots go, and where does the maximum go? Write down what you observe, then say which of the two has to change: the death rule, or where the boots live.
In the Code ~30 min

This is the level-3 substitute for a walkthrough: the API is laid out below and the code is not. You write the file. Every row is a call or a declaration you have already typed in 6.1, 6.2, 6.3 or 2.1 — read the cost column before you pick.

APIWhat you getWhat it costs
[SerializeField] private int A class-body field — the declaration form from 1.3, visible in the Inspector and still there on the next frame. This is the counter; a second one beside it holds the maximum. Its starting value is a design decision rather than a formality, so the type has to match the question: an int cannot say "maybe", and a bool cannot say "two left".
jumpsLeft = jumpsLeft - 1; An assignment to a field that already exists — no type in front of the name, the declare-versus-assign rule from 1.3, and the line 2.1 warned about. Write the type in front and you declare a brand-new local that dies at the end of the frame, leaving the counter at its old value on every jump.
Rigidbody2D.linearVelocity The body's velocity, and the Unity 6 spelling of it. It is the property 6.1 used to overwrite the vertical half and keep the horizontal — and older tutorials, written for earlier Unity versions, call it something else. Setting the whole vector erases the half you did not mean to touch.
AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse) The flick from 6.1 — one instant change in momentum, which physics then spends over the following frames. It divides by mass, so retuning mass silently retunes both jumps.
OnTriggerEnter2D(Collider2D other) and other.CompareTag("Boots") The pickup callback and the tag check you have had since 2.1 — one branch more in a method that already handles the coin and the potion. It fires once per entry, and only if the tag exists in the project — which is why creating it is the first step above.
other.gameObject and Destroy(Object) The whole object behind the collider you just touched, and the call that removes it at the end of the frame. Plain gameObject is you, and getting the two backwards destroys the player. Destroy(Object) is also deferred, so the object is alive for the rest of the frame.
Architectural specification: the jump allowance.
  • What is the maximum's default value in a build where the player has no boots? Say it out loud, then check that the field in the Inspector agrees with what you said.
  • Where exactly does the counter reset — is that one line nested inside the ground check you wrote in 6.2?
  • What does the new jump condition say in English — the ground or coyote logic from 6.3 and a comparison on the counter? Write the sentence before you translate it.
  • What do you do to the counter at the instant the jump fires? Skip that line and the player has an unlimited supply.
Architectural specification: the second jump.
  • Read your own jump line from 6.1 rather than guessing: does it replace the vertical velocity or add to it? Then predict a second jump fired while you are still rising, and say which of the two you would rather design levels around.
  • If that is not the one you wanted, what is the smallest change that gets you the other — and does it break the first jump?
  • Whichever you choose, the second jump now needs to know which jump it is. Which line of your code already knows?
Architectural specification: the pickup branch.
  • Which callback fires when the player touches the boots — the trigger one or the collision one? The answer depends on the collider setting you chose in the editor half, and it changes the parameter type you are handed.
  • How do you identify the boots from inside that callback, and how do you reach the object that should disappear?
  • What does the branch change on the player — the maximum, or the count? Justify the choice you made on paper, and say what the other would have felt like to a player who finds a second pair.
  • What do you hand to Debug.Log(string message) so a tester can see the change with no UI in the game?

Deploy in neutral first. Add the counter and the reset, and leave the maximum at its default: the character should play exactly as it did before, one jump and nothing new. Change the maximum only once that is true — a wrong counter is easier to find before the pickup exists.

Socratic: Choosing the Data

  1. Where does the jump allowance live — on the player, on the boots, or on a manager? Your answer should sound like the one you gave in 2.1, and for the same reason.
  2. What type is the counter, and what is its starting value in a game with no boots? What does the field default mean to a designer who has never read your code?
  3. Is the reset "when I land" or "when I touch a ground-layer collider"? Are those two statements the same thing in your build?

Checkpoint — before moving on, you must be able to:

Reference Docs

Need a deeper explanation? These pages cover the same concepts:

Next: 6.5 — Platforming Studio: The Gauntlet, where every one of these skills has to survive a stranger.

0/6 answered

Answers save on this device as you type. At the end of class, click Download and upload the file to the Canvas assignment.

Saved on this device only — the Dashboard tracks your progress.