PC Games

Orb
Lasagne Monsters
Three Guys Apocalypse
Water Closet
Blob Wars : Attrition
The Legend of Edgar
TBFTSS: The Pandoran War
Three Guys
Blob Wars : Blob and Conquer
Blob Wars : Metal Blob Solid
Project: Starfighter
TANX Squadron

Tutorials

2D shoot 'em up
2D top-down shooter
2D platform game
Sprite atlas tutorial
Working with TTF fonts
2D adventure game
Widget tutorial
2D shoot 'em up sequel
2D run and gun
Roguelike
Medals (Achievements)
2D turn-based strategy game
2D isometric game
2D map editor
2D mission-based shoot 'em up
2D Santa game
2D split screen game
SDL 1 tutorials (outdated)

Latest Updates

SDL2 Versus game tutorial
Wed, 20th March 2024

Download keys for SDL2 tutorials on itch.io
Sat, 16th March 2024

The Legend of Edgar 1.37
Mon, 1st January 2024

SDL2 Santa game tutorial 🎅
Thu, 23rd November 2023

SDL2 Shooter 3 tutorial
Wed, 15th February 2023

All Updates »

Tags

android (3)
battle-for-the-solar-system (10)
blob-wars (10)
brexit (1)
code (6)
edgar (9)
games (43)
lasagne-monsters (1)
making-of (5)
match3 (1)
numberblocksonline (1)
orb (2)
site (1)
tanx (4)
three-guys (3)
three-guys-apocalypse (3)
tutorials (17)
water-closet (4)

Books


The Third Side (Battle for the Solar System, #2)

The White Knights have had their wings clipped. Shot down and stranded on a planet in independent space, the five pilots find themselves sitting directly in the path of the Pandoran war machine as it prepares to advance The Mission. But if they can somehow survive and find a way home, they might just discover something far more worrisome than that which destroyed an empire.

Click here to learn more and read an extract!

The Making Of

Introduction

Back in about 2014, I was looking for an Android game project to work on. I thought I would dip my toe into the world of mobile gaming and see how it all went. After playing around with various ideas, I thought I'd make an exclusive Blob Wars game. I figured the game could be set between Metal Blob Solid and Blob and Conquer. It would play much like the original Blob Wars, i.e., a 2D non-linear mission-based platformer.

Starting out

As this was a mobile game, I decided that the missions shouldn't be too long; I figured that mobile games are really something that lends itself to short play sessions, something you might do for 10 minutes on the bus ride home, for example. As such, the levels needed to be about half the size of Metal Blob Solid and shouldn't be able to be completed (in part) quickly. I also added in a feature that would mean that if the player exited the game mid mission, the state would be saved and they could resume play at a later time.

I wanted the game to be a little different from Metal Blob Solid, however. I didn't want the missions to purely revolve around rescuing the MIAs. And so, after some consideration, I added in feature of carrying the discovered keys between missions, so that they could be used to open doors and access areas in others that might be otherwise inaccessible. Since the game was set between MBS and B&C, I gave Bob the jetpack and aqualung from the beginning. There was a change in the behaviour of how the two items worked, however: both would now draw upon a shared power pool that would recharge gradually over time. I also made the enemies drop batteries that Bob could pick up to more quickly refuel these two items. Finally, I made the note that Bob has more health in B&C compared to MBS (10 vs 25 units). I figured that it would be fun to show how this happened and so added in some special items to find - hearts, to permanently increase Bob's health, and cells, to permanently increase his power capacity.

With that all worked out, I set about coding up the game, using graphics from the original MBS, as well as drawing some new ones for the new areas, items, and enemies. As I was already well familiar with Java development and had mucked about with the Android SDK for a time, the coding was somewhat straight forward. As always, creating the levels and everything else took the longest.

Mission design

By far the most time consuming aspect of the game was designing and testing the levels. Since the game allowed the player to take keys that they had picked up between levels, I had to ensure that it wasn't possible to get stuck and not be able to proceed. I solved this by ensuring that all the keys that Bob would need to complete the mission the first time around would be available on the level, and then added in extra doors and keys later on. This approach succeeded, as I was essentially making the levels so that they could be played through once and finished. I also wrote a script to parse the XML files and count the number of key types vs the number of door and card reader types to make sure they tallied up. This made sure that there weren't too many or too few keys in the game.

I then adopted the mission structure found in MBS, whereby finishing one mission would unlock others. The player would have a choice of which levels they wanted to tackle and in what order. At first I thought it might be fun to have all the missions available from the start, but this looked too confusing on the world map and would also mean that players might choose to tackle an outpost mission first (which features enemies that require more than one hit to take down) and thus be put off by both the information overload and the difficulty jumping all over the place.

I decided that bosses should be included in the game and chose to include those from Blob and Conquer, namely the elemental duo Blaze and Frost, and the EyeDroid Commander. The player is only able to defeat them in battle, not kill them outright. This is simply to maintain the canon of the story. Once defeated, these opponents will simply teleport out of the area. The one exception is the tank boss that Bob faces - that enemy can be destroyed.

Finishing the Android version

Once the Android version was complete, I uploaded it to the Play Store where it received a modest reception. To begin with, some players bemoaned the speed of the game. I discovered that while the game ran phone on my Galaxy S3 it was too slow on a lot of other players' phones. I investigated and found that my OpenGL code was the culprit, as I was using immediate writes rather than batching. After some investigation into texture atlases and the like, I was able to increase the game's speed considerably.

I'll admit now to not being overly fond of gaming on mobile devices. I don't think phones and tablets make good gaming devices and as such, at the time of writing, I have only made one other Android game: Three Guys. Attempting to play platformers and twitch games on a device where the screen is also the controller (meaning that your hands can obscure the view at times) doesn't lead to a good experience. Still, I was pleased that Attrition turned out well on mobile and was easy to play, given the number of controls involved. The launched ad supported. In a later version, I added in the ability to remove ads and unlock a cheat mode using in-app purchases. I then released bug fixes for crashes ever now again, but the game was largely finished with the 1.1 update.

Starting the C Port

In January of 2018, I was surfing the net looking at old stuff to do with Metal Blob Solid when I spotted on Aminet - the world's largest archive of Amiga-related software - that someone had recently updated MBS. The comments thanked the person who had ported the update, but one in particular stood out. The comment was asking for a port of Attrition. Further comments said that that would be impossible unless the game was open source (Attrition on Android isn't). This got me thinking. What if I were to create a desktop port of Attrition in C? I took a look at the Java code and decided that it would be possible.

