Random Learnings from Entering JS13K Games 2019
The JS13K Games is an annual, month-long coding competition where the aim is to create a web-based game on a theme with a size of only 13 kilobytes. I like to use the competition to find dedicated time to learn new skills and refresh old ones.
I have entered the JS13K games competition twice before. With Element War in 2014, I used it to learn HTML canvas and then again in 2016 with Escape from Maze 13 to learn ES6 without frameworks. Both times I learnt many new things that have helped me back in the day job (web developer) along with many that I will probably never use again.
If you have not played my game Flight Back Home why not try it out. As a background, it is a hybrid of HTML5 Canvas and HTML elements to create a repeat after me game. I also encourage you to check out the other 2019 entries as there are many great games.
This post is on just a few of the random things I learnt or was reminded of this year.
Holding Back, Stepping away and Planning
There are many ways to approach the competition. I had made the mistake many times before of diving in and writing code with the first half baked idea that I had thought of.
This year I consciously decided to take the first few days to think, research and explore before going full steam ahead. I had a whole month after all, and a few days considering ideas would save re-work later. This strategy generally worked, and the idea I initially had was scrapped before writing any code.
Many of the best ideas came when away from the keyboard. It has been well documented the many ideas come when away from the task in places like the shower. I was often reminded this throughout the month.
SVGs to Make Patterns
Early on I decided to use a hexagon grid and with the limit of 13K I set about looking how to generate it in the smallest and quickest way. I looked at options including HTML5 Canvas, using CSS to make hexagons and SVGs.
I had often use SVGs and as they are lightweight they were perfect for this. What I did not know is that you can tile them as a background. There is a great post with more details on sitepoint.
In the end, the final version did not use tiled SVGs as I needed to interact with individual grid cells. Though I can see these could be great for other games or splash screens in the future.
Optimised SVG
In my previous JS13K entries I had used png images and optimised them using tiny png. This year I decided to use an SVG image for the plane to try and retain more detail. I had never looked at SVG optimisation before, though as SVG files are XML I imagined them already to be small.
It turns out after experimenting with different programs each saves different amounts of data in the SVG file. Much of this data is not needed and is either metadata or declarations of default values. Luckily InkScape has a way of removing this.
Hexagons are not what I thought
You will see hexagon patterns in all sorts of places both man-made and in nature, though I had never really thought about them in detail. I learnt that there are two ways to tile hexagons, they are not the same width to height and many other random hexagon facts.
The width to height ratio caused collision detection an error early on in the game design. The initial investigation led to trigonometry to calculate the correct values, however, taking a deeper look at the ratio of a regular hexagon is fixed at 1:1.1547005. This discovery saved both trying to remember maths but also all-important bytes in the final filesize.
If you ever want to know more about hexagons and hexagon grids then there is an amazing post at red blob games
Hexagons Maths is Hard
I chose a hexagon grid to make the game more visually interesting, however, this led to many new challenges. The first was the maths needed to tile hexagons as the offset column is a different width to the non-offset columns.
As I built the game I then needed to navigate around the grid and find if spaces had been visited before. In a normal grid +1 on X-axis moves you to the right and -1 to the left however in a hexagon grid it is far more complex.
Once again the red blob games page had great detail on how to achieve the navigation.
Native Modal Dilaogs
I have implemented modal dialogs many times in my career and I decided that I would use HTML dialogs rather than create these in the HTML canvas. For me this would make them quicker and easier to style and manage things like aligning text.
I had heard of native the HTML dialog element but had never used it. Using the new element would mean the code was short. It seemed as simple as replacing DIV with Dialog and then call open or close in JavaScript which was ideal.
<dialog>
<p>Content of the Dialog</p>
</dialog>
const modal = document.querySelector('dialog');
modal.showModal();
modal.close();
In chrome this worked well however it turned out that Firefox does not support native dialogs without a feature flag and the polyfill turned out to be 25.1 KB!!
Further research showed that firefox has the CSS in place without the flag. The polyfill was also fully featured supporting many browsers so I could create a cut-down version that worked just in the latest firefox and chrome.
function show(selector) {
const modal = document.querySelector(selector);
if (isNative()) {
if(!modal.hasAttribute("open"))
modal.showModal();
} else {
modal.setAttribute('open','');
const backdrop = document.querySelector("#backdrop");
backdrop.style.display = "block";
}
}
function hide(selector) {
const modal = document.querySelector(selector);
if (isNative()) {
modal.close();
} else {
modal.removeAttribute('open');
const backdrop = document.querySelector("#backdrop");
backdrop.style.display = "none";
}
}
function isNative(){
//Native is not supported by FF yet :(
return typeof HTMLDialogElement === 'function';
}
There will always be a bug
It was three days before the end of the competition and I had decided to draw a line under what I had done so far just in case there were any issues. There were extra features I could add but I felt now was the time to finish.
I ran the build process to create the zip file and ran one last playtest before submitting. There was an issue, cells I clicked were off by one grid cell. This was a disaster and the game was unplayable. I opened the dev tools in chrome to take a deeper look. Upon opening the tools it was no longer an issue, closing the tools once more and it was still not an issue. I then refreshed the page and the issue came back, the following refresh and again and it went away!
After a day of trying many things out, I discovered the answer. It turned out to be dependent on how the browser loaded the HTML elements above the canvas. Sometime the Kontra mouse script would load before the canvas had been pushed down the page by other elements and sometimes after.
The point is that there will always be an eleventh-hour bug and I was reminded yet again why I always allow extra time for these things.
Looking Back
Once again I learnt a lot from developing my game this year and I would recommend any developer to enter even if they have never written a game before. The JS13K Games community has been great giving excellent help and input on social media and their slack channel.
For my game, there are many things I would have done differently however I try to remember there are not bad choices just decisions that lead to the next challenge from which we can all learn.