Uncompressed Source Code: https://paste.ee/p/5KOG5 (warning: it's pretty gross)
Late last year (2017) I started work on a port of Super Mario Bros [NES] to Pico-8. The goal was to be authentic as possible to the original game, while working within the Pico-8 limitations. Something like Super Mario Bros Deluxe [GBC] (https://www.mariowiki.com/Super_Mario_Bros._Deluxe).
In the end I was able to get 1-1 and 1-2 mostly complete before starting to hit serious memory limits which make it seem near impossible to ship the full game.
With that in mind, I'm releasing it as-is for now so that people can check it out and see where it was headed.
If you are curious, the biggest factor for memory is the level data which is quite huge. At some point I'd like to document how my level authoring process worked, but for now you can check out this twitter thread of me slowly wittling down the level data size:
https://twitter.com/matthughson/status/929194247202340864
Update: I have managed to squeeze in all for World 1 now!
Music by: https://twitter.com/gruber_music
I'm not sure if you're already doing this or not, but as for level data goes in a mario game. It seems reasonable that you could just need to have the floor be a solid rectangle of tiles, so basically the only info you need is the tile type and then the location of the pits, which you just cut out. Then all that's just is the location of objects. It would be reasonable to assume you're already doing it this way. I haven't taken a look, but if you ever wanna bounce ideas on reducing data size, hit me up. I love that stuff. Maybe we could work out something cool.
@Cabledragon: That's actually similar to how the original cart did it, although I don't. I store map tiles using a kind of run-length encoding.
Really good job! Never played it on actual hardware but this works quite well. I don't remember goombas chasing you though.
P.S. If you released multiple cartridges on the same thread with different level data, you might be able to do all the levels. I don't know how well it would work, but it is an idea.
Trying out your MARIO, MH. Spot on graphics and feel.
I noticed when you are on a pipe, in the original game if you press down, Mario will crouch down. Does not do that in here - if you're going for authenticity. And - no castle to enter at the end of the level ?
Marvelous work what I've seen so far.
Run Length was my first idea but then when I got to thinking about how the floors are in mario levels, it made more sense to just have teh floor be a constant repeated single tile so no data is needed except for the type of tile and the location of pits. Then for other objects or groups there of you could story their values and positions and have a lot less data on your hands and then frmo there you could FURTHER compress with some RLE stuff.
I noticed it doesn't revert back to the mushroom powerup when you get hit with a fire flower. Just a small difference, although it makes it a bit harder.
@hw2002: The goombas don't chase you. They just walk forward and change direction when they hit stuff.
Releasing multiple carts is probably how I would do it. I can fit about 10 levels per cart right now but there are still some additional objects to implement which may reduce that number.
I'm not sure about going back to Mushroom when you get hit. I thought I checked what the original did and copied that but I might be mistaken. Confirmed: Mario always returns to small Mario when hit by an enemy in the original game.
@dw817: Thanks! You are correct. Duck and end castles are 2 things I cut for space.
@Cabledragon: if I come back to the project I probably give that repeating floor idea a try to see how it affects memory and token counts.
IIRC the original SMB game uses a "templating" strategy for its levels: the tile data is defined as large objects like "pipe", "stairs", etc. and then pasted into the scene at the appropriate x scroll position. The levels are actually tiny when using that strategy since so much template content gets shared, and it explains the existence of the "minus world" and similar invalid yet playable levels.
However, the original cart is also 256kb so that probably still won't get you to the full game.
Edit: Actually, it's 32kb so maybe? SMB3 was 256kb.
@triplefox: yes, the compression on Super Mario is like that but even more complex. The X,Y coordinate of the object also defines the object type, and what all the bits mean.
So an object of Type 1 at Y position 0 might be a coin, but object of Type 1 at Y position 32 might be a flag pole. It's all very clever and based on all the mutually exclusive information the designers knew about the game (eg. you can't place a coin below the floor, so we can use that limitation to say "coin below floor" means "flag pole" and flag poles are always at the same y position so we can ignore the fact that it is positioned below the floor).
It goes a step further to break up the meaning of each bit of the object such that the first few are the page, the next few are position on that page, and then the last few can mean different stuff depending on the object type.
I did dig into that quite a bit and implemented a first pass. It saved good chunk of compressed memory, but added a huge amount of tokens to handle all those cases. It was pretty neat though: being about the copy raw Hex data out of the ROM, and into Pico-8, and see it load the level. :)
Small update (version 0.1.2):
- Added moving platforms to World 1-2.
- Implemented placeholder warp zone in 1-2.
- Added proper ending to 1-2.
This makes the whole experience feel much more complete.
@mhugson I have a working version that use my good ol' json parser. It clocks at ~7300 tokens (started from the pastebin version).
note: I didn't dig too much into it, but the whole hex to map thing could eventually be replaced by a json number array + RLE encoding (as the json parser already supports hex&number string to values)
@freds72: That's pretty cool! But 7300 tokens sound like a lot, isn't it? That only leaves ~900 left for the game itself.
@freds72: oh haha sorry. I totally misinterpreted your post :D
So what did you change to save those tokens? Would you mind posting the p8 file somewhere so I can do a diff?
Hi Matt, really enjoyed playing this. I appreciate the design choices you have made, particularly the white look-out circles, and the sound effects (I think the shell kicking sound is more similar to the later games?). Here are a few of things I noticed that seem out-of-place:
- At the end of the level intro, there is a frame displaying the actual level in the wrong place
- The mushroom/fireflower blocks yield a coin if you hit them again (I quite like this one!)
- Mario's collision dimensions are larger than the original game (in SMB Small Mario is 12x12px, not sure about Super Mario, maybe 12x24px)
- The small coin at the top is distorted (sspr?)
- The controls are inverted (may be a matter of preference, but on my 360 pad, I expect the bottom face-button to jump)
Really impressed at how faithful this recreation is.
@Lafolie: Thanks for the thoughtful critique!
"At the end of the level intro, there is a frame displaying the actual level in the wrong place"
Yah, I know what you're talking about. Looks like a frame hitch while it loads the level or something. I'll get to it some day... :)
"The mushroom/fireflower blocks yield a coin if you hit them again (I quite like this one!)"
A bug for sure, but I like it, so I think I will keep it!
"Mario's collision dimensions are larger than the original game (in SMB Small Mario is 12x12px, not sure about Super Mario, maybe 12x24px)"
I'll need to double check but I thought I made sure this was accurate to the original.
"The small coin at the top is distorted (sspr?)"
Yup, it is the regular coin scaled down with sspr. Gotta save sprite memory wherever I can!
"The controls are inverted (may be a matter of preference, but on my 360 pad, I expect the bottom face-button to jump)"
I use "A" and "B" which is correct, but if you use "X" and "A" it's backwards. I'd like to do some so of key config if possible. But i'm sure i won't have the tokens for it!
WORLD 1 IS COMPLETE!
The latest version of the game now includes:
- All 4 levels of World 1
- All enemies of World 1 (incl. Bowser!)
- All Power-ups!
I had to remove some features to fit it all in, but I think it feel pretty complete at this point.
Give it a play-through, and let me know what you think!
This is incredible! It's so close to the original! Even the music is good. I didn't think this kind of thing was possible on Pico-8.
@PicoLate Thanks so much!
@StinkerB06 That's true, but also true to the original games.
Why was this cart hidden for so long? Like... it didn't even come up in search results before.
@StinkerB06 I had it in the WIP section for a long time cause I had planned to finish the rest of the worlds. When it started to seem like that is never going to happen I moved it to "Complete". I'm guessing that affects the search results.
@BrightBlackHole That's pretty cool. I haven't see that before!
Nice job on the graphics and gameplay here. If at some point you're interested in revisiting the project to fill in the rest of the levels, I've managed to get a good level compression system going using metatiles. A while ago I made an interactive demo with it that included all SMB level maps, and they fit in just 3.9KB. https://www.lexaloffle.com/bbs/?tid=39469
Since then I've released a graphical editor using a newer, more versatile version of the system: https://www.lexaloffle.com/bbs/?tid=42848
Storing levels made of 16x16 tiles instead of the 8x8 ones in the demo would actually be very easy, too, just requiring adjustment of some math and a bit more space to hold the reference tile patterns. Fitting the full-size NES sprite graphics should also be feasible with the system's built-in sprite compression. Nintendo's pretty touchy about their IP so you probably wouldn't want to promote it a lot, but using metatiles it's definitely possible to fit the game on a Pico-8 cart.
This is really well done! The best version of Mario on Pico-8. Thanks for updating this.
i had made a expressive mod of this. i think i did good
@JadeLombax thanks for sharing! That's really cool. I don't think I'll work on this much more at this point though.
@Gameboi64 I like your ? block sprite a lot!
Why do things get the white circle when they're just off the edge of the screen? Is that in the actual game?
@ooooggll The "off screen" indicators accommodate the fact that PICO-8's screen can only show a portion of the original viewable area at a time. They're specific to this version, not in the original.
As far as fitting more level data in, the original game uses sprites to control the height of the floor and ceiling. For example, in World 1-1, the floor is initially set at 2, then 0 to make the bottomless pits.
floors = { [0] = [2, 0], [20] = [0, 0], [24] = [2, 0] -- and so on... } |
I might play around with it when I get some time off at Christmas.
As far as improving the music, I've made a demo with how it can be achieved.
remember what you said?
I had it in the WIP section for a long time cause I had planned to finish the rest of the worlds. When it started to seem like that is never going to happen I moved it to "Complete". I'm guessing that affects the search results
if you are the user of the project you can use edit to update
learned
from @Verb
NOOOOOOOOOOOOOO what happened to Toad at the end? I wanted him to say the princess was in another castle. Still 10/10.
Awesome work!! Don't know if you've seen it, but here there is a link to a very nice explanation on how the original cartdridge store levels (and is very tricky)! https://www.youtube.com/watch?v=1ysdUajrhL8
[Please log in to post a comment]