JS13kGames 2016: Super Chrono Portal Maker
August-September 2016
TL;DR:
You can play the game HERE! (please share!)
Try also my Codegolf Team's entry "26 games in 1" HERE (please share too)!
You can see all the shared levels (and share yours) HERE.
You can follow the official account @SuperCPMaker HERE.
The Github repo of the game is HERE.
The speedruns of the game are HERE. (warning: spoilers!)
The game was ranked 3rd in the Desktop category!
Preparation
This year, I was really into 2D platforming.
I developed a platform engine during my free time.
We also discussed on JS13k's slack about the idea of a "13kb Mario Maker". This idea made me develop a 1kb level editor with shareable URLs, that all js13k's devs can use in their games...
As I was a bit rusty on 2D maths, I also made this trigonometry cheat-sheet for 2D games that many people found very useful.
I also made a tiny graphics editor, to help devs produce line-based graphics quickly and lightly (like I did for my 2015 entry GeoQuiz).
And finally, @innovati, @p01 and I, made a graphical music composer called miniPiano that lets you draw a melody and outputs a tiny piece of JS code to play it back.
Everything is ready to make a cool game now!
Week-end 1
When JS13kGames 2016 started, I remembered this Mario Maker idea and decided to mix it with two other of my favourite games, Portal (no presentation needed) and Chronotron (a Flash game that lets you rewind time and collaborate with your past self to solve puzzles).
The idea of mixing Mario and Portal also comes from Super Mario Portal by "Moumou" (20Mb, made with RPG Maker!) and Mari0 by StabYourself.
The idea of mixing Portal and time travel also comes from Thinking with Time Machine, a great Portal 2 mod.
Some inspiration can also be found in Braid (for time travel) and Enough Plumbers (for the multiple Mario gameplay).
And for the record, this article is a great resource about 2D portals implementation!
So I wanted to make a game featuring most of the cool mechanics of these three games (Mario, portal gun, time travel, mechanisms, companion cube, traps, and of course a level editor), but also being something completely unseen before.
The theme of js13k this year is "Glitch!", and to include it in my game, I decided to provoke glitches in case of time paradoxes... (and in a few other cases).
Like previous years, my personal challenge was to make a game so big that it would be complicated to make it fit in 13kb. So with this puzzle-maker idea, I believed it would be a hard (and fun) task to achieve. I really wanted to make a game that was a complete system with a lot of interesting rules, and with a quality high enough that no player would guess that its size was limited (and make them wonder how all that can fit in 13kb).
Unlike previous years, my source code before minification will be really readable: well commented, cut into multiple files, and with explicit variable names! I'll do all the optimizations at the end instead. I can't promise that the code will be clean and mainainable, but at least, it'll be readable.
Last detail: last year, half of the zip was used by the game's data (the world map, the names of countries, capitols, famous places, etc), but this year, I'll really focus on filling it with a lot of code and a ton of features, instead of data. So, to sum up, I don't wanna look lazy this year...
During this first week-end, I wrote the game's specs, then I drew all the images of my game into this spritesheet...
... of course, inspired by Super Mario Maker, Chronotron and Portal, but without the copyrights:
I also developed basic menus (title screen, level selection screen...) and started to develop the main features of the level editor (select tiles, place them on the map, etc).
All the following screenshots show the interface at the end of the week-end...
Current code size: ~7kb commented, ~1.5kb minified and gzipped. (plus a 1.8kb PNG)
Week 2
During the first half of this week, I developed the level editor, to give it strict rules (eg. only one starting point, only one end flag, the ability to place green pipes and switches that make them go up and down, the ability to place pairs of balanced platforms, etc...).
To do that, I had to define a precise format for saving the levels, a format that allows to store all the level's tiles in a grid of 40 * 20 ASCII characters (which is the most compressible output I could find while developing the 1k level editor), plus information about linked elements (pipes and switches, pairs of balanced platforms, etc). And all this data needs to be serializable in a string shorter than 4096 bytes, in order to be easily shareable via an URL on twitter.
Here's what the data of a level looks like:
// As a JS object:
level_data = {
tiles: [
[0, 0, 1, 2, ...],
[3, 2, 0, 0, ...],
...
],
pipes: [
[x, height_1, height_2, switch_x, switch_y],
...
],
balances: [
[x1, y1, x2, y2],
...
]
};
// As an URL:
http://...#{hash:"0012...",I:[[x,height_1,height_2,switch_x,switch_y]...],J:[[x1,y1,x2,y2]...]}
I also added many checks in the code of the editor to prevent to draw overlapping pipes and balances, and also to avoid overwriting important elements of the map (like the pipes or the time machine) to avoid bugs.
The whole code, including the menus, the complete level editor, as well as the "share", "clear" and "exit" buttons, is 19kb commented, and 2.16kb minified and gzipped. (plus the usual 1.8kb PNG)
~
At the end of the week, I designed the first levels of the game, which will be useful for me, to develop the game's engine in "real conditions".
Weeks 3 & 4
During these two weeks I wrote the game's engine, little by little. Here's my TO DO list, plus some GIFs I tweeted while developing it:
General stuff:
- ✅ Load/draw a level
- ✅ Restart with "R"
- ✅ Quit by clicking on the black "x"
- ✅ Record all the inputs (in order to be able to play them back after time travels)
- ✅ Animate the hero (use different sprites, walk, jump, die, turn left or right, etc)
Basic controls:
- ✅ Fall
- ✅ Move left / right
- ✅ Jump
- ✅ Collisions in the four directions
- ✅ Break brick tiles by jumping under them
- ✅ Collect coins
- ✅ Die by falling (Oops!)
- ✅ Die by touching a spike
- ✅ Win by touching the flag if all the coins are collected
- ✅ Hold/drop/throw a companion cube
- ✅ Stand on companion cubes (they're only solid on the top side)
- ✅ Stack cubes (Oops!) (WOW!)
- ✅ Slip on ice (unless we're standing still) (Nice!)
(at this point (and after a little refactoring session), the JS code fits in ~3.6kb minified and gzipped. The zip takes 5.4kb.)
Mechanisms:
- ✅ "!" blocks and toggle switches (Oops!) (Nice!)
- ✅ Pipe elevators and switches makes them move
- ✅ The hero dies if he's crushed by a pipe or a balance (Nice!)
- ✅ Switches can be pressed by cubes (Oops!) (Nice!)
- ✅ Balanced platforms (that move if more weight is on one side)
- ✅ The hero can go on a platform from below (only solid on top)
- ✅ Cubes can make balanced platforms move (Oops!) (Nice!)
(Little refactoring... current zip size with 5 levels: 6.5kb)
Portals:
- ✅ Portals (mouse to aim, left/right click to shoot) (WIP Nice!)
- ✅ Portals push you out (Nice!)
- ✅ Portal ray bounces on ice (Nice!)
- ✅ The hero keeps his momentum when he goes through a portal (Nice!)
- ✅ Cubes an be dropped or carried through a portal (they keep momentum too) (Oops!) (Nice!)
(Huge refactoring (it took 5 days)... current zip size with 10 levels: 8.2b)
Time travel:
- ✅ Time machine (press shift to rewind time and play with your previous version(s)) (Nice!)
- ✅ Multiple time travels (Nice!)
- ✅ Show which one is the "current" hero
- ✅ The hero can walk on a cube held/dropped/thrown by another version (Nice!)
- ✅ Game over if a previous version doesn't reach the time machine (a.k.a. Paradox) (Glitch!)
- ✅ Game over if a previous version dies too
- ✅ Previous version can collect coins, take/drop cubes, press switches, walk on pipes, walk on balanced platforms, launch portals, go through past/present/future portals, get the flag.
- ✅ Previous versions can "steal" cubes to present hero and disable his portals by firing their own portals (and vice-versa)
- ✅ Clouds! (Nice!).
(Another refactoring...current zip size with 15 levels: 10.5kb)
Weeks 5 & 6
These two weeks (actually, one week plus two days) were consacred to the creation of the final levels included in the game, the music, the debugging and the polishing:
- ✅ Proper custom level testing and sharing (on Twitter).
- ✅ 30 levels in total (most of them are actually tutorial levels). Thanks to Adrien Guéret for designing a few and beta-testing the others!
- ✅ Sound (Thanks to Anders Kaare!)
- ✅ Next levels unlock after clearing one.
- ✅ Save progress and chronos in Local Storage
- ✅ "Developer times" to beat by speedrunners (cumuled record: 9 min 55 sec)
- ✅ Video record for all the dev times (for speedrun.com)
- ✅ Final title screen
- ✅ Inline the tileset in base64
(current zip size: 13.9kb)
There's an important discovery made a few days before the deadline: Advzip, a zip optimizer/recompressor is able to save around 1kb out of a 13kb zip. By passing my current zip through Advzip, it only takes 12.8kb. We're still below the limit! Maybe we can have some music...
At this point, my commented source code weighs 114kb (scattered in 12 files and containing more than 3600 lines of code), and shrinks to 72.4kb when minified (including 27kb of level data)
And yes, as incredible as it sounds, once zipped, all that code fits in less than 13kb!
Golfing:
- ✅ Just one HTML file with all the game contents
- ✅ Inline the functions that are only called once
- ✅ Optimize the JSON of the built-in levels
- ✅ All the game variables, hero / level / cube properties and functions are renamed to 1 to 2 chars
- ✅ All the function params are renamed to e,f,g,h
- ✅ Explicit "window" references are removed
- ✅ Shorten Twitter URL
- ✅ Minification, zip, advzip
Zip size after this golfing: 11.1kb!
Final touch
With 24 hours left and nearly 2kb available in my zip, I called Anders Kaare to save my life once again. He made me a great collection of sounds plus a gorgeous musical theme in no time!
I also added a hidden, super difficult level and recorded all my developer times as a challenge for speedrunners.
All these latest details were added in a hurry, without any form of optimization or golfing.
Final beta-testing with my colleagues!
Final interface:
Conclusion
This project took me nearly 200h to complete, much more than any of my previous entries, and more than any of my previous personal projects!
There's a lot more that could be done, but I ran out of time and energy... but never ran out of free space! My final zip is just 12.5kb!
I'm still very happy with the result, and hope that a lot of people will enjoy it and create stunning levels!
Thanks js13kgames, and Andrzej, and Anders for the music, and all the people that helped me and supported me during this compo, and see you next year for something even bigger! :D
One week later:
People play and enjoy the game, they also start making cool levels, and they speedrun it too! That's great!
I also took the time to speedrun it as fast as I could (better than my own "dev times" in the game), and you can see the result here (warning, spoilers!):
But even if you create something and think you master it, someone will always be better than you, and it's just awesome!
Two weeks later:
Publication of the final results:
- Super Chrono Portal Maker was ranked 2nd in Community votes. 26 games in 1 was ranked 10th! Thanks guys!
- Super Chrono Portal Maker was ranked 3rd in the Desktop category (and 26-games-in-1 54th)! Thanks jury!
Also, these playtests by Jupiter Hadley:
2017 update: A new speedrun in 6:18.40!
Cheers!
@MaximeEuziere