Every year, from the 13th of August until the 13th of September, there’s a gamejam called js13kgames. The objective of the jam is to build a game that fits in a .zip file of max 13Kb. The nice thing about this jam is that there’s a special WebXR Catergory. When participating in this category you are allowed to use one of the provided WebXR frameworks, and that doesn’t count towards the 13Kb. The theme of the jam this year is Death. For a framework I chose to use Babylon.js. I’ve used it a while a go and would like to see where it’s at at the moment.
In this blogpost I’m going to keep track of the development, like a devlog. I started out doing that in my personal Discord ( http://discord.gg/J3j43p8) , writing a few lines pretty much every day after I done some developing of the game. In the end it will be a long list of small daily posts with thoughts and the process of building the game. Here we go!
The jam has started, and the theme is “Death”…
First idea… Beat saber, but you are the Grim Reaper and instead of 2 swords you hold a scythe. People come at you with arms in a specific position and you have to make a clean cut to get their souls…
Second idea. A Brookhaven experiment clone, in 13k. Hordes of zombies coming at you and you’ll have to fight them off.. Graphics will be the most challenging in this one.
It’s tough. Most ideas I can come up with are nice for games, but impossible to do in only 13k because they rely heavily on graphics. A humanoid type character is so hard to create in only 13k. I need to either come up with a very clever idea for doing 3D characters (animated with bones) or do something without characters. Anyway. The environment the game is going to take place is is probably going to be a graveyard or a morgue. I think a nice, dark, graveyard is possible.
It could be that I’m spending too many precious bytes on this character, but. I have a rigged character in WebXR 🙂 Now lets see what the impact of an animation is, or that I have to animate it from code. Or just make it wobble or something.
It starts to look like an active graveyard! 🙂
Worked on a flashlight and using the VR controllers in Babylonjs
Working on a baseball bat to hit the skeletons with. Maybe they should scatter into particles when they’re struck. Particles in the direction of movement. Or maybe you’ll have to hit the multiple times.
It’s a start:
I’ve added the start of walls to be able to create guidance for the player to where the skeletons will be coming from. You will start in a corner and skeletons are going to approach you only from 1 direction. After a few waves they will come from all sides. I also changed the texture of the baseball bat and removed the blurring from the shadows.
Todo for the coming days:
- Make the skeletons move towards you
- Turn the screen red for a moment when they hit your (not sure yet if you are dead instant or if you can take a few hits)
- Spawn the skeletons (preferably animate them coming from graves)
- Explode the skeletons into particles when you hit them and have the particles move in the right direction depending on the movement of the bat for optimal satisfaction…😈
I’m at 7Kb now with no real optimizations.
I might be pushing the possibilities of what can be fitted in 13Kb here, but I’ve implemented a simple entity component system (SECS 😂) . This makes it easier, for example to attach a mesh to a controller. I don’t believe that that is something that is in BabylonJS by default. Also, controlling various enemies and particle effects might be easier to implement this way. I am a little bit afraid that I might have to remove a lot of stuff in the end to compress it down to 13Kb. But, at this point I’m near 8Kb and I know there’s a lot of stuff in the scene file that can be removed and optimized. I plan on having the main game loop complete by the weekend. Thus at that point it should be possible to spawn enemies, kill them or they’ll kill you. No updated video today, since nothing has changed visually. Except maybe this experiment on the title screen:
This is generated from one of the sprites based on the lightness of the pixels in another canvas. With an added randomness. The fun thing with the choice for BabylonJS is that this year I need to think about complete other things than previous years. Where the shaders, shadows and post-processing of the image is no problem and comes out of the box, I need to think about how to make my enemies move.
I found someone to test my game…. it didn’t go well…. https://vm.tiktok.com/ZMNWWaXsB/
Making progress again. I’m already having the benefits from my own crappy ECS. Skeletons have “AI”, so that walk towards you no matter where they spawn. Right now there are 3 spawners in different locations in front of your. Also the collision with the bat is working. Next up is dying when a skeleton gets to you (or a couple) and adding the title/game over screens. At that point there’s have a “full” game and the fun begins. At that point I can start adding multiple levels or changes so they come from behind and eventually from all sides. And I can start to make the game look better by adding particle effects and such.
Today I worked on adding some particles when a skeleton is hit. That wasn’t as hard as I thought. Although I would really like to have the particles go in the direction of the swing of the bat.
I also added the start of game state management and a title screen. Lots more work need to be done here. I hope to be able to reuse most of the code to create the game over screen. Probable it’s going to be 1 string different.
One last thing I finally did is make a start of adding the sprite textures as a base64 encode webp image to the code. For the text I needed to have the string again. I have another place where 1 sprite is used instead of the entire sheet. That need to be replaced as well, hopefully the code to extract that 1 image for the ground texture will be smaller then the entire string.
Current file size: 9289 bytes
The goal for today was to finish the gameloop. To make it into a game you need to be able to die, to go ‘game over’. To get whole sequence to work I needed to have game states, track them, change them and have the game respond correctly. I added a switch statement to the RenderLoop to have the AI not running when on the title screen or the gameover screen. I also added a couple of Babylon Nodes (these are comparable to the base GameObjects in Unity) as parents of various things like the different texts that need to be shown and the controllers. By having these with a single parent I can just disable the parent and things do not show.
I’m still very happy with the choice to create a simple Entity Component System. It made things really easy to update in places. It is missing a way to communicate to the main script though, resulting in sometimes needed to directly calling methods on the app class. I don’t like this and it might be better to do this with events or something, but I only have 13Kb. And when I was writing the code today I was pretty sure I would go way beyond the limit. (spoiler, I didn’t 😝).
Biggest challenge today was an issue that came up when removing the enemies when switching to the gameover state. After removing the meshes and entities,and changing the state the RenderLoop still ran with the old state once causing a lot of errors because the entities were removed. I bypased this issue by adding a small delay between changing the state and actually removing the stuff.
Current file size: 9568 bytes
Today I finally figured out a way to have the particles fly in the direction of the swing of the bat (I’m thinking of changing the bat to a shovel to better fit the story). I also add 5x more particles. The more particles the better. Having these particles really make the game more fun. Next up is the UI and counting the number of hits.
Over the weekend I got this weird idea for backgound ambience. I wanted to try and generate a couple of different sounds with the Web Audio API. I’ve used this api in the past and it is really powerful. I started with creating a howling wind sound by generating noise and filtering that. The filter frequency changes slowly over time.
Having only wind is a bit boring. I searched around a bit and found a video explaining how to create a bell sound. Perfect! I added a looping timer that randomly plays a low bell sound every once in a while.
The last thing I wanted was the sound of crickets in the night. I’ve analysed a couple of cricket sounds and noticed it’s basically a tone with a couple of LFOs on the amplitude. So, I created that. I added a few lines extra to slowly and slightly change the volume and pitch over time.
Here’s the result, and endless stream of wind with bells and crickets:
Current file size: 9836 bytes
Big plans for today. When you are hit by a skeleton your are game over. But, I want to show how many skeletons you have killed before they got you. I used almost the same code for creating a texture that shows text with your score as I did for the title screen. Except this one is only shown when you are game over. The texture itself is generated each time you die.
I was on a roll last monday with generating background sounds, so I thought it would be a nice idea to do something similar for the soundfx. The audio library I’ve used in all my previous jam entries used a Flash tool to create the sound presets and, well, Flash is really dead now. I came across this MiniSoundEditor . It uses math to fill a buffer and that is played. I wrote a little bit of code to make the buffer play more efficiently in my game, and voila, a very small way to play sound efffects.
The only thing is, that at this point I just went over 10k, but I didn’t do any real optimization yet.
Current size: 10040 bytes
I really do not like the way the skeletons just pop into existance when they are spawned. Today I added an animation that make them rotate from lying flat to a standing position. I haven’t mentioned how to create this, so let’s talk a little bit about that. The way this animation is created is similar to how I created the walking animation.
First of all, there’s an editor/inspector you can insert into your game. There are a few lines in the codebase (that are automatically removed when building a production version), that show the editor when pressing Shift+Ctrl+Alt+I.
This tool is very useful to inspec stuff in your scene and debug issues that might occur. It comes with an animation editor as well.
In this you can create key frame animations that can be played in your game. I exported these and added them to my scene.js file manually. When a skeleton is spawned I play the ‘Rise’ animation and after a couple of ms I start playing the walk animation. Very simple stuff basically :)
Current size: 10126 bytes
NOOO! I found a bug in my build system. It was ignoring a couple of files :(. This meant that instead of having about 3Kb left, I’m already 4Kb over. There seems to be more going wrong now…
Ok. I managed to get it back down to just below 13Kb. Changes I made:
- Removed all the exports and imports
- Back to just concatenating all files
- Started testing the zip with advzip on linux instead of 7zip on windows.
- Removed the bells and crickets 😭 I loved those.
- Hacked the sound effect into Babylon instead of handling the AudioContext myself.
The reason for the weird changes in the build is that tools like Webpack and Babel add a lot of overhead. Just concatenating the files into one big one let you keep everything in separate files, and still have only one file without the overhead. Biggest downside is that things like autoreload don’t work anymore. I use Gulp solely now, with a couple of different tasks, a production that does everything as minimized as possible, a dev and a watch task. I run a simple-http server to host the game locally.
There are a couple of more places that need to be optimized, like the scene file (which is just a JSON file basically) and a lot more duplicate code that could be improved.
Over the weekend I didn’t spend a whole lot of time on the app. But I did a conversion of the scene file. The object shown in the game are created from code now. Everything that is not needed from the scene json is now not in the game anymore. Also, for the grave stones only the UVs are different per asset so instead of having all vertex data and indices for all 3 different grave stones I have them only once in the code. This brought the filesize down quite a bit and open the door for some features that the game really needs.
For example predefined levels. To get anything implemented this time I’ve decided to give the Level editor the amzing Xem created (yes, the same that build that audio tool). The editor creates a very compressed string that can be decompressed using a very small piece of code. After that I replaced the random placement of thumbstones and walls to be done by an interpreter of the level data.
Current size: 12174 bytes
I slowly start to run out of bytes :) Which means there are still bytes to use. So, I added 2 more levels. I also fixed a couple of bugs with graveyard facing the player. As you can see in the screenshot, the background is purple now and there are scary trees. There’s still a few bugs that need to be removed which need to be addressed. I also want to have a fade to back when switching from and to VR and when changing levels.
I also found a couple of places that had some bytes that could be removed…
Current size: 13102 bytes
Today I finished the fading between the levels and when entering VR. I think this does the game real well and makes it feel more polished. I’ve found an issue when switching levels and clearing everything from the previous level. This caused way to many skeletons to spawn. I also improved the algoritm for spawning a bit.
The last thing that was on the list and I didn’t think I’d have time or space for was text between the levels. But, since I already had some code to generate the text to show the score when you are game over, I refactored that a little bit and reused it.
Current size: 13296 bytes (16 bytes left)
Since there’s no space to add more features I did some playtesting today. And… Found a little bug when entering level 3: The path should be in a cross to indicate that skeletons come from all 4 directions, but it was showing only 2. After fixing the level, I went over the 13Kb limit again. After about an hour of searching and tweaking lines of code I managed to get it under again.
Man, the third level is hard :)
Current size: 13277 bytes (35 bytes left)