Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Right after the 2017 js13k comp ended (please don't look at mine from that year) I decided to look into ways that I could improve compression. My game barely fit two levels and two songs with png compressors and 7z ultra compression. I created a folder with some of the test files and found out that PPMd was pretty much superior to deflate when it comes to text. Turns out Windows couldn't even extract it, so that idea was thrown out.
Later, in February, I decided that I was going to write a 3D game engine for this year's competition. Many ideas had gone through my mind, and I wanted to make sure I got ahead so that I could have enough time to work on it with school starting (spoiler alert: I ran out of time.) Originally it would be a first-person game in a city, trying to break some sort of curse (see possible inspiration, "The Witch's Isle".) That ended up sounding to complicated and wanted to change it up by making a puzzle game. At first, it was going to be some kind of puzzle switcher. At this point, the engine was already decided to be a voxel-based engine. Only using a school Chromebook and Drive Notepad, I ran various tests to see what the best way would be to compress models. The first arrow model seen in the chiisai repo in March was made only using drive notepad. The original page was also made on that Chromebook, testing the model format in layers:
The format explained (kind of):
(The repo model is "17773034740213534012362400337340", so minus the 1777 and 0 at the end, it's been the same)
Bonus: after I copied it from the chromebook to the Mac, I made some more models: https://www.youtube.com/watch?v=7wQNnEY5vuM
It was a start, but not by much. The format involved drawing volumes from two different points. The original format only allowed for 8x8x8 models. Models also had to be created manually (see code in image above). At first, creating a program to automatically do this for me seemed like something too difficult to actually make. I started building levels sometime in the middle of January. The idea was that there were walls in the way and you could flip to the other side but you would have to stay in the "same location". Pretty standard puzzle stuff. For some reason I still have a screenshot of a MagicaVoxel render of the map in the repo:
(The funny thing is, this game was actually being called systems way before the theme was announced so it ended up kind of working out.)
After that was done, I spent a good amount of time trying to actually get some 3D working. Originally, I wanted to try using CSS3D since I thought it would prevent me from having to learn WebGL and manually creating models. After some fiddling, I decided that the performance hit and no shaders wasn't worth the size. In somewhere in February I started to create some WebGL sample programs.
I mainly edited the MDN 3D WebGL tutorial to start the engine. My biggest fear of making an engine was having matrix multiplication, inverse, etc. take up a lot of space. Positioning and rotation have to have some kind of view matrix, and there are three ways you can do it:
- Multiply matrices by individually calculating each cell (fast but large)
- Multiply matrices by using for loops (slow but smaller)
- Don't multiply matrices at all and precompute them
Before, I was using Mathway to try and solve for matrices. Eventually, I found Algebrite and was able to get the matrices multiplied beforehand instead of multiplying them at runtime. This still took a lot of fixing and a week of headbanging, but eventually I got the spinning cube back into the scene without any weird bugs.
Once that was done, it was time to load the model in. It didn't take too long and by no time I had a spinning arrow model from the one I created on the Chromebook. Initially, the "voxelizer" created individual cubes, but this was later combined into the original volumes for performance reasons.
The spinning cube was great, but there was no camera. The code I was using let me move objects around, but I couldn't look around. It just wasn't a thing. It was probably the end of March when I stopped development on building the engine. A very crude prototype of voxelbox was created in Java that supported 8x8x8 models. Color wasn't even supported until it was rewritten in C#. It probably took two weeks for this to be finished as I had a lot of other things going on at this time and I kept messing up in the stupidest ways possible.
In April, the idea was breaking out of a prison. This is where the idea of using MagicaVoxel for designing the levels started. The idea changed sometime around the end of May with an investigative horror game where you investigate a murder in a locked down hotel building. I started designing a few of those levels in MagicaVoxel:
(The room in the far back is in the chiisai repo. This level was built off of that room after the first commit in July.)
Pretty late on in June, I found a website with a script that calculated a matrix from an eye position and rotation. It worked perfectly first try and with a little modification I got my (no longer spinning) arrow with fps controls. Here's the arrow model in the chiisai repo:
The format was created with numbers because I believed this would compress better than bytes, even if it meant taking up more space uncompressed (later, I actually learned how deflate actually worked and made a thermal view for zip files and a Huffman tree viewer). The 8x8x8 limit was an artificial limit because of the ten digits. At first, I wanted to try and avoid using anything bigger than 10x10x10 to avoid using letters. I ended up adding support for it anyway to test a complex model: the MagicaVoxel icon model. Other than a few minor color things, it worked mostly fine and I made my first commit on the repo.
The idea about the hotel stalled when I couldn't come up with anything interesting to do in such a small area and without the camera being blocked by walls. Looking back, I probably could've made something pretty cool out of it, but hey, what can I do about it now? With other things going on (I just finished Hollow Knight around this time and was developing some tools for it), I only began working on the scene exporting tool in late July. The front room of the ship was built and into the game in early August. I started to move into the school around this time, so I didn't have much time to do anything for a while.
During the weekends we had free, I spent all day working on building levels and adding code. A week after competition start and I had managed to get both the front and back of the interior part of the ship done, the menu, the svg converter, the UI, and the stars. Originally the game was going to have an intro cinematic, but I didn't want to bore anyone and it would've taken up valuable space for something that I could leave out. The story was going to be put on the computer on the left but that never happened because I ran out of time.
(It was almost done too! I don't know how I couldn't make the time for this.)
The game was also supposed to start out in a ship with red blinking lights where you would have to investigate the bottom half of the ship and repair it. That also didn't get added so there's just an empty room on the bottom that doesn't do anything.
Eventually, I got around to making the planets. I had no idea what I was going to put on them, so I just put security cameras because why not right? Using the new model rotation added recently, I was able to get a camera and "laser" or line of sight added. I had to manually place them by guessing but at least I was able to get them working at all. The cameras didn't do anything at all until the last week when they were poorly added with a restart (I wanted the room to turn red and a fade to black but nope).
Around this time, during creation of the first shooting scenes, the game started lagging pretty badly, down to 10fps. I spent a few days that I could've been working on the rest of the game trying to fix the engine: removing arrays where possible, changing some functions to use global variables, etc. The fixes didn't even work that well and in the end, it seemed that closing and opening the tab fixed the GC problem.
The shooting scenes were also going to be before you reach the base. I could've done that, but I don't exactly remember why I switched it at the last second. Regardless, I think those turned out okay. Originally there were going to be lives, but I ran out of time for that too and just added a score counter on the last day.
The space station was originally much bigger too. It was going to be where you find various items in beakers around the lab and mix it to create a substance to open a safe (see possible inspiration, "Submachine 4").
(The models in the lab on the space station were first. I ended up copying them over to the bases.)
A problem I started running into around this time was my terrible management of models. The idea initially was to have scene and model generation automatically edit the data.js file, but I ended up copying all of the codes and scenes manually into the file. At least six or seven times I ran out of space in the array and had to increase the limit while pushing all of the indexes pointing to the data after it up. It was a pretty stupid idea to put it all in one array, but I didn't want to risk messing anything up.
For the second time in a row, I went home on the weekend and uploaded the wrong file for the project and left the correct one back at school. I lost a bit of time but tried to design new levels and combine them later on. I couldn't think of any cool way to make the cameras new without becoming stale, so I took a risk and tried to make cameras go through walls:
(I was told by many other people that the camera should've been a cone shape. That would've been great, but the format only supports cubes and not rotated models. It wouldn't have been impossible, just a lot of work for something that didn't really matter at the time.)
Obviously, it wasn't as simple as just putting a wall there, but it was still a problem. The problem still never really got fixed. It involved placing boxes in the range of the camera I wanted to block and use some GL magic to block the laser from showing.
(Yes, I got this idea from a Minecraft reddit post.)
The last few days were pretty busy too. I already had 3 essays and a presentation due and I was wasting time on a game that was hardly done. A week before, I taught one of my friends how to build some bases in MagicaVoxel. The levels got built, but some of them were the wrong direction and some were floating. For some reason I never had that problem and just lucked out that all of my levels were in the right direction on the right vertical offset. The offset was an easy fix, but all of the maps had to be manually rotated since MagicaVoxel's rotate function just gives the models a rotate value, rather than actually rotating the model. The last two days before the competition were adding the cameras and wiring up the terminals along with docking.
The last day I did pretty much everything. I set up some bad tutorials, redid the space station and created the water, acid, and space shooting scenes. It was 11:30pm when I decided to make the boss the "Space Octopus". I dunno why he looks so happy but here he is:
He was supposed to be much harder but I had no time to playtest with it being almost midnight. I cobbled everything together, compiled it (unsurprisingly at 12kb, could've been smaller), and uploaded it without testing it at all past the main menu. If I had taken a little bit more time to test it I would've noticed that everything was way too dark. To see what size my game was currently at, I would copy over the precompressed shaders into the small js file. My folder was getting a bit disorganized as the competition went on:
Music was also something I meant to add. Last year's submission used OrgMaker (which is pretty good btw) and I wanted to try to use the "better version", PxTone. Toneplay was supposed to be a PxTone player using an almost number only format, similar to the model format. I didn't like how PxTone worked and I switched back to OrgMaker, writing a tool to convert org files to the new format. Sadly, the playing part never really got implemented, and most of the music hadn't been written anyway. I had one for the acid planet done but that was about it. I was considering on the last day setting up one song to play during the whole game in something like miniMusic but I ran out of time to do that.
Anyway, that's about it. Maybe next year now that I'm a "professional" with my "engine", I can make something a lot better than this year's. It was a pretty stressful competition for me but hopefully next time I'll be more prepared :)