We're finally here at the end of the experiment. Nearly 3 months after the original announcement, I've tried 9 different open-source engines and frameworks and written my thoughts on each. Now it's time to step back, do some comparisons on the group, and work out what I want to do going forward.
First, just to jog your memory I've assembled the complete list of posts:
In my first post, I talked a little about each lap and what I was expecting out of them (except Heaps.io, which was added to the list later on). Let's look back and see how they bore out.
DFGame fared about how I expected it to. This is no surprise, it's the one item on this list that I made myself so naturally it wouldn't really deviate from my expectations. Still, of note is the 'wordiness' that I mentioned in my write-up. DFGame's lap is the largest codebase by far, with the other (completed) games ranging from ~400-600LoC, 25-50% smaller. It's not entirely C's fault either--raylib's demo is only 547LoC. If I was planning to keep it, I think a high-level API would be a must to remain agile.
Godot was probably the biggest upset of the bunch. I had only really heard praise for the engine, and several people I know and trust recommended it... but in the end I found it kinda awful.
On thing I feel obliged to note is that I've spoken to some Godot users after writing this article--for the most part, they don't really seem bothered by the issues I brought up. As a professional Tools Programmer with a (mild) UX background, it could be that I'm extra-sensitive to these sorts of issues. If you're unsure about Godot after reading my post, consider giving it a whirl to decide for yourself. It's free, so you have only time to lose.
HaxeFlixel is an odd one, because despite a very positive review I've since soured on it a little. I think as the first "good" lap, I overreacted to it a bit. The iteration times are really annoying, particularly paired with the logo that pops up at every launch, and there's something to be said for being the only engine on the list with physics issues that aren't clearly traceable to my code. Still, it's not a bad engine and it had easily the best documentation of the lot!
I think the other projects could improve a lot by copying HaxeFlixel's example site.
LÖVE is pretty clearly the "winner" of the bunch, hands-down. I was hoping that it would be good, since I remembered liking it, and it was. I have very few negative things that I could say, so here's a link to a post from 2012 where you can envision current me shouting "NO! YOU FOOL!" over an over.
Monogame was another big surprise for me. I was expecting to like it a lot more, but I bounced off of it pretty hard. For the record, it does seem to be a decent framework. Rather, I think it doesn't work well in the conditions I tested and doesn't really offer what I'm looking for. More on that in a later section.
Raylib was not what I expected at all. I was expecting something a little like DFGame (but, y'know, better), instead it was much closer to LÖVE. In the end, I think it mainly suffered from the language it was based on and the lack of a proper API. It could be interesting to check out the language bindings it has sometime in the future...
SFML was kind of a filler option when I put it on the list. I didn't remember it being all that great (something that you can see from the fact that I didn't bother using it when I was raving about C++, despite having tried it), and it turned out to not be all that great. I think there are better low-level options and better high-level options out there, so I don't plan to ever revisit this one.
Overall, there were a lot of surprises. I think this speaks to the value of trying out software, rather than relying on just word-of-mouth.
A Note on Language
One thing that I noticed during this whole process was that the language being used does matter quite a bit. On average, it seems like the full-blown OO languages under-performed a lot in this 6-day test. This doesn't surprise me much, since building up those kinds of structures adds overhead to the development process. I'm curious to find out how true the reverse is... will a larger script-based project break over the weight of its complexity? Time will tell, but I think this is avoidable with good design.
Another big deciding factor was compile times. Stopping to rebuild files really becomes annoying when trying to tweak gameplay, and I think the noticeably-slow compile times of Haxe make it a lot less suitable for games than it first seemed.
Eliminations
One last thing to look at before we wrap up is what options will do what I really want. Some time after starting this project, I hit upon a couple of requirements that I really wanted out of an engine/framework:
Easy multiplatform support -- One thing that's held me back a bit with DFGame is the pain of porting to other platforms (like Windows. This is a real issue). It means that my audience is very restricted, and it's hard to stay motivated about a project no-one will play.
Ease of Design/Iteration -- I don't think game-building tech needs a graphical editor, but it does need a way to quickly tweak assets and values with an 'in-game' view. That can be through hot-reloading or tools integration, but I think it's legitimately important for getting work done quickly.
Starting with the first requirement, we can eliminate everything based in C/C++. That leaves Godot, HaxeFlixel, LÖVE, Monogame, and Heaps.io
The second requirement is a lot more wishy-washy, since it's about how easily some things can be done. As a graphical engine, Godot definitely makes it in. Due to how it handles assets, Monogame definitely doesn't. The others are a little more up in the air... so for now, I'll leave them in. That leaves me with a final list of 4:
Godot
HaxeFlixel
LÖVE
Heaps.io
Setting aside preferences for a moment, I think these 4 engines are the most suitable for my requirements. Unless someone can find a way to bring Monogame back in or I find new engines to try, these are the engines most likely to show up on this blog again.
Coming Up...
At this point, I think it's clear that LÖVE is the engine that jives with me the most. Before I launch into anything big though, I have another project that needs some attention: this blog!
I have the next couple of weeks off, and my hope is to finally sit down and set up a unified site and blog on a new host. It's going to start out very simple, but hopefully having everything working off the same base will make updates easier later on. Once that's done, I think I'll try to spend at least a few months experimenting, doing game jams, etc. before I start on any larger projects. I think it's important to take time getting to know a new engine, and jumping directly into the deep end won't get good results.
I didn't finish this week's lap, and frankly I don't have the motivation to do it. I'm in a bit of a weird position--I feel like I haven't delved deep enough to really give this engine a fair shake, and yet what I have seen so far doesn't inspire the confidence I need to keep going... all of this is to say that I don't like Heaps.io, but I'm not confident enough to say that it's entirely the engine's fault.
Regardless, let's talk about that experience a little.
My initial impression of Heaps.io was actually pretty good. The basic introductory text seemed to imply a pretty sane modern structure based on a scene graph, and the setup seemed simple enough. I didn't really like the focus on specific applications, but I figured that was mostly just to help out beginners.
My problems began immediately after that. The next major section of the documentation goes over 2D rendering, and shows a simple example of resource loading (here, scroll down to the Image section for that). What it doesn't mention is that you need to initialize a resource loader. Indeed, it doesn't mention those loaders at all! The first reference I found was a 1-line comment in a code sample several pages later.
If you don't realize this because you're not psychic, you'll get this helpful exception when you try that code:
"Resource loader not initialized: call to hxd.Res.initXXX() required"
...ok, so clearly a loader needs to be initialized, and the functions are in the hxd.Res namespace. See? I'm not being sarcastic, it is helpful!
Well, except that if you check the API docs you'll notice that there are no init functions listed. I'm not really sure why that is, but it's a problem. I also checked a good half-dozen of the official samples and conveniently, none of them had any sort of resource loader initialization either. Nice. The time I spent setting up loading code and searching the API and samples is a waste, because what I really had to do was:
Skip from the second section of the documentation (H2D) to the fourth section (HXD). And as an aside, what does HXD even stand for?????
Go into "Resource Management"
...and read that instead of the example that was given in the first place.
This is enough to progress, but there's no simple way to work out what resource loaders even exist. 'Embed' is used as an example, but if you look at the API page for it... Weird, there's nothing at all. And by the way, don't bother checking hxd.res.Loader. I know it seems like the obvious next place to look, but it contains nothing relevant to this search. To this day, I still don't know if there's a list of resource loaders out there.
After all that hassle, we finally have textures onscreen. At this point, I was pretty miffed but not nearly ready to throw in the towel. The apparent lack of vector math (more on that later) also didn't deter me, since I saw that collision detection code was available. Most of the math I've been doing in these demos has been bouncing a ball off of rectangles, so a basic collision API would cover that pretty well.
I'm going to spoil the punchline now and tell you that it doesn't cover that at all. You might think it would after looking at this sample, where they use built-in API calls to get the normals of a rotating collision object from a point in space. Amazingly, this function is entirely exclusive to the capsule collider class, for...some reason? Beats me. All I really need is the closest point from a circle-to-rectangle collision check though, so let's see what we get from that...oh. We get a bool, and nothing else.
At this point, I was starting to question how Heaps.io games handle physics, seeing as the built-in collision detection code doesn't seem to give anything that's needed for collision resolution. On a whim, I decided to check the hxd.col.Point class. It has all the vector math you could want! I should've been happy, but the only thought racing through my head was: "Wait, if this exists then why do all the scene graph nodes exclusively take raw floats???????"
And then, I stopped. Throughout these past 2 1/2 months, I've seen and dealt with a lot of weird and arbitrary API design, broken or incomplete docs, and a handful of runtime bugs. I've pushed through it all to bring you my opinions, but now? Now, I'm tired of this. Heaps.io put the last dagger in the back of my desire to try new game engines. I just don't have it in me to keep wondering about these things, and I think it's time to settle down and change gears.
Thankfully, that's already what's next on the agenda! We have one more post to round up all of the past engines and frameworks, and to declare a "winner" that I'll be playing with further.
This was kind of a weird entry, and the next one will be as well... I timed the demo out to 6 days as usual, but had to break it up over two weeks--let's just say I've been working on 2 AAA games simultaneously and one of them is shipping SOON™.
This may have hurt the demo a bit, but I don't think extra time would change my conclusions here.
SFML is a framework in a very awkward position, in that it seems to advertise itself both as one of those lower-level 'OpenGL/Vulkan access' libraries and also a higher-level 2D multimedia library. Since the goal of this little experiment is not to reinvent the wheel, I can't speak to the former use-case... but I'm not really impressed with the latter.
One common issue, perhaps the main issue I have with SFML, is the problem of trying too hard with its features and making the API worse in the process. Consider these examples:
For each 'instance' of a texture you want to draw to a window, you need to make a corresponding sf::Sprite object. You have to set transforms on the sprite, draw it yourself, manage the lifetimes of both objects, etc. It offers no gameplay functionality like the Sprite class in HaxeFlixel, so you can't use it to replace your objects.
The result is that any game object needs to copy its transforms over to this extra object on a regular basis, and you now have two objects to manage instead of one. Moreover, there's no simple 'just draw the damn texture' function. You can imagine a world where the sprite class never existed, and in that world it would be easier to draw textures onscreen...
SFML offers vector classes that you must use to represent positions. That's pretty standard... but what it doesn't offer is any of the corresponding vector math. There's no dot product, no cross product, and not even the humble length function. These vector math operations are the bread and butter of gameplay programming, but SFML expects you to provide them yourself. You now have a choice: write your own helper functions (which can't extend the API nicely, this ain't C#), or adopt a math library and convert types every time you make an SFML call.
Curiously, this situation is described in a very deliberate and matter-of-fact fashion in the docs. This proves that it wasn't an oversight, and it's almost as if the devs consider this missing critically-important functionality to be a positive.
In both instances the SFML devs thought of a useful feature, created the feature, but stopped short of the part that makes it useful. The result is baggage that the programmer must carry, but benefits little from.
Funny enough, this segues nicely into the next pain-point: C++ itself. I mostly swore off of C++ back in college, and have only used it in brief spurts since. I've grown a lot as a person since then, and I was interested to see how the language felt now... but no, it still sucks. Somehow, young and foolish me was completely right.
It has nothing to do with being lower-level, I've used C in two separate entries so far and been happy as a clam. It's not really about being higher-level either, I've used C#, Lua, and Haxe in this experiment as well. But something about C++ makes every new feature feel like an overdesigned mess that, get this, looks like the start of a useful feature but stops short of being useful. It makes me wonder how much of C++'s dominance in large-scale gamedev comes from inertia.
Well, I think that's enough ranting for one day. I'm tired, and the less time I spend thinking about this C++ and SFML tag-team the better.
Oh, and uh... the API docs are ok but they could really use a search bar.
With this post, we are officially past the halfway point of this series! There's a good chance we'll wrap this up at the end of the month, and if not we'll definitely finish before the end of the year.
But enough about that, let's take a look at this week's demo:
Overall, this demo is in-line with DFGame and HaxeFlixel. In the interest of transparency though, I should mention that I had a few days off last week and had much more time to work on this than usual... without that, the demo would probably have a lot less. In general, I'd say that Monogame is one of those frameworks that requires a bit of scaffolding to work in quickly. Since Monogame is C#, extending this sort of API is still pretty reasonable though. (As an aside, I really wish extension methods were a thing in more programming languages)
Setting that aside for a moment, let's talk about what I liked first. Obviously, as someone who works in C# professionally it's a pretty comfortable environment to work in. The compile times are also pretty good, although they still pale in comparison to raw C. To balance that out, I don't need to worry about defining code files in my build config or managing #include directives.
Like most of the tech we've reviewed so far, Monogame doesn't try to enforce a particular engine structure on the user. I always appreciate that, and in terms of complexity the framework seems to sit at a nice medium spot between DFGame and LÖVE.
...aaaand, that's the stuff I liked. I'm going to be honest, I was somewhat disappointed by Monogame. I have a number of friends and coworkers who use it, so I went in with pretty high expectations. However, I was less than thrilled by some of the design decisions.
Let's start with the big complaint: I really hate the Monogame Content Pipeline. To cater to larger games, Monogame compiles asset files into an intermediary binary format. This is great when you're publishing a game commercially, and terrible for everyone else! Every time you make a new asset, you have to pop open a special tool and 'import' your asset into the project. I haven't tested, but I suspect this also makes any sort of 'hot reload' feature infeasible. Regardless, at the end of the day it only serves to slow down the development process without bringing any real benefits until the game is ready to ship.
Now that you've marked down "Feature that slows down iteration" on your bingo card, let's move on the the free space: Griping about API documentation.
At a glance, Monogame's docs look fine. There's a search bar to filter through classes, and plenty of details. Unfortunately, there's one really serious issue: The sidebar listing class members doesn't scroll. Like, at all. If there are more results than your screen can display, you cannot see them. This is actually worse than not having such a bar, because it gives no indication that the results are trimmed. It's useless in the best case, misleading in the worst case, and you still have to Ctrl+F for class members.
I also have some complaints about the design of the API itself. I'm a firm believer that UX applies not only to User Interfaces, but to Programmer Interfaces (literally, APIs) as well. Monogame makes a good case for this, because I think it has pretty bad UX.
The SpriteBatch class, which handles most of the drawing functions, makes for a good example:
When drawing anything with the SpriteBatch, you have options to position, rotate, and scale the element you draw by passing vectors / angles. But if you want to do that to everything you draw, you need to provide SpriteBatch with a 4x4 transformation matrix instead.
Conversely, you can't use a transformation matrix with individual elements. You must pass in the individual transforms.
You can draw text, and you can 'measure' text for placement/alignment purposes... but you can't draw aligned text without writing the alignment code yourself.
You can recolor any element you draw. In fact, you are required to pass a color in every draw call. Yes, it will almost always be white. No, you still can't skip it.
While working with Monogame, I felt like I was spending most of my time doing busywork and adding things that should've been redundant instead of getting work done. I'm sure it can be a good framework with enough helper libraries, but it really feels like the API designers don't respect the user's time at all. I'm trying make games here, if I wanted to write my own framework I would rebuild DFGame in OpenTK. It's still leagues better than Godot tho.
I really love LÖVE. This past week has been a blast, and despite skipping a day (I spent Saturday trying to make some music, but alas I still absolutely suck at music compostion) I've managed to put together the most polished and stable demo so far:
Pretty much all of the features the other demos have were completed in the first two days, so I took it easy for the remainder and tried to add some extra polish and refinement to what was already there.
I think a big part of what makes LÖVE so efficient for me to work in is that it's a framework like DFGame. This lets the programmer go as simple or complex with the architecture as needed, which can really speed up the production of simple games. Unlike DFGame however, this framework is based on a high-level language with a greatly simplified API. To top it off, the fact that it's based on Lua means the user can launch builds instantly. In short, it has most of the upsides of HaxeFlixel, with none of the downsides. Honestly, this test makes me want to kick old me in the shins for casually dropping it ~9 years ago. It's great!
But of course, we can't just be positive. LÖVE has one curious flaw: There's no vector math in the API. Seriously! Since Lua supports multiple return values, the devs have taken to just passing around pairs of floats. That's not such a big deal, but having to write your own math boilerplate to do basic vector manipulation is kind of a chore. I have absolutely no idea why LÖVE doesn't provide these functions, especially since the core engine almost certainly has them somewhere...
Thankfully, this is the sort of problem that can be solved with a helper library. Overall, I think LÖVE is handily "winning" this comparison so far.
After last week's fiasco of an engine, I was a little worried going into something I hadn't tried before. Haxeflixel, however, was a breath of fresh air!
As you can see, the resulting demo is pretty close to what I made for DFGame. There are a few notable differences:
I had never used HaxeFlixel or Haxe before
I spent less time on this entry than the DFGame one
At 395 lines, the resulting game has less than half the DFGame entry's linecount
This is the sort of result I was expecting to see from some of our contenders, and in general I quite enjoyed my time with HaxeFlixel. The engine offers most of the stuff I wanted out of the box, and the documentation is really well-designed. Just look at the HaxFlixel Snippets site for an example of what I'm talking about:
Each page has a minimal example (often just a single line of code!) showing the relevant call, API links, a real demo running in your web browser, and the full demo code acting as a more 'complete' example. It manages to frontload only the most relevant info while still offering enough depth to understand what you're doing.
Overall, I was impressed and I think HaxeFlixel is actually a quite good starting point for new gamedevs. There are a few negatives that make me unlikely to use it for big projects going forward though.
The first negative is the engine/language's compile times. A 'dirty' build (ie. no code modifications) of my 400-line game for linux takes ~13 seconds. A clean build takes 2 1/2 minutes building to an SSD on a 12-thread Ryzen CPU!!! For comparison, here are the build times for DFGame:
Dirty: too fast to perceive
Clean: 4 seconds
The Haxe codebase is nearly 40x slower to compile, and I can only imagine what a 5 or 6-digit linecount would do...
The other issue is a little less obvious, but worries me just as much. Part of what makes HaxeFlixel so quick to develop in is that many of the things you want are already handled in the engine. Want an object with a sprite? Make an FlxSprite and add it in! Want to give it physics? Just turn the physics on! Want to make it disappear when it runs out of health? Just call hurt() on it!
This is awesome for quick development, but it also restricts your visibility of what's really happening with your game objects. For instance, when I tried to make bricks move the ball started randomly teleporting, getting shoved out-of-bounds, etc. The changes I'd made on my end were so small, and the API was so 'foolproof', that there was no clear bug in my code. Something was going wrong in the backend, and I didn't have any good debugging options. This always worries me when engines try to hide the details, simplicity can bite back hard when it fails.
With that said, HaxeFlixel seems like it would make for a good prototyping tool. I'll probably keep it around, and I would recommend it for small games and game jams.
Given how many people recommended Godot when I started gathering my list, I was actually pretty excited to try it out. I didn't think it would be as good as claimed, but I figured it would make it into my top 3 and get some use as a prototyping tool, at the very least.
...How wrong I was. As it turns out, Godot is ahotmess.
I'm not bothering with a video this time, there's nothing interesting to see. I got the very basics in place (bouncing a ball around, breaking bricks) and immediately dropped the project, because I didn't want to use this engine any more than I had to. Instead of talking about the game itself, let's talk about why I hate Godot so much now.
First off, let's set the tone with a little anecdote. Here's my first interaction with Godot, step-by-step:
Load an example project to see how everything works
Open a scene and look around a little
Open a script--wait, did that just replace my tab?
Try to open the scene again. Nothing happens.
Try to close the tab. The tab (and the script within) is still open, but the tab title changes to "[empty]"
If you use Godot, you already know what's happening. But if you don't, I'm sure you're about as mystified as I was when this happened. As it turns out, Godot's designers had a bright idea along the lines of:
"Hey, why don't we force users to open scripts on top of their scenes even though we have tabs?"
For some reason, in addition to 2D and 3D level-editing views they just added a script editing view instead of opening documents in a new tab like any normal piece of software. Just for good measure, double-clicking a script will change the view but double-clicking a scene won't change it back. Like many of Godot's failings, it's so obviously wrong that it almost feels like a deliberate joke.
I should also take a moment to point out that I'm a Linux user and casual FOSS advocate. I know that most open-source software isn't the pinnacle of UX, since I use it all the time. Even knowing this, Godot feels like it's on a totally different level somehow. Almost every interaction is slowed or complicated for no reason.
Here's another example: Since we've established that you can technically open multiple files in the same tab, how do you suppose you save them? As it turns out, Godot has 2 save shortcuts, Ctrl+S and Ctrl+Alt+S. Normally, Ctrl+S will save the content of your tab. However, it's bound to save scene so if you don't have a scene open under your script you have to press Ctrl+Alt+S for save script. That's right, they fucked up the most basic action of saving your files.
Of course, that's a bit of a moot point since there is autosave. Unfortunately, autosave always saves open files, even if they're not modified! This means that if you use an external editor, every time you launch the game your editor will detect a file change and prompt you to reload. Nice. The classic loop of "make change, run, go back and adjust" now has an extra step, courtesy of Godot! Oh, but don't worry. In addition to always re-autosaving your files, Godot will also ask for confirmation every time you try to close the editor. Yes, even when nothing is modified. And yes, it also autosaves when you do that, making the entire confirmation pointless.
But you know what? If that was the end of it, I might be able to grit my teeth and push on. So next let's talk about the API documentation. Surely, a team of programmers (because I refuse to believe that there are any "creatives" involved in this engine) would make good docs right?
So the first thing I noticed when I opened the Godot docs was that the API docs were nowhere to be seen. The sidebar is filled with tutorials, but to get to the real API you have to scroll to the very bottom of the list. Or hit Page Down twice. Yes, it's that far down. You could also use the search bar, of course. From my experience, unless you put in the exact name of a type you'll have to scroll deep into the results to reach the relevant API page. Depending on what you search, you might also get the internal engine API, because they put both APIs in the same space for some reason. They also put ads in their documentation, but since Godot itself is free I have trouble blaming them for that.
Ok, so the workflow is bad and the API is annoying to search. But maybe the level editor is good? I'm not going to beat around the bush this time, it's not. The biggest offender is the "Select Mode", which does a lot more than select. Select Mode is ostensibly for selecting objects in your scene, but clicking and dragging movesthem. Did your mouse move slightly when you clicked? Your object is now 1px out of alignment, sucker! I hope you noticed before you started doing any real work.
I think that's enough bashing to get my point across, I could keep writing for hours (these past 6 days have given me an endless supply of material), but I think I'll just block this past week out of my memory and move on to the next entry.
Lately, I've been in the mood to get back into gamedev. It has been a while since I sat down and made a game for real, so this feels like an ideal moment to look at the landscape with fresh eyes. Over the last 5-10 years, a lot of open-source game engines and frameworks have popped up and grown up alongside the indie scene. I have a little framework of my own, but I want to find the tech that I'm most comfortable with.
To that end, I've got a fun exercise to try. I call it:
The Big FOSS Game Tech Battle Royale
The concept is quite simple: Every week, I'll spend 6 days trying out a new set of tech and building a little breakout clone. I'll write about my experience, then at the end I'll pick whatever I enjoyed the most for my future projects. Also, though it goes without saying--I'll also post the code and assets for each attempt.
I think breakout is a nice 'test game' because it's very simple on a mechanical level but incorporates a decent number of core game development concepts. The simple format is also ripe for expansion--which will be good for testing tech with a fast iteration speed.
I've picked out 8 'contestants' for this exercise.
DFGame -- DFGame is a lightweight C framework that I've worked on from time to time... It's not terribly impressive, but works well and benefits a lot from being familiar territory.
MonoGame -- I've used XNA to build games in the past, and I work in C# professionally as well. For that reason, I think this framework is absolutely worth trying.
Godot -- Godot is an engine that I've heard a lot about, but never actually used. While I'm a little skeptical of the hype it's gathered, dismissing it offhand would be silly. This exercise will be a good opportunity to give it a fair shake.
HaxeFlixel -- From my understanding, Haxe is the phoenix that rose from the corpse of Adobe Flash... I never really enjoyed Flash development proper, but I've never tried Flixel before and Haxe has been used several high-profile indie titles.
LÖVE -- Good old LÖVE, I used this engine for a few months back when this blog first started. I discarded it for silly reasons back when I was first learning C++, but the engine is still going strong to this day and I want to give it a second look.
SFML -- Another briefly-used piece of tech, I used SFML for exactly one school project. I have a couple of friends who recommended it while I was building this list, so here it is!
Raylib -- I've never used this one, but at a glance it looks like "DFGame, if it was fleshed-out and actively supported". I don't know if it's any good, but it's clearly worth trying out if it can save me from reinventing the wheel.
Pygame -- I'd forgotten about Pygame until I asked around and someone mentioned it. It seems a bit dated, but how it fares remains to be seen.
What a list! If I knock out one test a week, it should be enough to last me a couple of months. It should also give me plenty to write in the meantime as well. I'm also open to suggestions, if you know a little open-source gem feel free to suggest it in the comments.
It's done! Earlier this week, I finished the last of the features I needed for Halberd's MVP. I'm going to sit down and make a game with it now, so I thought I'd bring you along for the ride. Please bear in mind that Halberd is still in a very rough state, I've done basically no polish or UX work with this version yet.
Why Make a Game Before Release?
Longtime readers have likely noticed that I do this all the time, but don't really explain why I take the time to make games before engine releases. In fact, I even denounced this practice during a retrospective last year (For the curious but lazy, check the section titled "Total Overkill"). So why am I doing it now?
There are a few good reasons why I feel a need to make a game before pushing my work to the internet and calling it a day:
Making a game is a way to validate that the tool works, by forcing me to engage with all of its features. If there are any bugs or missing parts, I can fix them before release. It also lets me see which features need the most love and which are 'good enough' as-is.
Having games made in an engine is also good for proving its capabilities. Anyone can make game development tools, but if no good games have ever been made with them then they'll be a tough sell for other devs.
Finally, games can also serve as a useful reference for anyone who wants to try Halberd out. I don't think anyone will at this point in development, but when people do start using it they'll have something to help them.
Clearly, there are some real benefits to using your own tools before offering them to the world. But why not small demos like I did with DFGame?
In response to my previous post, I would argue that the circumstances around Halberd make points 2 and 3 legitimate in a way that they weren't for DFEngine. My stated goal with Halberd is to produce a game engine as a product for others to use, whereas my old mistakes were mainly for personal use. I've seen certain engines receive criticism in the past because the devs didn't use them to make their own games, so clearly this is a factor that some people care about.
Additionally, the large scope of Halberd makes it a real marathon of a project. I need to break it up with smaller game projects if I want to keep my sanity! Not all of my 'filler' will be made with Halberd, but it's still a convenient excuse to give the engine a workout.
About the Game
Right now, Halberd's limited featureset heavily restricts what I can and can't do. To get around that, I'm going to start things off with a very simple game about a knight slaying a dragon. It's a typical story that has been done to death, but that makes it easy to work with, perfect for a limited toolbox. We can try some more exciting things for future versions of the engine.
Due to the limitations, I'm also aiming for around 8-10 minutes of gameplay. That should be enough for the game to show off everything Halberd currently has to offer without overstaying its welcome.
Too Much Information?
With this mini-project, I'm going to do something different from my usual fare. Nowadays I mostly write posts when I have some specific 'theme' or aspect of a project that I want to cover, but that leaves out a lot of potentially interesting things. I never really write about anything outside of fairly dry programming topics, but I enjoy other aspects of development too.
I think it could be interesting to share my process in detail, so I'm going to try documenting everything I do and see how things turn out. Assuming it all goes how I want it to, you'll be able to see the game's assets take shape from start to finish, including any drafts and thrown-out ideas. It'll slow the pace of the project down, but I think the idea has enough merit to try just once.
You can expect a few weeks (hopefully no more than that) of posts talking about various parts of the game as I work on it. Following that, I'll probably return to my usual non-schedule.
Well, it has been 2 1/2 months in the making. But today, Halberd has reached its first milestone!
Video captions can't really convey how happy I am to see this happen. I've been thinking about Halberd for years now, and it's great seeing it take its first step.
Granted, I still have massive amounts of work to do, but this still feels special regardless.
MVP, or Not?
One thing that I've been struggling with is figuring out what an MVP actually looks like, in the context of an RPG engine. What features are required for such a tool to become 'viable'? Where do I draw the line between wants and needs? I've generally tried to stick to as minimal a definition as possible, but such a definition is probably not what a user would actually expect. It's a tough balance.
In the end, I've decided to go with a little cop-out: The next milestone is what I'm referring to as my 'AMVP' (Absolute Minimum Viable Product), and the next one is the 'True MVP', with additional features and polish that your average user would likely expect as their minimum. I'm still figuring out the details of the latter, but my current benchmark is Dragon Quest 1 (a.k.a. Dragon Warrior). If Halberd can do everything that game can (minus some polish and a few of the more specific features like torches), then I feel like I can more confidently proclaim Halberd to be a viable (if bare-bones) engine.
After that? Who knows! Once Halberd has reached a usable state, a lot of potential avenues will be open to me. I'm probably going to keep finding progressively more varied and complex games to compare against, and mix those features with quality of life updates.
Whatever happens, I'm excited to see where the project goes next!
Hello again! After a few weeks of toil, I've finished my second 3-week project for Console Programming. I opted to make this project about building up DFGame to a more usable level, and I'm happy to say that the project was quite successful!
Project Overview
My ultimate goal for DFGame is to be able to build the base of a game from scratch, editor and all, in a single week. I decided that a nice way to cap this project off (and test the viability of DFGame in the process) would be to try and make a super-basic game/tech demo without an editor in a single week. I'm pleased to say that the result way a success!
To make this game happen, as well as improving Halberd a bit, I decided to implement the following features during weeks 1 and 2:
A script for generating new DFGame-based projects
Some UI widgets for editor development
Input handling code
Sprite loading/drawing code
Some initial project management code
In the downtime between projects, I also started work on audio loading/playback.
Project Script
One of the main differences between DFEngine and DFGame is one of approach. DFEngine's goal was to make a fully-featured game engine, but with DFGame I add features that will benefit me directly in game projects. As a result, I can get things done faster because my focus is specifically on making games.
The project script is a great example of such a feature. It's designed to set up a new DFGame-based project as quickly as possible, while also being easy to modify and extend.
DFGame now creates a folder in /usr/share (on *nix-based systems, of course), and adds folders which act like templates to it. This means that users can add their own, as well. It also installs the script to /usr/bin, so you can create a project just by calling "dfgame new project-name folder-name". folder-name is optional too, if you omit it, it'll set up the default project. The script moves over the contents of the template folder, and then checks for a special script within the folder. If the script is found, it's executed as well, to allow for extra customization. The current template scripts set up a config.mk file, for instance. Finally, the script initializes Git and builds the project, ensuring that everything is in working order.
UI Widgets
I've been meaning to move several parts of Halberd's UI over to dfgame for some time now. Most of the more 'generic' UI elements, such as the asset pan and missing files window are mostly self-contained, so moving them over was quite simple.
I also took the opportunity to make something new: a log viewer. I've wanted this for a while, so that I could debug issues without having to look at several windows at once. Now, it's in!
It's not an enormous addition, but it feels like another good step towards making my editors more professional.
Input
My input code has always been fairly simple, but this time I decided to try and make a more powerful system.
This new system lives up to my expectations quite nicely! It revolves around mapping inputs of any kind to either (or both) of two input types, actions and axes. An action is any kind of digital input. It generally used to represent singular in-game actions, such as opening a menu or attacking an enemy. Axes, on the other hand, are 2D analog inputs. An axis can be thought of as a 2D vector, like a joystick input. Axes should be used to describe inherently directional actions, such as movement or aiming. Any keyboard, controller, or mouse input should be translatable to any actions and/or axes.
So, we have a decent base here. But what makes this so powerful is the way it's implemented. DFGame's input code is broken up over 2 of its modules: the base game module, which is used everywhere, and the game frontend module which is only used in released copies of a game, not the editor. This means that the editor and game are responsible for handling their own inputs, and passing the result to the base input system.
Not only does this separation make inputs inherently rebindable, since the actual keys are disconnected from the in-game actions, but it also allows the editor to simulate inputs and the game to take inputs from custom sources and input devices. Ultimately, this makes input code way easier to deal with, and it also makes adding or changing controls during development a cinch.
Sprites
DFGame's new sprite system is mostly identical to Halberd's, with one main exception.In addition to the sprite/animation system that I described in this post, DFGame's implementation has an additional layer of abstraction.
In order to speed up rendering and save on memory, I've split sprites into two parts, the spriteset and the sprite [player]. This is a similar approach to the one I took with audio: One struct controls data access, while others act as interfaces to play back this data. The spriteset holds the texture atlas and animations, while the sprites hold information about the currently playing animation.
Project Management
One of the most important features that you can put into an engine is the ability to create new projects. Even if you plan to only use an editor once, being able to go back and create brand-new content with it can be quite useful. In addition, it gives the editor potential for a decent public release. For that reason, I've moved Halberd's project management code into DFGame. It could still use a bit of cleaning, but for now it'll do the trick.
The Game
All of this technical talk is good, but you might've noticed that I mentioned a game earlier. In addition to the DFGame improvements, I also created a small game as a test. I planned to spend a week on it, but instead I only ended up with 3 1/2 days. Despite that, I still managed to make a small, well-scoped twin-stick arena shooter.
The game isn't currently packaged and available for download, although I'm considering that right now. The game's code is quite messy, since the point was simply to use it as a quick test of my library's capabilities, rather than to start a 'serious' development project. It's more of a game jam-style game.
Regardless, I took the time to make a video of the gameplay. Since there aren't any sound effects anyway, and the music was borrowed from one of my old game jam entries, I decided not to record the audio. Feel free to add whatever background music you like while watching.
Conclusion
I'm really happy with the progress that I've made in the past 3 weeks. I took a simple collection of asset loaders and turned it into a wonderful budding library of game development tools. Now that I've proven that rapid development is possible with this engine, I'm going to try and participate in more game jams again. In addition, I think I might try to make some smaller games as well.
Most of that will have to wait until after I graduate though. This is a very tough semester for me.