I started by stripping down the code I used for The Pandoran War, keeping the sounds, graphics, input, and IO routines I had written, and using it as a basis for the port. I then began porting the map loading and rendering code. This was pretty straightforward and only took a few hours. I literally took the Java code, pasted it into a C file and then fixed all the syntax errors, changing things such as boolean to int, declaring private functions and variables as static, and moving all the public variables into a struct. After just a couple of hours' work, I had the map rendering:

With that working, I set about porting the game properly, doing the same as above but with all the other Java classes. This took quite a long time, several days in fact, and the Entity class that I had made to represent every object in the game, now represented as a struct in the C code, began to grow massive. For the time, I ignored the fact and focused on just getting the game up and running.

One of the obstacles that I had to overcome at the beginning was that Attrition on Android relies on XML, whereas The Pandoran War was using JSON for its data. I was much more familiar with the C JSON code I had worked with and so decided to convert the XML to JSON. This was a mostly easy process, as all I had to do was write a Java program to load the XML and then spit out the result as JSON, instead. It worked fine, but there was a number of manual tweaks that I needed to make afterwards, to make it easier to work with. Writing code to handle the sprite atlas came next. Then a few days later, I was able to render the enemies, items, Bob, and everything else in the world. Things were looking extremely positive.

I then turned my attention to the AI, combat, control of Bob and other bits and pieces. However, there was still one thing that was bugging me about the way the port was happening.

Inheritance and OOP in C

