I'm in!
This'll be my second Ludum Dare, after LD32 all those years ago. Again, I'm entering the compo. I'll use C++ with SDL to program the game, FL Studio to make the audio, and GIMP for the art. Good luck to everyone!
This'll be my second Ludum Dare, after LD32 all those years ago. Again, I'm entering the compo. I'll use C++ with SDL to program the game, FL Studio to make the audio, and GIMP for the art. Good luck to everyone!
https://ldjam.com/events/ludum-dare/47/fly Recorded a playthrough of my game: https://www.youtube.com/watch?v=kmcIkc4-o5A
Hi! I made a game that fits inside a tiny 47KB executable file. You can play it here, https://ldjam.com/events/ludum-dare/47/fly, or watch a playthrough here: https://www.youtube.com/watch?v=kmcIkc4-o5A
So how does it fit in 47KB?
Step 1: Simplifying the art
It's no secret that blocky pixel art uses less asset space than 4K textures and 3D models. So unfortunately if you want to make tiny games, then you'll have to make it 2D. However, I was inspired by a previous Ludum Dare winner, Cat Planet, for a good art style that fits within these restrictions. Fonts are also pretty large, so I decided to hardcode all the text messages by pre-rendering them out as images. I disabled anti-aliasing in GIMP to help with compression. For compression I used the PNG format, which is fairly standard. To decode these images (without bringing in extra library dependencies that'd bloat the code size), I used Windows Imaging Component, which has been fairly standard in Windows for a while now. Since I was able to prepare the images in the format I chose, I didn't bother adding in code to do color format conversions. This meant loading textures was very simple - only 22 lines of code!
Step 2: Simplifying the music
Modern music compression is pretty good. The Opus codec is made freely available and can compress audio file to really small sizes with no noticable loss in quality. However the files wouldn't be small enough for our 47KB target, and Windows doesn't come with a Opus decoder builtin, so I'd have to include an extra library to do that, which would be adding minimum of 100KB. So I needed a better solution. So, I decided to use General MIDI files. Since Windows 98, Windows has licensed a soundfont from Roland, which provides a variety of instruments of playing MIDI files. MIDI files contain only the instrument selection and notes to be played, rather than raw sample data like other audio formats. To play a MIDI file, first the game copies it out of the executable (I'll talk about this later), and then uses the ancient Windows API of mciSendString to start playing the file. It's that simple! I also decided to not add sound effects, because during early playtesting I felt they weren't necessary.
Step 3: Simplifying the game logic
Since I wasn't using an engine, it was completely up to me how to structure the game logic. The Windows platform layer exposes a very simple interfaces which allows the game to query keyboard input and then draw textures to the screen. For the game logic, I used a similar system that I did for LD46, and made a basic entity system. During startup, the game sets up entity "templates", giving them a unique tag, a texture, a width and height, flags (e.g. the kill flag was used to mark any entity that killed the player on contact), and callbacks for different game events that are used for any entities using that template (create - called when an entity is created, destroy - called when an entity is destroyed (this only happens at the end of an update), step - called 60 times per second per entity, and draw - called to draw each entity). Each room in the game stores a world ID (to determine the background color and music), and a list of entities in the room. Each entity is specified by the tag of its template and its X and Y coordinate. When the game switches room, all entities (except the player) are destroyed, and all the entities in the room file are created. The game only has a few different entities templates - the player, blocks, checkpoints, moving blocks, star particles, the collectible powerup, a show message object (that fades in and out a message image), the collectible key, locked doors, and the end marker (placed in the final room to end the game). For collision detection I wrote a single function called FindEntity. As arguments it takes a rectangular region of the screen to look for entities, a tag of the type of entities to match, and optionally an specific entity to exclude in the search. The tag can also be a special value to indicate the search for is for all entities, or any entity with a specific flag. This function is general enough to implement all types of collisions I needed. The entities are stored in a single fixed-sized array (it's 1000 spaces large, which is more than enough for the rooms in this game). This meant I didn't have to do any dynamic memory allocations at all in the game! (Although I presume Windows and OpenGL are doing lots behind the scenes :smile:).
Step 4: Tying it all together
By default, the Microsoft C++ compiler includes the C standard library. This makes even trivial programs like hello world take up ~400KB executables. After some shenanigans, you can disable it, and instead use a DLL included with Windows called msvcrt.dll (you're not technically supposed to rely on it, but I don't think it's going anywhere any time soon; Microsoft doesn't want to break compatibility with programs that do use it). This massively reduces the executable size. The next step is to put all the game's assets inside the executable - the room data, images and MIDI files. Otherwise I'd have to distribute the game as a zip file, which is incredibly inconvienient for the user. I wrote a tiny program to do this ages ago. It searches a folder for all the files in it, and then generates a C header file, that can be included in your source file, which contains all of the files as data arrays, that are then placed directly into the executable by the compiler. Finally, the executable is around 100KB in size. This is stll too big! But luckily there's a program called UPX that magically compresses your executable and bundles its decompressor right in the executable. I won't pretend to understand how it works, but that got the executable down to around 40KB - too small! So I padded the end of the file with zeroes in a hex editor, that luckily Windows ignores, until it reached 47KB. And that's it!
Thank you for reading. Why not give the game a try? :smile: