๐ŸŽฎ Summer Coding Quest
Week 1 ยท Day 4

Gravity & Jumping

Make your player fall properly, land on the ground, and leap into the air.

โฑ About 45โ€“60 minutes
๐ŸŽฏ Today's mission Two things, Raviv: make the ground solid so the player can stand on it, then add gravity and a jump. By the end you'll be bouncing your box around like a real platformer.

What you'll learn

Part 1 โ€” Make the floor solid

Right now the ground is only something you can see, not something you can stand on. The player would fall straight through it. Let's give it a real surface.

  1. Select the Ground

    Click your Ground node (the MeshInstance3D with the PlaneMesh).
  2. Use the Mesh helper

    Look at the toolbar across the top of the 3D viewport. Click the Mesh menu that appears there, then choose Create Trimesh Static Body.
  3. Done โ€” check it worked

    A new StaticBody3D (with a collision shape inside) appears under your Ground in the Scene panel. That's Godot building a solid, invisible surface that exactly matches the floor you can see. No typing required!
๐Ÿ’ก Static vs Character body A StaticBody3D is something solid that never moves on its own โ€” floors, walls, rocks. A CharacterBody3D (your player) is something solid that does move. They can bump into each other, which is exactly what makes the player land on the floor instead of falling forever.

Part 2 โ€” Add gravity and jumping

  1. Open the Player script

    Double-click the script icon next to your Player node.
  2. Replace it with this

    It builds on yesterday's code โ€” there are three new variables at the top and two new blocks. Every new bit is explained below.
    extends CharacterBody3D
    
    var speed = 5.0
    var jump_force = 8.0
    var gravity = 20.0
    
    
    func _physics_process(delta):
    	# 1. Pull the player down when they're in the air
    	if not is_on_floor():
    		velocity.y -= gravity * delta
    
    	# 2. Jump, but only when standing on the ground
    	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
    		velocity.y = jump_force
    
    	# 3. Left / right / forward / back (same as yesterday)
    	var direction = Vector3.ZERO
    	if Input.is_action_pressed("ui_up"):
    		direction.z -= 1
    	if Input.is_action_pressed("ui_down"):
    		direction.z += 1
    	if Input.is_action_pressed("ui_left"):
    		direction.x -= 1
    	if Input.is_action_pressed("ui_right"):
    		direction.x += 1
    
    	velocity.x = direction.x * speed
    	velocity.z = direction.z * speed
    	move_and_slide()
  3. Run it

    Press F5. Move with the arrows, and press Space (or Enter) to jump. You leap up, gravity pulls you back, and you land on the floor. ๐Ÿฆ˜
โœ… You did it! Falling, landing and jumping are the foundation of a huge number of games. Your little box now obeys the laws of physics โ€” that you wrote.

Understand it โ€” line by line

The three new variables

jump_force is how hard the player launches upward; gravity is how hard they get pulled down. Both are just numbers you can tweak. Keeping them at the top, named clearly, means you can balance the feel of your game without hunting through the code.

if not is_on_floor(): velocity.y -= gravity * delta

is_on_floor() is a built-in question that answers true or false: "am I standing on something solid?". not flips it, so this reads "if I'm NOT on the floor, pull me down". We lower velocity.y (the up/down part of velocity) a little every frame, so the player falls faster and faster โ€” exactly like real gravity.

๐Ÿ’ก Why "* delta"? This is important delta is the tiny slice of time since the last frame. Multiplying by it means the player falls the same real-world speed whether the game runs at 30 or 240 frames a second. Without * delta, your game would feel different on different computers. Rule of thumb: anything that should happen "per second" gets multiplied by delta.

is_action_just_pressed("ui_accept")

Notice it's just_pressed, not is_pressed. "Just pressed" is true for a single frame โ€” the exact moment you tap the key. That's perfect for jumping: you want one jump per press. If we used "is pressed" (held), the player would rocket upward as long as you held the key. Try it as the experiment below and you'll see why this matters.

We also check and is_on_floor() so you can only jump from the ground โ€” no mid-air double jumps (yet!).

Why velocity.x and velocity.z separately?

Yesterday we set the whole velocity at once. We can't do that today, because gravity is busy controlling velocity.y. So we only touch the left/right part (.x) and forward/back part (.z), and leave .y for gravity and jumping to manage. Three numbers, three different jobs.

Play around โ€” level up ๐ŸŽฎ

๐ŸŸข Level 1 โ€” Easy Make the player jump like they're on the Moon: lower gravity to 5.0. Then make it feel heavy: try 40.0. Find a gravity you like.
๐ŸŸก Level 2 โ€” Medium Crank jump_force up to 15.0 for a super-jump. Combine a low gravity with a high jump force โ€” what kind of game would that feel like?
๐Ÿ”ด Level 3 โ€” Spicy Add a double-jump. Make a variable var jumps_left = 2. When you jump, do jumps_left -= 1 and allow jumping while jumps_left > 0 (instead of only is_on_floor()). Reset jumps_left = 2 whenever is_on_floor() is true. Trickier โ€” give it a go!
๐Ÿ”ฌ Experiment: the rocket bug Change is_action_just_pressed to is_action_pressed for the jump. Run it and hold Space โ€” you fly straight up forever! Now you can see the difference between "just pressed" (one tap) and "pressed" (held). Change it back when you're done laughing.

If something went wrong

"The player falls through the floor." The ground has no collision. Go back to Part 1: select Ground โ†’ Mesh menu โ†’ Create Trimesh Static Body.

"I can't jump." You can only jump while on the floor. Make sure you've landed first. Also check the jump line uses ui_accept (Space/Enter).

"The player sinks slowly into the ground." Make sure your Player has a CollisionShape3D with a BoxShape3D (from Day 3) and its Position Y is 1 at the start.

"Jump only works sometimes." That's the single-frame timing of just_pressed โ€” tap the key deliberately rather than feathering it. It's working correctly.

Tomorrow: a camera that follows you around, plus we pull all of Week 1 together into a little arena. ๐ŸŸ๏ธ

Previousโ† Day 3 โ€” Make it move