Let’s recreate Super Mario World, from scratch, in the Godot game engine! I’m going to reverse-engineer the original game, and go into ridiculous detail about it, and then, well, forwards-engineer it in Godot! Hi there!
I’m wye, and I want to make games! And for my first warmup project, just to gain some experience with the engine, I’ve decided to recreate the SNES classic Super Mario World. But why that one, of all games?
Why not start off with a simple game like Pong, or Snake, or a Flappy Bird clone? For one thing, I’m very familiar with Super Mario World, and I’m more invested in it than in Flappy Bird. And for another thing, I think I can handle a more complex project, because I do have some grasp on making playable things!
My background is in something called “ROM hacks”. Basically, there are tools out there that let you edit games and build on top of them to make your own! You can build levels, put in new assets - and, if you know how to program, do pretty much anything!
I’ve spent years making Super Mario World ROM hacks, and I’ve become very familiar with the inner workings of the game. It’ll be forever ingrained into my memory what the tile number of these concrete blocks is, or where the game stores Mario’s powerup state. I know, it’s very impressive, please try to contain your amazement.
But now it’s time to leave behind my old retro game dev ways, and see if I can do the same in Godot! I won’t be getting all that far in this video, which is just part one of however many - but I do plan to finish this project somewhat soon, and have learned a thing or two along the way. So here we go!
After creating the project folder, Godot greets me with an empty screen. This is the scratch from which Super Mario World will be made! I could start by making the title screen, or the file select, but I kinda want to build a level!
That sounds the most fun. I’m told everything in Godot is a node, so this level is just a 2D node. And because it’s made out of tiles, I’m attaching a TileMap node to it.
So now it’s time to make some tiles! There are Super Mario World tilesets online - or I can just make one myself. This is where my Mario hacking experience comes in really handy.
I’m just going to open the level editor, build a kind of dummy level with all the objects in it, and then screenshot that to get a tileset! There’s already a lot more freedom here compared to making SNES games. I could use any number of tiles and as many colors as I like!
But of course I’ll be sticking to the Mario World tileset. The tedious part is defining the collision for each tile. I’m sure there’s a way to edit multiple tiles at once, and I’ll be very happy when I figure it out.
But now, with all the tiles in place, and a solid blue color for a background, let’s get to building the level! Again, it’s handy to have the actual Super Mario World level open for reference. I’m just going to add a camera node and write a quick and dirty script so I can have a look around.
…and also do some fun things that would be really hard to pull off on the SNES, but easy in Godot. But this world wouldn’t be very super without Mario in it. So let’s add a player character!
I’m going to add a CharacterBody2D node - and save it as its own scene, because that seems useful. Mario’s collision shape is just a 16x16 box for now. It’s actually more complicated in the original game, but I’ll come back to it.
For Mario’s graphics, I’ve prepared this sprite sheet here that has the basic frames I need. To make these into animations, I guess I could use an AnimationPlayer node, but for this very simple case, I think an AnimatedSprite2D is gonna be fine. After a slightly cumbersome process (because Godot keeps forgetting the sprite sheet layout), I ended up with these animations: idle, walk, run, jump, fall, fly, duck, look up, slide, spin, and turn.
There are more animations in the original game, and more powerups too, and I’ll be adding them in the future. But for now, I just want to get a basic player character up and running - literally. Because now, it’s time for: player physics.
I’m not trying to recreate the Mario World physics down to the pixel, but I do want it to feel like the original game. The CharacterBody comes with a template script that gives you basic movement - walking around and jumping. But… yeah, this is not gonna cut it.
The Mario World physics are really intricate. There are documents out there listing most of the physics values, and very patient people have explained the finer points to me, but to really understand the logic, a lot of times I just had to dive deep into the game’s code and take cryptic-looking notes along the way. And the adventures from those deep dives I will now recount to you!
First, a lesson on speed. How speed works in SNES games like Super Mario World To make something move, you change its position by some amount of pixels each frame. So, the basic unit of speed is pixels per frame, right?
Well, kind of. The SNES doesn't have any numbers with a “decimal point” - only whole numbers. And that would be really restrictive for speeds - what if you wanted to move Mario at 2.
25 pixels per frame? What SNES games do is imagine a unit smaller than a pixel: a subpixel. In Super Mario World, one pixel is 16 subpixels, the SNES’s favorite number.
That way, 2. 25 pixels becomes a whole number - 36 subpixels, or $24. This means Mario moves 2 full pixels each frame, and the remaining 4 subpixels get added to a running total.
When that total reaches a full pixel, Mario moves by an extra pixel. That way, it averages to 2. 25!
It’s like how leap years work: a year is about 365 and a quarter days, but we can’t have a quarter of a day, so we add a full day every four years. Here’s the code from the original game that does this calculation. So that’s how speed is measured in Super Mario World - subpixels per frame.
You can also think of it as pixels per frame, but with an imaginary decimal point between the digits. This is known as a fixed-point number. How speed works in modern engines like Godot In Godot, speed is measured in pixels per second.
Modern hardware and software lets you work directly with fractional pixel values - so you can change Mario’s position by 2. 718 pixels, and Godot just handles it. But now it’s the time dimension that’s harder to deal with.
On the SNES, one frame is just about 1/60 of a second. But in Godot, a frame can take more or less time, depending on how long it takes to process. You don’t know how many frames there are in a second anymore - but you still apply the speed one time each frame!
How can you keep the speed consistent if you don’t know how often it’s applied? That’s where delta time comes in. Godot gives you a variable, usually called delta, that tells you how long the last frame took to process.
And every time you apply speed, you multiply it by delta. That way, if frames take longer, the speed gets applied less often - but it’s a higher speed, because you multiply it by a larger number! So it evens out!
If you want to hear more of the surprisingly intricate details, Jonas has an excellent video on delta time and its pitfalls. But right now it’s time to climb out of that pit, and put all this knowledge to good use! In Super Mario World, Mario’s maximum walking speed is $14, or 20.
That’s 20 subpixels per frame, or 1. 25 pixels per frame, or (at 60 FPS) 75 pixels per second. There we go!
…but I still have a long way to go before this feels anything like the original game. Firstly, Mario actually has three separate maximum speeds: one for walking, another one for running (when you hold the run button), and a third one for running when the P meter is full. The P meter is a kind of gauge that fills up when Mario is running and depletes when he’s not.
When it’s full, Mario’s maximum speed is higher, and he can run even faster - that’s also known as P speed. (The P meter was actually displayed on screen in Super Mario Bros. 3, but here, it’s only used behind the scenes.
) And secondly, Mario doesn’t instantly reach his maximum speed when you press a direction on the D pad - and he doesn’t instantly stop when you let go. That’s because the game has acceleration. Just like speed changes position over time, acceleration changes speed over time - so it takes a short while to build up speed, and to slow back down again.
And when you apply acceleration in Godot, you have to multiply by delta again! I guess that makes sense, for calculus reasons, and also because you don’t want the acceleration to depend on the frame rate. Delta is a pretty small number, and factoring it in twice means the acceleration values end up being pretty large and not easy to interpret.
But that’s no big deal - I just need to make sure I’m doing the conversion right. So, with all the speeds and accelerations in place, the results are finally… still not right. It’s still a bit off from the original.
Like I said, Mario’s physics are really intricate. It took me ages to figure out the logic of when the game does what. With a lot of help from Thomas, probably the world’s leading expert on Super Mario World physics, I eventually landed on this code.
It doesn’t seem like much, but I’ve agonized over this. Here are just a few fun facts about it: #1: acceleration and deceleration is different depending on the situation. If you’re holding a direction on the D pad, Mario slows down quicker than usual, but if Mario is ducking, he takes longer to slow down, even if you’re holding a direction.
#2: if Mario is in the air and you’re not holding a direction, he doesn’t speed up or slow down at all. That’s why when he shoots out from a pipe, he actually moves faster if you don’t hold a direction! #3: the game never really caps Mario’s speed at the maximum - it just makes him slow down if he’s too fast.
When Mario is running, his speed is constantly fluctuating! He briefly goes above the maximum speed, so he slows down, and then he speeds back up and goes above the maximum again. And on average, that comes out to exactly the maximum speed.
So after implementing all of this in Godot. . .
yeah! That feels pretty good. Mario’s position is still a few pixels off in the long run - literally.
Either way, I’ll say this is good enough. It definitely feels like Super Mario World now. I’ll just add some dust clouds when Mario turns around.
That’s an easy thing for a change - I just need to make it a scene, give it an animated sprite, and add code in the player script to spawn it. And now, we can move on to moving up. Mario’s jump is surprisingly easy to make!
There’s not that much logic to it. When you press the jump button, Mario moves up. And every frame there’s gravity, which changes his speed over time, like downwards acceleration.
So after jumping, Mario slows down and then starts falling down again. I remember reading somewhere that Super Mario World doesn’t actually apply gravity while Mario is jumping up, so his upwards speed would actually be constant. But as far as I can tell, that’s just not the case.
Maybe I’m misremembering the rumors. But Mario’s gravity can change! While you hold the jump button, it’s only half as strong.
So when you hold the button the whole time, Mario jumps higher and doesn’t speed up as much when falling. That’s also what lets you run across these one-tile gaps. And of course, Super Mario World also has the spin jump, which has pretty much the same logic as the normal one, except Mario jumps a little less high.
When I coded the jump, I noticed Mario was jumping a little higher in my Godot version than he does in Super Mario World for some reason. That “some reason” turned out to be: I forgot to apply gravity to Mario when he’s on the ground. That extra frame of not having gravity pull on him can make a difference.
Mario’s upward speed, and thus his jump height, actually depends on how fast he’s running. So the faster he runs, the higher he jumps. And technically, there’s not even a limit to this jump height!
It’s only limited by how fast he can run, and that does have a limit. But if I were to remove that, just for the heck of it, then… yahoo! Now that we have walking physics and jumping physics, let’s get to… walking physics.
Because you know what I forgot? Slopes. Slopes might be the most annoying part of platformer physics.
They’re not that much of a pain in Godot, because the physics engine handles collisions well enough - but recreating the exact slope physics of Super Mario World is a different story. There are four types of slope in the original game: gradual, normal, steep, and very steep. First of all, how do I even detect when Mario is on a slope, and what kind of slope it is?
After some trial and error I found the get_floor_normal function, which gives you a vector pointing away from the surface. If it points straight up, then Mario is on flat ground - and if it’s at an angle, I can find out what type of slope he’s on by how much it’s leaning to the side. Trigonometry!
Godot actually makes things slow down when they move uphill - a nice gesture, but I want to have finer control over the physics here, so I’ll disable that. I’ll also need to set the floor_snap_length, so Mario sticks to the ground a little and doesn’t overshoot when he walks uphill. Now Mario is walking across the whole terrain at the same speed, which is a good starting point.
Now, what do slopes do to that speed? A bunch of things: #1: they change Mario’s maximum speed, so he’s slower uphill and faster downhill. #2: they change Mario’s acceleration and deceleration, so he speeds up quicker downhill and slower uphill.
#3: Mario can slide on slopes when you press DOWN, and there’s a separate speed just for sliding. #4: on steep and very steep slopes, when you let go of the D pad, Mario starts walking down the slope on his own. That auto-walk has its own, separate, acceleration values.
And of course, all these things are different depending on the type of slope, and also on whether Mario is walking uphill or downhill, and also whether you’re holding the run button or not - so I need to check for all those cases. Eventually I gave up giving these numbers meaningful names, and just hardcoded them all in. I was really struggling with these very steep slopes, because they’re a special case in many ways.
They’re so steep that Mario can’t walk uphill even if you hold the run button, and they make Mario slide automatically, without you pressing DOWN, and without showing the sliding animation! That was pretty fun to find out. I’ve had my fair share of slip-ups - but eventually, I got slopes under more or less control.
This is all still far from perfect, but perfect isn’t my goal here! I want to learn how to use Godot, and I’ve already learned plenty. And the movement really feels like Super Mario World now!
This seems good enough to move on with. There are so many details I couldn’t cover in this video. And there’s still so much left to do here even just for player movement: water physics, climbing, flying, springboards, conveyor belts, more springboards, Yoshi - not to mention powerups.
But I’ll leave that for another time. For now, I’m gonna add some polish to the level and give it a background. I’ll make a “Background” scene, add a colored rectangle node for the backdrop color, and also a parallax layer node, because that seems like the easiest way to make it scroll slower than the foreground.
In modern games you would probably just use an image for the background, but in Super Mario World, the backgrounds are also made of tiles, so I’m adding a TileMap node and putting the background together from a tileset. And to round off the jump mechanic, I’ll give Mario an “audio stream player” node and make it play a jump sound. At this point, I think I’d be remiss not to mess around a bit.
Here’s where engines like Godot really shine: once you have something coded up, you can just copy it, and now you have two! …or three, or four, or five! But yeah, there we have it!
An okay Mario in an okay level - the start of my adventures in recreating Super Mario World in Godot. In the next video, I’m probably gonna take a break from Mario physics, and flesh out the world a bit by making coins, powerups, blocks, and enemies. …or maybe I’ll just add some more Marios.
Either way, thank you so much for watching! If you enjoyed this video… you’re a frickin’ nerd.