I’m glad I was able to participate again this Ludum Dare. This is my third jam, and first time submitting to the Jam rules. While that’s technically true, as I submitted on Monday, I didn’t really start until 24 hours had already passed. That, coupled with the solo work and the starting from scratch, makes it feel to me more of a compo entry, but alas, I have no say in the matter. Onto the postmortem.
Plunder Postmortem
I decided to give Lua and LOVE another shot this time around. I have been using the framework off and on over the past year, and really enjoy how rapidly you can develop on it, but the lack of true Object-Oriented Programming techniques have hampered me in the past (and as you’ll read later, nearly caused me to bail this time around, too). There are plenty of great libraries out there that create a pseudo-class system, but they aren’t as fully featured as you’d find in a natively OOP language because…well…of course they won’t be!
The Idea
When the theme came out, I immediately started think “Tower Defense”, because it works extremely well with it. Simply put a princess in your tower and done. But As usual, as soon as I started looking at what other people had been posting I once again realized that the first idea is often the same idea everyone has. I could have just rolled with it, because even though it’s a bit obvious it’s clearly a good idea, but my first Ludum Dare entry was also a Tower Defense game, so I wanted to try something different.
I eventually came up with the idea of a rampaging boss razing and pillaging a town, all the while having to fend off various heroes along the way. The boss would be clearly more powerful that an individual hero, but though sheer determination, they could eventually whittle the boss down to defeat it. Thinking back, I must have gotten the idea from a recent play through of Rampage: World Tour with a buddy of mine, because it hits all the same beats. I even was going to have “peasant” characters that the boss could eat to regain health, and a destructible environment.
Programming
I tore though the framework relatively quickly. Most of it was all fairly benign code. A Hero class with subclasses for the particular Heroes, a Boss class, a Block class for the environment. I started out exclusively using vrld’s HUMP libraries, but I ran into a few snags (the big one I later figured out was of my own doing), and switched to kikito’s middleclass for my pseudo object orientation. I used vrld’s HardonCollider (you read that right; it’s the LOVEly thing to do) for my collision detection, although if I had known about it earlier, since I only used AABB’s, I could have used kikito’s bump to lower a bit of overhead.
Art
If you look at my game, you’d think I was still in elementary school! I have come to realize that I am a terrible artist. I plan on putting in some effort of the school break looking into Inkscape and vector graphics, because GIMP is not cutting it for me. Too much freedom, not enough “tweakability”.
Challenges
I had three big challenges, all of which stem from the HardonCollider library and my interactions with it. Granted, I have not really used it all that much, so I maybe it’s just growing pains, but it ended up costing me a lot of time that I could have used polishing the art or adding some more mechanics.
Is your mama a llama?
You are supposedly able to use the HardonCollider objects inside your classes, simply adding to the resulting table your additional information. But it did not seem to interface too well with middleclass, because I could never add those objects into HardonCollider’s object pool if I tried to assign its created object to self. I assume it has to do with the metatable being overridden by middleclass, and therefore HC cannot guarantee that what I am passing in is a HC object, but I ended up having to create a separate bounding box field inside the class to hold onto the HC object’s information.
This might not sound much of an issue, but you have to understand how HC works. After you add your objects to its object pool, you write callback functions to describe how the objects should respond to one another. However, the objects you get in the callbacks aren’t attached to the class objects you created them in! Luckily, in Lua, this can be fixed easily without having to change any of the libraries code: just add a field to the HC object that points back up to the the object’s parent. You just then have to be aware that you have a circular path here, so you need to be careful about how you use those objects.
Calling for disposal in a garbage collected world.
Lua is garbage collected, which helps greatly when dealing with a quick project like the game jam entries. And most of the time, it works like a charm. But here’s the tricky thing: Lua has no proper way to define a destructor (or dispose method for a garbage collected equivalent) for non userdata (i.e. C API interfacing) objects. So, when you do something like say, registering an AABB with a collision detection library, and then say, change levels, unless you are keenly aware of this fact, even though you’ve lost access to the parent of the AABB, which should have destroyed the AABB, it persists in the ether, since the collision detection library has no way of knowing that the encapsulating object is out of reach of the program. (It really isn’t, considering that I had to attach a reference to the parent on that object to fix the earlier issue).
If destructors were a part of the Lua lexicon, then maybe this wouldn’t have been an issue because I would have had to thought about this beforehand; but when I run a few checks and see why my levels are changing even though my boss character is no where near the door, everything sudden falls into focus, and I curse to the heavens. And, as usual with things like this, the bug is often super simple to fix compared to the amount of effort required to find out what exactly is causing the bug.
Why did we decide to move our origin again?
Everyone knows (or should know, otherwise how have you made a game for Ludum Dare) that most 2D graphics libraries out there choose the top left corner of the screen to be the origin of their Cartesian coordinate system, and that the positive y-axis points downward from that point. I understand the decision to make positive y point down given that the origin is now in the upper-left, but why make it there in the first place? Why not follow the convention of mathematicians everywhere and make the lower-left the origin?
Besides random pontificating, the point of that was to show how the convention works. Most people extend that convention to everything that requires a coordinate system within their code. If you have a local coordinate system for an individual image, the origin is the upper-left. Mouse movement? Upper-left. Consistent across the board.
HardonCollider does this as well, but for whatever reason, when dealing with it’s movement functions, it decides to use the centroid of the object as it’s movement. I can only assume that since HardonCollider fully implements SAT collisions, since it can handle any convex polygon, having to calculate the “upper-left” might be too much of a hassle when using any other point would also serve the same purpose when moving based on velocity, but when you have a moveTo function, you’d think that you’d be moving the upper-left of an object to the specified point, not the centroid.
This one might be on me more than vrld. Once I actually took the time to read the reference materials I saw it was stated fairly clearly, but it was fairly annoying while I didn’t know, and caused me to implement walls because I couldn’t understand why the images would jump in the air whenever I tried wrapping them around the screen.
Things I would have done differently
Don’t try to be as ambitious as I was. I think next time I do a game jam (which likely would be the Global Game Jam coming this January), I’ll try and pitch just making a simple platformer. No enemies; no weird mechanics; just a finely tuned platformer that I could finish rather quickly and spend most of my time polishing rather than implementing critical code at the last minute.
Work with an artist, or hone my art skills. I was reasonably happy about my game until I started adding art to it. I didn’t have much time (nor honestly enough energy) to spend on making some decent art, so when I threw together some art to replace my sweet rectangles I had been using, everything looks so incredibly ugly. I almost thought this was too embarrassing to turn in. So, hopefully by next Ludum Dare, I’ll either have gotten a team together for the Jam, or have greatly improved my art.