Attrition was designed as an Android game, therefore Java, and therefore OOP. C on the other hand is a procedural language and as such doesn't support things like overriding, overloading, or inheritance. For the most part, this wasn't an issue, except for the Entity object. In Attrition, an Entity is anything: Bob, a bullet, an enemy unit, a door, a lift, an item, etc. Entities always have things such as x and y coordinates, a sprite, a name, an id, and a width and height, and a health value, to name but a few. However, some other objects such a unit (Bob or an enemy) have a reload counter, an oxygen level, a weapon type, a flag to say if they were spawned in, and a pointer to the item they are carrying. Other things, such as a door, will have an open and closed state, a locked or open state, a speed value, and the name of the key that is needed to open it.

As I stated earlier, when I wrote the base game I simply lumped all these things into the basic Entity struct. This worked, but it lead to a problem: the size of the entity struct was about 1084 bytes in size, so just over a 1k of data. That means anything created in the game, be it a bullet or a bit of decoration, would consume 1k of data. Now, to be fair, on a modern system with 8GB of RAM (even 1GB), that's not such a big deal. If there were 1,000 objects in the world, this would only be consuming 1MB of memory. A drop in the ocean. However, I considered it sloppy and wanted to bring the value down.

After much Googling, I discovered a Stackoverflow post where a poster was asking a similar question. The accepted answer was to use a Microsoft extension that allowed for structs to be extended. Simply setting a compile option -ms-extensions allowed this to be done. The result was that I was able to inherit the fields from a base structs into a child one:

struct Entity {
	unsigned long uniqueId;
	int type;
	char name[MAX_NAME_LENGTH];
	...
};

struct EntityExt {
	struct Entity;
	char spriteName[MAX_NAME_LENGTH];
	Item *carriedItem;
};

struct Unit {
	struct EntityExt;
	char *unitType;
	int weaponType;
	...
};

struct Item {
	struct EntityExt;
	int startX, startY;
	int power;
	...
};

