Jump Jump! ๐Build Your Own Mario-Style Platformer
Run, jump, and stomp your way to your very first platform game! You'll make a character who leaps over gaps, bounces on enemies, and collects coins just like Mario!
Run, jump, and stomp your way to your very first platform game! You'll make a character who leaps over gaps, bounces on enemies, and collects coins just like Mario!
Open Godot and get ready to build your first platformer.
We're going to make a REAL platform game like Mario! That means a little character who can run and JUMP over things. By the end, you'll have your very own game that you made yourself. That's amazing! Let's open Godot and get started! ๐
This is Episode 2 of the My First Video Game series, no prior Godot experience is needed. Key concepts over the 12 steps: CharacterBody2D for a physics-based player, move_and_slide() with gravity, StaticBody2D platforms for level design, Camera2D to follow the player, Area2D for collectibles, and a simple group-based enemy stomp. Godot 4 must be installed (free at godotengine.org).
Create a new Godot 4 project called "My Platformer" and get it open.
Godot is like a magic toybox for making games, and it's completely FREE! First, we need to make a new project. Think of it like getting a fresh new notebook just for our game.
Standard Godot 4 project setup. Choose the Compatibility renderer, it's the most stable for 2D beginners and works on all hardware. Point the project folder somewhere easy like the Desktop.
Create a Player scene with a CharacterBody2D for your hero.
Now we build our main character! In Godot, every character is made of pieces called "nodes", like building blocks. The special one we need is called a CharacterBody2D. It knows how to walk and jump!
Node tree: CharacterBody2D (root, rename to "Player") โ Sprite2D + CollisionShape2D (RectangleShape2D, sized to a rough character body ~24ร40px). Use a coloured rectangle or placeholder for the sprite. Save as player.tscn.
Write a script so your character can run left and right using the arrow keys.
Time for some CODE! Don't worry, we'll go slowly. We're going to write instructions that tell our character: "when I press the right arrow key, move that way!" It's like programming your own remote control.
Attach a GDScript to the CharacterBody2D root. This step focuses on horizontal movement only. We use Input.get_axis(), a Godot 4 shorthand that returns -1, 0, or +1. move_and_slide() handles all collision response.
extends CharacterBody2D const SPEED = 220 # How fast we run func _physics_process(delta): # left/right movement, get_axis returns -1, 0 or +1 var direction = Input.get_axis("ui_left", "ui_right") velocity.x = direction * SPEED move_and_slide()
Input.get_axis("ui_left", "ui_right") gives back -1, 0, or +1 depending on the arrow keys.move_and_slide() handles bumping into floors and walls for us.velocity.x = direction * SPEED?Add gravity and a Space-bar jump to your character.
Right now your character floats like they're in space! Let's add gravity, the invisible pull that brings everything back down. Then we'll give them a jump button. Gravity pulls down a tiny bit every single moment, which is why falling starts slow and gets faster.
Gravity is added to velocity.y each physics frame, multiplied by delta so it's frame-rate independent. Jumping sets velocity.y to a negative value in one go. is_on_floor() is only reliable after move_and_slide() has run at least once, which it has by the second frame.
extends CharacterBody2D const SPEED = 220 const JUMP_FORCE = -400 # minus, because UP is negative! const GRAVITY = 1200 func _physics_process(delta): # gravity pulls us down a little bit every moment if not is_on_floor(): velocity.y += GRAVITY * delta # jump, but only if we are standing on something! if Input.is_action_just_pressed("ui_accept") and is_on_floor(): velocity.y = JUMP_FORCE var direction = Input.get_axis("ui_left", "ui_right") velocity.x = direction * SPEED move_and_slide()
JUMP_FORCE a negative number like -400?Build a Level scene with solid ground and floating platforms for your player.
Your character needs a world! We're going to build the ground, then some platforms floating in the air to jump up onto, like the bricks in Mario. Each platform is made of two things: a coloured rectangle you can see, and an invisible solid shape you can land on.
Level scene: Node2D root (save as level.tscn). Each platform is a StaticBody2D with a CollisionShape2D (RectangleShape2D) plus a ColorRect for the visual. Duplicate with Ctrl+D. Instance player.tscn and drop it above the ground. Godot will ask you to pick a main scene the first time you press F5, choose level.tscn.
Add a camera that follows your character.
At the moment your character can run off the edge of the screen and disappear! A camera fixes that. It's like a friend holding a video camera who always keeps you in the middle of the picture. Now your level can be enormous.
A Camera2D added as a child of the Player inherits the parent's transform, so it follows for free with no code at all. Godot 4 makes the first Camera2D in the tree current automatically. Position Smoothing adds a little lag so the camera glides rather than snapping.
Make a coin that disappears when you touch it.
Every platform game needs treasure! A coin is different from a platform: you don't land on it, you walk through it. In Godot that special "notice me but don't block me" node is called an Area2D.
Coin scene: Area2D root + ColorRect + CollisionShape2D (CircleShape2D). Connect the built-in body_entered signal to a script on the coin. The player is added to a group called "player" so the coin can tell the difference between the hero and anything else that wanders in. queue_free() deletes the coin safely at the end of the frame.
var score = 0 just under the const lines. Save.extends Area2D func _on_body_entered(body): # was that the hero, and not a platform or an enemy? if body.is_in_group("player"): body.score += 1 queue_free() # the coin disappears!
body.is_in_group("player") first?Put a coin counter in the corner of the screen that goes up as you collect.
Collecting coins is more fun when you can see the number going up! We'll put some text in the corner. It needs to stay stuck to the screen even when the camera moves, so it goes in a special box called a CanvasLayer.
A CanvasLayer draws its children in screen space, ignoring the camera, which is exactly what a HUD needs. The Level script reads player.score each frame. @onready grabs the node references once the scene tree is ready, and str() converts the number into text.
extends Node2D # grab these two nodes when the scene is ready @onready var player = $Player @onready var score_label = $CanvasLayer/ScoreLabel func _process(delta): score_label.text = "Coins: " + str(player.score)
$Player and $CanvasLayer/ScoreLabel have to be spelled exactly as they appear in the Scene tree, capital letters and all. Great first lesson in why programmers care about spelling!str(player.score) do?Put a flag at the end of the level that shows a "You Win!" message when the player reaches it.
A game needs a way to win! We'll pop a flag at the far end of your level. When your character touches it, big letters appear saying You Win, and everything stops. That's your level finished, properly finished.
The Goal is another Area2D using the same body_entered pattern as the coin, so this step reinforces rather than introduces. It reveals a hidden Label and sets get_tree().paused = true. Rendering carries on while paused, so the message stays on screen.
extends Area2D func _on_body_entered(body): if body.is_in_group("player"): # show the message FIRST, then freeze the game get_node("../CanvasLayer/WinLabel").visible = true get_tree().paused = true
get_tree().paused = true makes the game run faster.Make a patrolling enemy you defeat by jumping on top of it.
Time for a baddie! It marches left and right on its own. Here's the clever bit: the enemy works out how you touched it. If you were falling downwards, you squashed it. If you weren't, it got you, and you go back to the start.
The stomp check is body.velocity.y > 0, meaning the player was moving downwards at the moment of contact. Remember y grows downwards, so falling is positive. We also add a respawn() function to the Player, its first custom function, and a lovely introduction to the idea that objects can be asked to do things.
start_pos variable and the respawn() function shown below. Save.# ADD THESE to your Player script var start_pos = Vector2.ZERO func _ready(): start_pos = position func respawn(): position = start_pos velocity = Vector2.ZERO
# The Enemy script extends Area2D const SPEED = 60 var direction = 1 var start_x = 0.0 func _ready(): start_x = position.x func _process(delta): position.x += direction * SPEED * delta # turn around after walking 80 pixels each way if position.x > start_x + 80: direction = -1 if position.x < start_x - 80: direction = 1 func _on_body_entered(body): if body.is_in_group("player"): if body.velocity.y > 0: # falling downwards, that's a stomp! queue_free() body.velocity.y = -300 # little bounce else: body.respawn()
Design and tune your own level using everything you've built.
You have all the pieces now: platforms, coins, a baddie and a flag. This step is the fun one, you're the level designer! Build a journey from the start to the flag. Make some coins easy and some really tricky to reach.
This is the playtesting step, and it's where the real learning lands. Encourage changing one number at a time (GRAVITY, JUMP_FORCE, SPEED) and playing after each change. That change-test-change loop is genuinely how professionals tune game feel.
A side-scrolling platform game just like Mario or Sonic! Your character runs left and right, jumps over gaps, lands on platforms, and tries to reach the end of the level.
Have you ever played Mario? We're going to make our VERY OWN version! You'll build a little character who can jump, collect coins, and even stomp baddies. You're going to be a real game developer!
This is Episode 2 of the My First Video Game series, no prior Godot experience needed (start with Episode 1: Zoom Zoom if you're brand new!). New concepts introduced: CharacterBody2D, gravity & jumping, StaticBody2D platforms, Camera2D, Area2D for coins, goals and enemies, groups, and writing your first custom function. We keep code ultra-short and friendly.
This workshop was free and took many hours to build. If it helped you learn something new, consider supporting the project.
☕ Support on Ko-fi๐ Free In-House Dev Tools
Use these free browser tools alongside this workshop to create custom sprites, sounds, levels and colour schemes for your game. No installs. Free forever.
Design your platformer sprites!
Use Pixel Studio to draw your hero, coins, and platforms - make your jump game look amazing!
Drag the JavaScript game steps into the correct order: