The Making of The Legend of Edgar
I'd always wanted to write a 2D platforming game, and initially it was going to involve a knight entering a castle, to rescue a princess. Pretty standard stuff. I was going to have features like being able to drink potions to give him wings and fly for short periods of time, but this was just something I thought about, and never actually committed anything to paper.
After completing Blob And Conquer, Stephen stopped making games to pursue other interests. I decided to add some tutorials to the Parallel Realities pages to give people who were just starting out making games a bit of a leg up. They started out as very simple things, such as opening a window, displaying an image and playing a sound. I then added more tutorials to demonstrate moving a sprite around, firing bullets and dealing with collision detection, so someone could make a simple space shooter. I then did a tutorial on tile-based collision detection, essentially allowing someone to develop a platform game.
Halfway through one of the tutorials, I realised that I'd written enough to actually start making a fully fledged game of my own.
I had a fairly good idea about what the game would be about and that the player should be able to return to previous maps, rather than treating them as separate levels that the player would progress through. Allowing the player to wield different weapons would allow for some weapon-based puzzles and also increase variety. An inventory system would therefore be needed. I went out and bought a notepad so I could jot down ideas as I came up with them, as well as sketching out what enemies should look like and design the maps. Sometimes I'd come up with an idea when I was out or at work so I'd either note it down in my phone or email it to myself, because otherwise I'd have forgotten about it by the time I got home. This only happened a couple of times but fortunately something else jogged my memory a couple of days later.
I treated everything in the game (enemies, items, weapons) as an entity, with a field denoting what its type was. Furthermore, every entity had a name which was used to determine what properties file to load up. Certain entities, such as keys and doors, also had additional information stored so that the player could identify what they were or what they required. For example, a door might require a item in the player's inventory called "Forest Cell Key".
The entity information would be saved in the map file and read in when the player entered that map.
I decided early on that the easiest thing to do would be to store an entity's information in a properties file. This would allow me to modify information without having to compile the code every time. The properties file would store information such as the type of entity, its sprite file, its animation file and its flags (such as whether it could fly, was invisible etc.). Some of this information would be permanently stored in the map file that it was added to (such as health), but other information would always be read from the properties file.
Sprites and animation
The first problem I encountered with writing the game was dealing with loading sprites and animation. Initially, I had a text file for each entity's sprites, which listed the sprite's filename and its id. I could then reference the sprite's id in the entity's animation file. The sprite file would contain:
Sprites 0 - 3 were for Edgar's walking animation. The corresponding animation file would then contain:
Meaning that when the WALK animation was set, it would loop through 4 frames and display sprites 0 - 3. The number after each id is how many frames the sprite would be displayed for, before moving to the next one. The biggest problem with this approach is that the sprite numbers are hard coded and adding or removing frames would result in having to juggle everything around. I ditched this method and made the code determine what the sprite id would be when it loaded up the images. The sprite file then simply contained:
The animation file would stay the same. When the code loaded up the sprite, a unique value would be assigned to it and stored in an array. The animation file assumed that animation frame 0 would be the sprite on the first line of the sprite file. Frame 1, the second line, and so on. In the end, I ended up with something like this:
gfx/edgar/edgar_walk_00.png would be assigned to sprite index 56
Frame 0 of the WALK animation maps to sprite index 56.
This solution worked out really well and saved me a lot of hassle going forward. I then started adding more information into the sprite files, to create bounding boxes so that a sprite's collision box wasn't necessarily the whole image. This was used for a couple of enemies, such as the Floating Snappers.
The size of the maps in the game were hard-coded, since they were just massive arrays. This worked out OK to start with but before the first release I realized that the map size was too small. I increased the size and ended up making them bigger than they actually needed to be, but this was OK since having wasted space was better than having to go back and increase the map sizes halfway through the project.
The map file contained information about the name of the map, the tile set to use, the music file to play and the entities that were initially present in it. Whenever the player moved from one map to another, the game would store the entity information for the map the player had just left into a persistence file. Subsequently, whenever a player entered a new map, the game would check the persistence file to see if the player had already visited the map. If they had, then the game would load up the entity information from the persistence file, rather than the map file. This worked out pretty well in the end, the only problem being that if a player was running away from a monster and exited the map, upon returning to it, the same monster would still be bearing down upon them.
The map editor
When I first started out, I just used a text editor to place a few tiles into a file and added Edgar and a chicken (more on these later). When I was satisfied that it all loaded up OK it was time to make an editor, to allow me to place tiles and entities more easily. I put together a very simple editor that allowed me to toggle between placing a tile and placing an entity. I then added small features such as filling in an entire row with tiles and snapping an entity to the grid, rather than being able to place it freely. Once I'd placed all the tiles and entities I'd go into a text editor and adjust the data.
|The minimalistic editor|
Scripting was possibly one of my most favourite parts of the game to code. It allowed me to make the characters walk around, talk, give the player objectives to complete, and so much more. As an example, here is the script run when Edgar encounters one of the hidden bosses, Azriel:
MUSIC FADE_DOWN 3000
LIMIT_CAMERA 1184 128 1824 576 TRUE
WALK_TO EDGAR 1260 522 WAIT
TALK ??? Who dares pillage the tomb of the great warrior Ivan?
WALK_TO EDGAR 1640 522 WAIT
WALK_TO EDGAR 1295 522 WAIT
SET EDGAR FACE RIGHT
TALK Edgar Who said that?
TALK ??? Insolent cur, you will suffer for your disrespect
SET AZRIEL PROPERTY MENTAL 1
WHILE_NOT AZRIEL MENTAL 0
TALK Azriel I, am Azriel
Most of this text is probably self explanatory, but I'll go through them line by line:
Fade down the music over 3 seconds
Limit the speed of the camera
Limit the camera's position. TRUE means that Edgar is constrained to the camera's bounds, rather than the map's bounds
Make Edgar walk to the coordinates 1260, 522. WAIT means that the script will not continue until Edgar has reached the coordinates
Wait 30 frames (0.5 seconds) before continuing (1 second is 60 frames)
Display a dialog box. The name of the speaker is the next word and will be displayed in yellow. The rest of the text is the actual dialog. The script will wait until the dialog box is dismissed
Make Edgar walk to the coordinates 1640, 522. Wait until Edgar has reached these coordinates
Wait 0.5 seconds before continuing
Make Edgar walk to the coordinates 1295, 522. Wait until Edgar has reached these coordinates
Wait 0.5 seconds before continuing
Make Edgar face to the right
Display a dialog box
Display a dialog box
Set the property "Mental" of the entity called "Azriel" to 1
Set the "Active" property of the entity called "Azriel" to TRUE
Do nothing until the property "Mental" of the entity called "Azriel" is 0
Wait 1 second
Display a dialog box
Set the "Active" property of the entity called "Azriel" to TRUE
Scripting allowed me to quickly create new events or adjust them without having to recompile the code every time. There are scripting engines out there, such as Lua, but I didn't want to spend time learning them or get 75% of the way through the project only to discover that it doesn't support something unusual that I wanted to do.
One of the trickiest parts of the game was keeping it fresh. There are 26 maps in the game, so making sure that the player didn't start experiencing déjà vu, I had to come up with something unique about each map (or at least a couple of new enemies). For example, in the Laboratory I came up with the idea that the player could drink a potion which would turn Edgar into a monster that could swim through water. The Left Tower contained no enemies at all, but had some memory puzzles involving teleporters or endless corridors (if the player chose the wrong path they'd simply be warped back to the start, giving them the illusion that they were walking forever).
A couple of my favourite items were the Ice Spray, which created ice cubes in water that the player could use as floating platforms, and the potion that turned Edgar into a Slime.
Right from the start of the project I knew I wanted the game to have joystick support and configurable controls. I already had a PS2 joypad for playing MAME and I wanted didn't want to be hunched over a keyboard playing the game (with keys that I couldn't configure). Adding support was pretty straightforward and well received by players who appreciated being able to modify the controls to their own liking.
I didn't want Edgar to be the sort of game that featured just 4 base enemies, simply colour swapped or tweaked for appearances later in on. I therefore did some brainstorming with my notepad and came out with as many unique enemy types as I could think of. Here are a few of my favourites:
Judging from some of the comments I received, some people found this enemy quite tough. All it would do is fly back and forth and if it spotted the player, it would flash the screen. If the player was in its line of sight and were facing it then Edgar would be stunned for a few seconds. A Gazer would sometimes drop its eye when it was defeated, which was needed to progress further in the game.
The Centurions weren't particularly tough, but they had a lot of energy and their attacks couldn't be blocked. The attack consisted of smashing the ground with their pile drivers, which would stun the player for a few seconds if they were standing on the ground. The safest strategy was to jump while attacking them.
The tortoises were great enemies. I wasn't planning on having more than one type, but after Edgar collected the Fire Shield, I decided to have another enemy that could spit fire. It then occurred to me that I could have a tortoise that spat fire and one that could produce ice. I then decided that I could have one with the powers of all three, that would feature as part of the optional quest.
While harmless in itself, the whirlwinds could suck in the player and spit him out, removing any equipped weapons in the process. This could be quite annoying if the player was trying to attack another enemy at the same time. The whirlwinds were relatively weak and could only withstand a few hits, but they could reflect projects, effectively making the bow and arrow useless against them.
While not strictly an enemy, the chickens feature as part of the first quest the player has to perform. Initially, the player had to round up all ten of them, which was incredibly tedious and wasn't received well. I then came up with the idea of requiring the player to only capture three of them, and if they caught more then they would be rewarded. Because of the response to the chicken quest, I decided that it would be fitting to feature them in the game's ending.
After a few months of writing the game, it was in a state that I could release a version to the public. Version 0.10 only had a couple of maps, and only one save slot. The response wasn't great, with much of the criticism being levied at Edgar's walking speed and having to catch ten chickens in such a massive map (the Village map was about twice the size that it is now). The blandness of the maps didn't help things, but that was something I was able to improve at a later date.
|The Forbidden Swamp Guardian. Missing from version 1.0|
I decided I wanted to not only have regular bosses in the game, but secret ones, too. The first secret boss I created was basically just the Red Grub with a lot more energy and a couple of different attacks. The advantages to defeating the secret bosses was that the player could increase their hit points and, in some cases, obtain an item towards the optional quest.
The secret bosses were a lot harder than the regular bosses and the game did not provide any hints as to how to defeat them. Something that I'm not a fan of is encountering a boss and all you need to do is shoot them until they die. Providing a small puzzle during the boss fight makes the encounter more interesting. Here are a few of my favourite bosses:
The Golem was one of the first bosses that I added to the game. The sword was completely useless against it since it was made of stone, so the player had to resort to using the short range pickaxe instead. Fortunately, there were a couple of cranes in the arena that allowed the player to pick up the rocks that the Golem threw and drop them on its head, shattering it temporarily. The player could then attack the head to do additional damage, until it reformed. Eventually, I added a medal (more on this later) which the player could earn for defeating the Golem by just dropping rocks on it.
Mataeus is one of the hardest bosses in the game, simply because of his array of attacks and the chance of instant death if the player isn't careful. Initially he was a story boss, but was simply too hard. I changed him into an optional boss that the player could activate by touching the Black Book in the Library. Defeating Mataeus was necessary if the player wanted to fight the Black Book later in the game.
The Awesome Foursome
The Awesome Foursome only had a couple of attacks, but their difficulty came from the fact that they attacked in pairs. So whereas one might be charging up to launch a fireball at the player, the other could be dropping from the ceiling. In addition to this, when the player defeated one of them, their partner would teleport in and begin to heal them, meaning that the player needed to wear them both down at the same time if they wanted to ever defeat them.
The Black Book
The Black Book had the unique ability of being able to change into seven of the other bosses - the King Grub, Queen Wasp, Forbidden Swamp Guardian, the Blob, Gargoyle, and the Awesome Foursome. The bosses had considerably less energy than their original versions, but nonetheless it was still quite frantic.
Chaos is the final boss of the optional quest, and certainly the toughest of the lot. When I first designed him, it took me about twenty attempts to defeat him, and even today he still poses a challenge. He's probably a bit unfair, but that's the point.
A few months into the development I decided to add an optional quest to the game. The main quest in the game involves Edgar setting out to rescue his father, but an additional quest would involve Edgar seeking out and defeating an ancient dragon known as Chaos, who had been bound and imprisoned beneath the sorcerer's fortress. Chaos had been defeated, but not killed, by a warrior known as Ivan, who had long since passed away. Upon reading that Chaos has been slowly recovering his power and will soon be free, Edgar decides to subdue the creature once more. Finding Chaos isn't too difficult, but actually being able to survive his breath requires the player to create a special shield, by collecting a number of items. The tricky part comes from the fact that after certain events in the game, the required items are no longer available.
|The Sewer Dweller. One of the hidden bosses in the optional quest|
Graphics, music and sound effects
My first attempt at drawing Edgar was quite poor. I'd never tried to draw anything properly before, so it turned out to be quite a challenge. After a while I looked at some old arcade games, to see if I could copy the style. My next attempt worked out better and the result is what you see in the game now. My ability to draw did improve as I continued to develop the game, although some of the graphics really do need some work (the Phoenix in particular could do with re-drawing).
|The Graveyard map featuring rain effects|
For the sound effects, I looked mostly on FindSounds, before moving onto FreeSounds. Again, finding a suitable sound effect is quite a task and I didn't simply want to stuff in any old effect just for the sake of it.
Much like the Xbox's Achievements and the PS3's Trophies, I decided to add in medals, which the player could earn by performing different tasks in the game. There are 54 medals in the game, a fair few of them being hidden from the player, as they are story related. Many people decry Achievements and Trophies, saying that people only play games to earn them, but I think they add great replayability to a game.
|Some of the medals the player can earn in the game|
In an effort to make the game available to as many people as possible, I added support for Gettext. This all worked out fine on Linux, but when I tried it out on Windows, I discovered that some languages displayed garbage. After trying a lot of different DLLs, I noticed that Frogatto had support for Russian, which was one of the languages that was corrupting in Edgar. I delved into Frogatto's source code and noticed that it was using its own implementation of Gettext. I contacted the developers and they helpfully explained that it was to avoid the very same issues that I was experiencing. Once I coded an implementation of my own, the problems went away.
|The game running in Russian|
Of all the bugs that reared their ugly heads in the game, the worst had to be the map resetting bug. What would happen is that, after the player escaped from the Catacombs (a map where the player had very limited vision), the Fortress had reset itself, causing the player to end up getting trapped in the Catacombs again. I never encountered the bug myself, but numerous players reported it. I added reams of code to try and detect the bug and ran the game for hours at a time, making it randomly change levels, save the game, reload the game, but nothing reproduced the problem.
Finally one day I happened to be walking around one of the maps and I opened up the map editor to check something. I then tried to exit to another map and the game reported a fault and exited. I finally found out that some of the players had compiled the game themselves and had then run the map editor while navigating the catacombs. When the map editor had started up it had cleared out all the game's temporary data. Since the game could not find it anymore, it assumed that the player had not visited that map yet. I fixed the bug and since then no one has reported the resetting issue.
|The Catacombs. Focus of the resetting bug|
I'm pleased that I achieved so much and saw this project right through to the end. It's been a great way to stretch my imagination and watch the game evolve over time. I hope it's something I can look back on in a few years and be proud of. The game is a standalone story and I have no plans to ever write a sequel (though even if I did it wouldn't feature Edgar).
The game didn't work out exactly the way I wanted it to and it isn't especially popular, but I'm not too bothered about that part. There are a few bugs in the game that are slightly annoying, but don't detract from the gameplay so I may leave them as they are. Some of the feedback I received wasn't exactly encouraging and some of it is even slightly disturbing. I guess I know what it's like to have a stalker now...
The Legend of Edgar has been a great experience and I hope you've enjoyed playing it as much as I've enjoyed making it. 2.5 years is a very long time to spend on anything and I probably won't make anything on this scale again. In an environment where you cannot move for endless First Person Shooters, I wish there were more 2D platformers like Edgar.
Development time: 2.5 years
Number of files: 8,343
Lines of code: 142,368 lines