This brought the memory usage down and made me feel better about things (this is something I've always been conscious of, likely due to the days of coding on an Amiga and needing to ensure that games could fit into 2MB of RAM). One downside was that it involved a lot of casting, as linked lists could point to the basic Entity struct, but might be holding an Item. The cost of this is minimal, however. Function pointers helped with other OOP behaviour. Naturally, I could've rewritten everything from the group up and not followed the Java code so closely. But as the Android version worked fine I didn't want to spend months reworking the entire game engine for the sake of it. And of course I could've just written the entire game in C++. However, I've always had a love-hate relationship with C++ and any project I've worked on involving it has ended up being some frankensteinian mess. I chose to stick to basic C as much as possible. Might I use the MS extensions again? Probably not. This was a one off.

Desktop enhancements

Moving from a mobile display to a desktop brought a number of benefits. Both the available screen size and resolutions were increased, allowing for a more comfortable viewing experience, and the controls could be customised to the player's liking. The Android version's on-screen controls were fixed in place and couldn't be moved around. Controllers couldn't be used either. The only thing that could be tweaked about the controls was the intensity of the display, making them dimmer or brighter.

The increase in resolution also allowed more information to be shown. For example, on the world map in the Android version the player would have a separate inventory screen to show which keys they had. In the desktop port, the keys were displayed as part of the overall mission information. This was also true of the information screen during the mission itself. What's more is that during development of the C port I decided that it might be nice to be able to see the inventory on screen at all times. I therefore added in the inventory slots to the top right-hand portion of the screen (as well as an option to turn it off if people thought it got in the way). I found this very useful, as I could now see at a glance what I had, instead of having to pause the game and bring up the mission information screen.

I next moved the health and power detail from the top of the screen to the left-hand side. Spreading that information across the top worked at a lower resolution, but at 1280, it was both unnecessary and made things harder to see. In both B&C and the Pandoran War, I had put the player's health, shield, and other bits and pieces in the same place and they had worked out well. Some minor extra enhancements saw the ability to turn off the blood, resulting in no screams of pain, sprays of red, stains on the map, or gibs being thrown by defeated enemy blobs. The enemies now disappear in a puff of white smoke. This feature was appreciated by some whose children liked to play MBS but didn't want their children to see the playfield drenched in blood. For the sadists out there, there is also an extra blood option that throws out much more blood and leaves gibs around for longer. Fires (non-lethal) also take longer to go out.

Trophies, like those I added into the Pandoran War, were also added into the game.

With these enhancements all in place, Attrition on the desktop is overall a much better experience than playing on mobile. Desktop feels like a more natural home for the game too, and I myself enjoy playing it much more this way. A mission plus mode is also in the making at the time of writing, to become a part of the v1.1 release. Once the game is complete, it will allow the player to replay any mission they choose, with options allowing them to randomize the enemies, make the enemies stronger, remove all the doors (perhaps to play against a time limit in a later update), need to defeat all enemies (no new enemies will spawn in) and finally to mirror the world. This v1.1 update will probably arrive sometime in late 2018, although it can be played right now in the development branch on github.

Bugs and problems

Like MBS, Attrition features a persistent world design. Missions retain the state they were in when the player left them: doors that were opened stay open, items move to new locations remain there, enemies (other than those spawned in) will be in the same place that they were when the player departed. This system is great when it works, as it helps to make for a more immersive gaming experience. The major issue with this system is that if something goes wrong it can lead to game breaking bugs.

The biggest problem that I encountered was with the keys. These are taken with Bob once the mission is complete (or when he manually exits upon a revisit). Though I followed the Java code closely, I made some tweaks to the saving logic and this meant that under certain circumstances the keys that were picked up were not saved into the player's inventory. This meant that several times I got to the end of the game and found that I didn't have the keys I needed to open some doors and access certain areas. This baffled me, as I have finished the Android version multiple times and never come across this problem. For a long time, I went over the converted XML files to see if something had been dropped or if it was possible for keys that enemies were carrying to not be dropped when they were defeated. Eventually I discovered that the bug only occurred when revisiting a previous level, collecting a key, exiting the mission, and then quitting the game completely. The mission state was being saved (and thus the key being removed) but the game itself wasn't being saved. The key was therefore lost forever. I fixed the problem and was then able to perfectly finish the game afterwards.

Something else that was quite amusing was that, having not played the game in a number of years, I had forgotten how some of the puzzles worked and what I was meant to do in order to progress some missions. This led to me tweaking some of the levels for a time (manually, as I have since lost the map editor I made for the Android version and didn't have the patience to create a new one), until I then realised how that segment was supposed to play out.

Other little issues included some of the items having the wrong graphics at first, due to the way data was being loaded. All in all, however, the port went quite smoothly.

Finishing up

With the game all finished, I uploaded Linux and Windows builds to itch.io, for players to buy. While the game is open source, I opted to withhold the data files that define the maps, missions, sprites, etc. from GitHub, instead charging a modest amount for them. At one point I offered the data files from this site, but this got complicated when I realised that any updates made to those files would become a bit of a logistical nightmare when it came to notifying those that had purchased them.

A number of issues cropped up on the first day: the game would crash whenever a player picked up one of the heart or cell upgrades. I discovered quickly that this was because the game was attempting to save a screenshot of the trophy that had been awarded. While this worked fine for me, it didn't for others. After working through things, I simply decided to withdraw the feature. It didn't add much to the game and was of no major loss. A few compile issues were nixed - later versions of GCC didn't like the code that earlier versions had allowed to compile. These were also easily fixed.

All in all, I'm very pleased with how the port went. It was easier to do than I expected, with the vast majority of the porting time being spent on testing the game rather than overcoming technical issues. I think the engine works better than the previous Blob Wars games and would serve as a good basis for a remake of Metal Blob Solid and perhaps even a 2D remake of Blob and Conquer in the future. However, at the time of writing I've no firm plans to do so. Maybe one day.

Screenshots

Statistics

Total development time    : ~9 months - Android
                          : ~3 months - C port

Lines of code             : ~19,000 - Android
                          : ~28,000 - C port
Size of source            : 563K - Android
                          : 746K - C port
Size of data              : 1.5M
Size of graphics          : 4.5M
Size of sound             : 1.0M
Size of music             : 22.5M

Number of missions        : 27
Number of trophies        : 32

Estimated gameplay time   : 6 - 7 hours

Mobile site