Time for our post-mortem
I won’t re-introduce the team, you can go to our “we’re in” post for that. Basically there were 3 of us and we’re pretty awesome!
So what happened?
Well, we made a time-bending tower-defence game called “10 Second Onslaught”. It’s about an onslaught you see, and the onslaught in question lasts 10 seconds:
The game wasn’t really “finished” after 72 hours even though it’s completely playable. I’m actually glad we were over-ambitious though: it’s a good beginning and something I’m still working on (in a separate branch of course 😉 )
What went well?
The art pipline was probably the one thing that went particularly well. Thomas is really a 3D artist, so soon reverted back from pixel art to making models and rendering them to bitmaps. To speed things up I wrote a couple of little ImageMagick scripts to mirror and then stick these images together into sheets. Then it was just a matter of using the haxelib spritesheet to have animated characters in the game
What went badly?
For various reasons, mostly the technology (OpenFL) being something only I had ever used before, I ended up writing a majority of the code, which is just stupid. Next time we’re going to have to organise ourselves better.
Read on for a rather long discussion of OpenFL, including comparisons to Unity 3D and Löve 2D…
Our company NaturalPad uses Unity for most of our game projects – here we wanted to try something a bit different: “OpenFL”. There’s some degree of patriotism involved as Haxe and Motion Twin are both French. I’m not actually French myself, but that doesn’t stop me from being patriotic about croissants and stuff. Anyway you might remember OpenFL (called “NME” until very recently) from such games as Papers Please and Rymdkapsel.
OpenFL vs. Unity 3D
OpenFL resembles Unity 3D in some senses: its tree-like draw-list structure for instance very much resembles Unity’s transforms. As a result scenes are constructed in the same sort of way, by linking up nodes to parents to form a hierarchy. That being said Unity is a game engine while OpenFL is just a framework for cross-platform multimedia applications. There are some OpenFL-based game engines out there, HaxeFlixel for example.
While I was happy to be using something lighter and less proprietary there were certain things I missed. Notably:
These two combined in C# make it absurdly each to find scripts and objects on the fly, something that is often central to game logic. After all, I will often want to find:
- “all the trees within 500 pixels of the player character.”
- “the number of enemies with full health.”
- “the ally with a bazooka with the most ammunition.”
These queries, in Unity C#, would look something like this:
root.gameObject.GetComponentsInChildren<Tree>().Where(t => Vector3.distance(t.transform.position, transform.position) < 500);root.gameObject.GetComponentsInChildren<Enemy>().Where(e => e.health == 100);root.gameObject.GetComponentsInChildren<Ally>().Where(a => a.gunType == GunType.Bazooka).MaxBy(a => a.ammunition);
In Haxe functions are first-class citizens and so can be passed to queries unlike, say, in Java. However I just couldn’t manage to get Haxe’s templates working. Thankfully I’m wise enough now to know when something isn’t working and to move on to other things, especially during a jam. Even a good few hours were wasted trying to build a nice API for game object queries.
OpenFL vs. Löve 2D
I was able to teach my team to use “Löve 2D” only a few weeks after starting to use it, and Lua, myself. That said Löve 2D is famous for being absurdly simple to use. Want to draw something for example?
love.graphics.draw(thing, 0, 0);
Even though I’d already finished one simple game using OpenFL (or rather NME) I think the framework is just a lot more complicated than Löve. You’re not telling the machine when and where to draw, rather you’re build and maintaining the elaborate draw-list tree structure. I also had a real person teaching me Löve rather than figuring it out myself, and Löve has far better documentation.
All this combined to make it very difficult for me to delegate tasks to the novice programmer on our team. I didn’t really know what I was doing myself! As a result he wasn’t able to make a particularly meaningful contribution to the project, which I’m not terribly happy about.
OpenFL vs. user interfaces
Speaking of not knowing what you’re doing: it was brought home to me with this project that I haven’t done enough interface-heavy game to know how to properly structure interface code. Generally-speaking my games have been sprite-heavy with plenty of AI and collision code, but the controls have tended to be direct mappings from a keyboard or gamepad to an action in the game.
Here we wanted a game that could be ported to mobile devices, so it needed to work with an extreme economy of input:
That said the player needs to be able to do a lot of things:
- buy and place units
- choose unit type
- choose positions in space
- choose position in time
- modify previous unit placement
- move through space
- move through time
- “sell” unit
- start the onslaught
- stop the onslaught
One of the advantages of OpenFL is that it is extremely good for exactly this kind of user interface. As mentioned before however, I wasn’t necessarily experienced enough with it to make the most of it.
Some of these interactions ended up being coded using static buttons but a lot of it was contextual menus. Because I’m not very experienced doing this kind of code the result was a bunch of tangled events and callbacks roped randomly through the code-base.
I’m not altogether sure how one “should” structure interface code for it to be “clean”, but it’s certainly not the way we structured ours!