I found out about JS13k, a competition to make a JavaScript/HTML5 game in under 13kb, back in July.
I've always wanted to make games; it's a big part of why I got into programming. However, being in the midst of a job search, I feel like I never have enough time to get into it since I'm trying to keep up with learning all of the web technologies and frameworks, practice algorithms, etc. My "hobby" has to sit on the sidelines.
I figured since I primarily code in JavaScript I wouldn't have to overwhelm myself trying to quickly learn a bunch of extra stuff on top of my already stacked list of things I'm trying to learn, so I could definitely try to enter. The competition lasted 1 month, from August 13th - September 13th.
Theme / Brainstorming
This year's theme was 404, as in the Not Found error. I came up with a concept that would be sort of like a point-and-click but I scrapped it because I didn't have a lot of time to come up with puzzles and a story. Then I thought, what about a killer robot with a missing kill.exe file? The player could play as the robot being swarmed by some type of enemy and they would need another way to defeat them. How about bringing them food? I figured I could make a game where food spawns in random locations as enemies swarm around and you have to bring them whichever food they want.
Then I thought, what about that old Bugs Bunny game Crazy Castle? I could make something like that, but instead of avoiding enemies and collecting carrots, you find and bring them the foods they want. If you come into contact with them without the correct food you lose. I really liked this idea, but again I didn't have a lot of time to come up with a bunch of different levels. Finally I thought, what about something like Pac-Man where there is a single map? This idea worked for me; there could be a "food court" and the player could zip around snagging the right food for the right enemies. Oh yeah, I decided the enemies would be aliens who really like tacos and donuts.
Creating the Game Art
After settling on an idea I used Aseprite to make my game art. I don't have a lot of pixel art experience so I was just kind of winging it. Thankfully Aseprite is fairly easy and fun to use so I was able to come up with designs that I liked.
Code Time
I decided to make everything from scratch, as opposed to using one of the game engines from the JS13k resource page. I just felt like even if I didn't come up with the best game, I wanted to learn how to make everything myself.
Organization
I created a main.js
where I handled the main game loop as well as any event listeners and a few global variables to instantiate a game object and to import sprites and sounds. Depending on the current game.state
, gameLoop()
either displayed the title screen, game over screen, or called requestAnimationFrame
and looped game.update()
(which handled game logic) and game.draw()
(which handled drawing to the canvas
).
Just about every other class, such as Player, Enemy, Food, EnemySpawn, etc extended off of a GameObject
class which handled collisions, animations, and variables like x,y, width, height, and the source location and size of each object on the sprite sheet. I'll probably eventually go back and clean some of this up, because many of the child classes don't do anything special or different. It was just easier in the moment to create the child class and keep track of all objects of a certain type using static class variables. For example:
import GameObject from './GameObject.js';
export default class FoodCourt extends GameObject {
static all = [];
constructor(srcX, srcY, srcW = 16, srcH = 16, x, y, w, h, type) {
super(srcX, srcY, srcW, srcH, x, y, w, h, type);
FoodCourt.all.push(this);
}
}
This way I could just use FoodCourt.all
to loop through only food courts when the player was within a certain range to check for collisions as opposed to looping through all game objects. I could probably go back and just use static foodCourts = []
in the GameOject
class, and push all newly instantiated foodCourts to that instead of creating a whole child class.
Struggles
I made my sprites 16x16 or smaller and therefore they needed to be scaled up. I also wanted the entire game map to scale depending on window size but it needed to stay in proportion. I spent a lot of time struggling with this. I got the sprites to scale up but then the collisions weren't working correctly and my character kept shooting off the sides of the screen. I did some research and found that basically you're dealing with 2 canvas sizes: the native height and width used for all your game logic, and the canvas height and width used for display. If you're curious how I went about this, I wrote a post here.
As the deadline was swiftly approaching I had to cut a lot of my ideas and just get something working. I added mobile controls, which are okay but could be a lot better, and I was able to create a few sounds using jsfxr.
The game was due at 7AM my time (13:00CEST) on Sunday, September 13. I was as done as I was going to be at around 9:30PM Saturday night. I had used some tips I found in a post by Yvonnick FRIN to compile and zip the game and it was under the required 13kb. Yay!
I started to fill out the form to submit my game and I ran into an error because I didn't have the index.html in the root. It was in src
along with all my js files, which is not how I normally organize my file structure, but that's how the guide told me to do it. I didn't follow the entire guide though, so maybe I missed something further on. Anyway, I re-organized the file structure and I could no longer get the game to find my images and sounds. Then when I got it working it wouldn't compress to under 13kb anymore. I was very confused. I tried multiple methods to compress and get everything working. I even copied all my code from separate files into 1 file and tried online minifiers, and I tried another JS13k starter that has scripts to do some high file compression and zip for you. Nothing I did was working and I couldn't figure out why. I dug into the scripts and started trying to learn what they were doing, how Archiver works, etc.
At around 4:00AM I was feeling defeated and I was preparing to give up and just be happy that I made a game. I closed my computer and went to wash up for bed. While I was brushing my teeth I thought about how the first time I zipped the build it was fine, except for the file structure being wrong. I decided I would go back to my computer and give it one last-ditch effort by reverting back to that first attempt and using what I learned by messing around with the scripts. It...worked... IT WORKED! I can't believe I was ready to give up, but I'm so glad I didn't.
You can play it here if you'd like: Kill.exe Not Found
Top comments (2)
Nice demo. But it's hard to turn, because character's size almost equal the road's side, when need to turn left or right, have to adjust the character position carefully to fit the road. Maybe bigger road can be an improvement.
Thanks Thien, I agree. Still learning 😅