The game jam theme “404”, my unfinished 2017 entry, and Kenney.nl’s graphics culminated the creation of “Employee not Found”, a game where you’re a mail-delivering office robot whose task is to deliver last minute mail to desks before the office opens. Alas, some employees have moved to other desks, so you have to find the new desk! The following is an odd journey that led to “Employee not Found”.
You can play the entry here: https://js13kgames.com/entries/employee-not-found
Story below technical info.
- Custom game engine with basic DisplayObject-style scene graph and essential rendering components.
- The blue top-down robot graphic from https://kenney.nl/
- gulp.js build system with modules.
- Mustache (via gulp-mustache) for template string replacements during build
- UglifyJS (via gulp-uglify) for minifying JS, with name-mangling option enabled.
- gulp-htmlmin for minifying HTML.
- gulp-sass for variables and minifying CSS
- gzip (via gulp-zip) for compressing.
- express for local testing.
JS13K 2017: Lost
The journey starts with an unfinished game for the competition’s 2017 iteration, where the theme was “Lost”. A little too true to the theme, my game had no particular direction. There was a general idea on what the game is about, but after finishing the map generation, I struggled in how to fit with the idea and how to make it fun.
The general idea was that the player woke up in an unfamiliar room, trying to find your way out of this building. This led me to needing an algorithm to randomly generate a building layout with rooms and hallways. Following this answer and algorithm, it took me maybe 1 whole week after hours to make a random map generator. Add another week to implement basic collision and voila:
… and then, I ran into a creative block. What kind of building has this much rooms, and how am I going to decorate each room to be unique enough? Is this even going to be fun? Also facing the issue of the collision system catching corners, I spent the last days of the competition fixing that, not having a clue on how to proceed with the game. I didn’t have an answer to that question until three years later.
You can play this unfinished game here: https://games.jayther.com/js13k2017/
JS13K 2020: 404
JS13K 2020 came around and announced that the theme was “404”. I came up with several ideas, and initially landed with the idea where the company’s website is showing the 404 error and the player’s mission is to go from computer to computer to find all the pieces of the website before it goes live. This is where I realized, I can reuse my unfinished game! And the answer to that old question is the layout resembles more of an office building.
The Mail Delivery Robot
So I pretty much started from the unfinished game, with the layout generator being largely untouched. However, I needed a graphic for at least the player character. Perusing through Kenney.nl’s assets, I stumbled upon the “robot” pack, which are these:
These gave me idea to use robots instead of a person as the player character. At this point, I started streaming the development of the game on Twitch and was coming up with an algorithm for desk placements. Soon after, I came up with possibly changing the idea from looking for pieces of website code to delivering mail. The more I thought about it, the less the original idea made sense in context of the robot, so I went ahead with the mail delivery robot idea. But to fit the “404” theme, I added the concept that some employees have moved to new desks, so the player will need to find where the new desk is.
Somewhere along the line after adding the robot image as the player character, the size of the robot was too small, so I had to enlarge it. However, the doorways were now too small. So I had to make the door ways wider, by one cell, one of the few changes I made to the original map generator.
I also added room floor, hallway floor, and room wall tiling graphics (also from Kenney.nl), but I later replaced them with generating those tiles with cached canvas instances, since the graphics were just zigzags anyway, which saved me about 1 KB.
Although an office’s rooms can be largely the same, there are still some variations between rooms, like where the desks are and what kind of office room it is. So I came up with these room types:
- Open office: large room with desks laid out in a grid with walking space between them, potentially two desks per grid cell.
- Private office: A single large desk in a small room, preferably facing and opposite side of the wall with a door.
- Bullpen: very large room with cubicles.
- Lobby: very large room with many chairs but one or two desks.
To avoid desks and other furniture blocking the door, the “potential desk bounds” retreated from walls that had doors.
I started with the open office that utilizes a separate grid for desks. At this point, I also started the whole “mail delivery” aspect, with the robot needing to almost touch the desk to deliver, the random few desks that has been relocated to another room, and the visual pointers to point towards the rooms that need mail.
As I was implementing the “double” desks for open office rooms where instead of one desk per cell, there were two, I started noticing issues with collision. This is only the beginning, as collision issues plagued me in the rest of the competition and caused me to delay any major progress for days at a time.
Collisions, collisions, collisions
I did solve the edge collisions along room walls for 2017’s attempt and the single desks for the most part. However, the double desks, which are separated by a small gap, were causing the edge collision issues (corner catching). On top of that, going around the corners of these desks were causing the player to sort of teleport to make it seem like they’re tunneling through. This is how I proceeded to fix:
- Tried to implement swept collision (using this tutorial) to replace both wall and desk collisions, but colliding just stops the player completely. In hindsight, it probably did not work initially because I did not implement the slide collision response properly (slide collision is sliding against a wall without bouncing, effectively canceling the velocity perpendicular to the wall).
- Reverted the collision code and turned the double-desks into a single collider to get rid of corner catching. However, the corner skipping was still happening. But at this point, the colliders and the visual desks are now completely separate entities.
- I thought multiple collision iterations per step with smaller travel would work. It didn’t.
- I looked closer at the slide collision response and re-implemented the swept collision, but only apply it to desks and other future furniture. This implementation worked… for now.
I felt pretty confident with this solution, and implemented the private office with a long single desk. This was easy enough, as there were no multiple desks and custom grid for spawning desks, which also meant only a single collider.
The bullpen came with the cubicles, and the custom grid for potential desk placements worked fine, which is essentially a grid of sub-grids that allowed partial sub-grids (a section of cubicles can be missing rows or columns).
I also used a different concept on how the grids are laid out to avoid the monstrosity that is the Open Office generation. However, once I placed cubicle walls and desks, new collision issues emerged, where the robot was going through walls and desks, only sliding against a specific wall or desk. Also, corner catching was back in fashion. This is how it went for furniture collisions:
- I thought about doing multiple collision iterations again, but initially went against it as it didn’t solve the issue last time.
- Attempted to use axis-independent collisions, but it still had corner catching when sliding across a specific axis.
- Attempted to store the swept collisions on a stack, but I didn’t really know how to convert the stack of collisions into a single slide collision response without going into physics-engine-style impulse vectors.
- Armed with a deeper understanding of the slide collision response from last time, I revisited multiple collision iterations and tried again. It worked!
Finally, I got a (mostly) solid collision response. I was happily sliding across cubicle walls and desks without stopping or going through. However, I only had three days left.
The Lazy Crunch
So what don’t we have:
- Title/landing screen
- Lobby room
- Tutorial for controls and game
- Some indicator that the mail needs to be delivered to another desk.
- Graphics for computer desks, mail, and chairs
Zipped, I’m already at 11.5 KB. I won’t have room for sounds or music like I hoped, so that’s out. I also don’t have room or time for making the lobby room, so that’s also out.
I started working on the title screen, which will also show the controls (as shown in the header image). Then I forgot how to make a scrolling pattern for the title screen, even after consulting my own full game engine, so that costed me another day of just stepping away to remember.
Last day, in the last several hours, I put in the scrolling pattern (
moveTo, of course) and put in the envelopes dropping for the title screen. I still need to show the instructions of the game (deliver mail to desks in 90 seconds!), and an indicator of redirected mail. I had to abandon the graphics for the desks, mail, and chairs, so those temporary graphics are now final.
Finally put some overlay text for the beginning and the end, and showing “404 Employee not found; Moved to another desk” text as an indicator the mail needs to be redirected.
15 minutes left. Zipped. Shoot, 13.2 KB. Luckily I still had some debug and test code I can easily remove.
10 minutes left. Zipped. 12.9 KB. We’re good, time to ship this. Opened the submission page and uploaded the zip. While that’s being checked, I scrolled down and… shoot, I need screenshots. Out of panic, I was having trouble getting the right aspect ratio and scaling according to the image requirements, which took me longer than I expected.
Uploaded pictures and… submitted. Phew.
Of course the submission itself needed to be approved, which I did receive less than a day later, thankfully.
I told myself, I should never bring it down to the wire like that ever again. But I’m glad I was able to submit something instead of missing it.
Looking back at my previous entry for 2019, there is a big contrast to this year’s attempt.
Compared with the relatively relaxed 2019 entry
Turtleback is my entry for the 2019 competition. This is an entry where I learned my lesson from 2017’s entry, so in effect, I unlearned 2017’s lessons for the 2020 entry. And thus one of the primary reasons I’m writing this postmortem.
My goal for 2019 was to make a simple enough game so I can finally submit something. No complex algorithms, no collision code. Just a simple game. The game was essentially simplified to the core mechanic, I never got stuck at any particular part, and I submitted early. I should have taken these lessons to heart, but instead, I got overconfident from using existing generation code and wanted to take it to the next level (or, more likely, next 5 levels).
There’s a lot to take away from this, but first, let me list out the important ones:
- Simplify the game.
- Don’t get stuck in one part; move on to other parts of the game.
- Submit early; do not draw it out until the literal last minute.
Simplifying the game means to boil it down to the core game mechanic. In my case, the core game mechanic is to deliver mail to desks. We already had desks for the open office layout, with collision code that works. Collision is secondary to that goal, so I should not have been trying to work on a size-fits-all collision solution and abandoned the cubicles. Simplifying also reduces the chances of getting stuck in something complex.
The most obvious lesson to learn from is to not get stuck in any one part. The collision portion took too much time away from other parts of the game. I probably would have had better graphics, and maybe even a lobby, and properly code golf. I focused too much on one part and didn’t move on to other parts. This is also a lesson I should have learned from 2017’s map generation, as it took the longest at the time.
On another note, I honestly thought I was giving myself an edge by recycling an unfinished game for an earlier competition. Paired with the false memory that the whole thing was only 4 KB (it was actually 8 KB) and collision code that only worked on a grid, I was essentially fixing code from 3 years ago. The generator took up 50% of the total game size, and it probably would’ve been smaller to make crafted levels instead.
Submitting early should be a goal instead of submitting on time. This way, there’s some breathing room for final polishing, as well as not stressing on a deadline. Avoid the crunch!
This year’s submission has been a lot of fun. I would have liked to stream more of the creation of the game, but being stuck on collision code for half of the development is just not entertaining content. However, content IS content, so maybe I should have streamed it anyway. And who knows, I may have rushed myself to do other parts in the game for better content.
So, note to self for next time: Simplify the game, don’t get distracted by a single issue, and submit early!