4 Hugues Ross - Blog
Hugues Ross

7/29/18

Making the first Halberd game: Were you sleeping in Algebra 1?

Where we last left off, I had gotten a pretty good idea of what the game would contain. Now that I've got an outline, The next step is to assemble it all into something playable. But first, let's do some algebra.

Math? In MY Level Design?

That's right! In the intro post, I mentioned wanted 8-10 minutes of gameplay. It's not much, but even this little can be tricky to reach if the levels aren't planned out with those figures in mind. (Unless the player is forced to grind, of course. Let's not do that!) The last time I tried making a similarly small game, I actually ended up short on content. This time, I thought it might be worth trying a more careful, numbers-based approach to avoid this problem.

The time that a player spends on this game can be summarized like so:
Time (total) = Time (walking) + Time (fighting)
-or-
Ttotal = Tmove + Tfight

We can break this equation down further. Movement time can be summarized as the distance traveled divided by the speed. Since this game has tile-based movement, we can get an estimated movement time like so:
Ttotal = (Tiles / Speed) + Tfight

Both of these variables can be controlled, one through settings and the other through level design. We can do the same for combat:
Ttotal = (Distance / Speed) + (Encounters * Turns * 2)

We can go further, and break down the encounter count too:
Ttotal = (Distance / Speed) + ((Distance * Encounter Chance) * Turns * 2)

In case you're wondering, your average turn lasts about 2 seconds. If we multiply the average number of turns by the average number of encounters, we can use that value to figure out roughly how much time will be spent in combat.

Bear in mind that these calculations won't be 100% accurate. They ignore a ton of variables, such as the player's level, how often they 'cut corners' by moving diagonally, how long they stop to think about things, and so on. Even so, I think it's a good method for guessing about how much the game needs.

Applying the Equation

Let's try solving the equation now. We want the game to last between 8-10 minutes, which we can replace with 540 seconds (9 minutes):
540 = (D / S) + ((D * C) * 2T)

This gives us a few variables that we can play with:
  • Distance
  • Movement Speed
  • Encounter Chance
  • Encounter Turn Count
Speed is the easiest value to test, so let's start there. In Halberd, speed is currently measured in pixels per second. I've already picked a tile resolution of 24x24, so I've set up some tests using multiples of that.
1 tile/s
2 tiles/s
3 tiles/s
4 tiles/s
3 tiles per second seems like a pretty good pace. 2 could also work, but I'm a bit worried that without a 'run' option it might feel just slightly too slow.
540 = D / 3 + (D * C * 2T)
1620 = D + (D * C * 2T * 3)
(1620 / D) - 1 = C * 2T * 3

With this addition, the easiest next step is to figure out how long the player should spend fighting. Given how simple fights are, I'd feel a little uncomfortable making them last more than 4-5 turns. So, I'm going to aim for around 4:
(1620 / D) - 1 = C * 8 * 3
(1620 / D) - 1 = C * 24
( (1620 / D) - 1) / 24 = C

Now, this only leaves the encounter chance and distance. Honestly, I'm not sure what I want to do for these two. However, we have simplified the equation enough to some real number-crunching. So, let's examine some possibilities with a spreadsheet:

Looking at these numbers, the distances in the 200-300 range look most appealing to me. For now, I'm going to start with an average of about 250 tiles of movement per area and a 2.5% encounter rate. For reference, 250 tiles is about 10 640-wide "screens" in size. It's on the bigger end, but considering the target time I'm going for it should fit rather well.

My next step would be building a test environment to try out these numbers for real, but my mouse is pretty much out of commission so that'll have to wait. I have a replacement coming in a few days, so I'll probably spend the downtime working on Halberd's code instead.

7/25/18

Making the first Halberd game: Story Time!

If you haven't read this post, do that now. I'll wait.

The first step to making a successful game is coming up with a good title, clearly. I spent a solid 10 minutes or so trying to think of a good legally-distinct title involving words like "dragon", "knight", and so on before remembering that I can just rename it later. So, let's just be lazy and call the game Henry for the time being.

Believe it or not, the second step to making a successful game is to make a new folder somewhere on your PC to put all the files in. Halberd can do that for me, or it could had I remembered to make it installable. Let's fix that now...

With that nonsense out of the way, we can start designing the game for real. Normally it helps to start a game with some prototyping, but that's not yet on the menu with Halberd. Instead, let's talk narrative.

Warning: Actual writers may want to skip this bit, to avoid the aneurysms my... process... will cause them.

Story

Even with a game as small and simplistic as the one I described before, it still helps to put together a little timeline of what's going on and what the characters will do before we build any content. We start out with the obvious:
Incredible. 10/10 story.

Sarcasm aside, this foundation gives us a lot of room to expand, even without dialogue and cutscenes to work with. This pair of events alone raises some interesting questions:
  • Why is the knight slaying the dragon?
  • What must the knight do to slay the dragon (besides the obvious)?
  • What happens afterwards?
You'll notice that these questions fill gaps before, between, and after the 'story'. Let's tackle the 1st and 3rd.

Motivation - Why slay the dragon?

Fictitious knights usually go on quests for kings. Kings, not typically portrayed as stupid, usually have a reason to send their knights off on a quest. Perhaps...
  • The king had a vision of his kingdom's destruction at the dragon's hands
  • The king is a greedy man, who wants the dragon's treasure hoard
  • The dragon threatened the king directly, demanding tribute
We could go on, with more ideas and deeper motives and circumstances. Of course, we couldn't depict most of that well with Halberd as it is. Let me instead reach once more into Ye Olde Bag of Cliches, and The dragon kidnapped the king's princess.

I don't want a totally boring story, though. 'Princess' is also used as a dog's name on occasion, so that might be a pretty achievable twist.

Conclusion - How does it all end?

We now have a knight, a dog, and a dragon. The little twist we just set up will provide a decent ending as well, so that can go at there. We can push it even harder, too. Since the player will likely expect a human princess, we can imply certain (wrong) things by stacking up some bones and a crown just before the dragon, and make the surprise even bigger.

The Rest - To Find a Dragon

I'm not cocky enough to try recreating the entire Monomyth in 10 minutes of lukewarm gameplay. Still, it's a good reference for brainstorming an RPG plot. Look back at the existing story points, and you'll see a couple similarities already.

Next, let's consider the (in-game) journey through our constraints. Given how short the game will be, I think 4 distinct 'areas' is a sensible goal to aim for. Clearly the 4th must be the den/lair/2-story condo that the dragon lives in, so that leaves 3 unknowns. Looking back at the Monomyth, there are a few things that interest me:
  • Most examples involve some transition from the known/safe to the unknown, then back at the end. This seems doable through environments alone, by starting the player off somewhere 'happy', like some lively woods or plains, then moving on to more foreboding locales.
  • There's a lot of events involving 'trials' and hardship around the middle. I happen to know of a couple simple events that could be made possible in Halberd, so I'll probably use those in the middle two areas.
So, we now have the following:
With this, we now have enough story to begin the game for real.
 Next time, we'll begin making some content.

7/22/18

Making the first Halberd game

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:
  1. 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.
  2. 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.
  3. 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.

6/17/18

Halberd: Finally, a Proper Demo!

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!

5/29/18

Halberd: Let's Talk Architecture

I knew this day would come...

...a dark, fateful day...

...when I actually have to care about code architecture


Halberd's development is chugging along, and now that I've gotten a few systems together my codebase is starting to get a little bit cluttered. That means it's time to tidy it up.

Why the Wait?

Personally, I believe that a lot of independent devs overthink game architecture. There's a certain school of thought that dictates that your code should be a perfect, well-oiled machine that's designed to handle anything you throw at it. That's all well and good in theory, but I've always had my doubts that most indies starting a "from scratch" project actually need more than a quickly-assembled Rube Goldberg machine, held together with twine and masking tape.

There are two primary reasons behind this notion of mine:
  1. Your customer does not care about code quality - They really don't. You could have the most beautiful, well-structured code, and a terrible game that no-one wants. On the other hand, your code could be a tire fire and no-one would notice if you managed to keep the game bug-free. As such, polish and quality should be put where it matters the most.
  2. Good architecture is an investment - And of course, investments have an upfront cost. Designing and building solid game architecture takes time, and implementing new code to work with it can also take longer in some circumstances. In return, you make your code more readable and maintainable in the long-term. However, games are often short-term projects and smaller titles are unlikely to fully reap the benefits, while still paying the cost.
Ultimately, I think a lot of novice devs see various patterns being touted as "best practices", and don't consider whether they'll actually benefit from them in the end. Nowadays, my usual approach to architecture is "as little as possible, until it is necessary".

Why now?

Now that I've written 4 paragraphs about why I usually avoid over-engineering like the plague, let's talk about why I've chosen to begin restructuring my code.

Unlike an internal engine built to develop one or two games, Halberd is intended to be an all-in-one tool used by others. That alone isn't necessarily an argument for needing architecture, but it does highlight one important point: This project will require long-term development and support. Along with large teams, long-term projects are among the truly valid use-cases for sound architectural design in my opinion.

If this were the only factor, I wouldn't be too worried yet.The other issue is that my code is starting to get rather complex, another good sign that some straightening out is necessary. More specifically, I'm dealing with:
  • Language interop
  • Data that must be edited and tested non-destructively at runtime
  • Modal input/display (due to switching between PIE and editing)
  • An engine that links into two different front-ends, and must be able to immediately start in any state (menus, combat, map, etc)
Technically, I have all of that already. Problem is, the level of complexity is turning it into a mess. So, it's time to refactor.

What's the Plan?

When you have a clear need for architecture, the next step is to plan it all out. I've done that already, and I'm going to step you through my process in hopes that it'll be helpful.

First of all, we have to consider our requirements. To begin with, we know that the editor and game are going to be Vala and C, respectively. We also know that our exported game shouldn't include any Vala code, giving us the following high-level relationships:
That has already existed since the beginning of the project, so the next step is to look a bit deeper. Specifically, let's look at how the asset editors are laid out, since my impression is that this is the messiest part. Right now, your average editor looks a little like this:
First off, let's get rid of the doubled-up viewport. As a GTK widget, the viewport shouldn't be owned by anything on the C side, but is so that they can check for things like size changes. If we add an event to DFGame for handling window size changes (which is a good idea to begin with), we can at least remove one of the references.

The other obvious problem here is that the C side is clearly doing two things, editing and testing. As a result, there are multiple copies of each child. The simple solution is to split off any test-related data into its own struct, ensuring a proper separation of responsibilities:
So, what about this new "Game Context" that just popped up? Right now, I'm in a position where I haven't had to think too much about how to put the different game elements together. Since I'm rapidly approaching the point where I will need to do that, let's talk about structuring the game state. Right now things are split:
So, what can we do about this? Clearly, the data here needs to be known to the two "states", but we need a way to manage them and make some data (such as the player) available across all of them. We also need to be able to handle things one at a time (We shouldn't be able to run around the map during a fight, after all) without losing information about other parts of the game. To me, this demands a certain structure:
I think a stack makes a lot of sense for this sort of interaction, because there's a lot of "layering" that can happen in an RPG.

Imagine you're walking through the woods, when a bunch of bandits appear to tell the party that they have a bounty on their heads. The bandits attack, then halfway through the fight some allies join in to help even the odds.

This feels pretty typical by the standards of scripted battles, and it fits this structure perfectly: Map, with a Cutscene within it, which initiates an Encounter, during which another Cutscene plays. And of course, most of these states clearly return to the previous state when they conclude. That's perfect territory for a stack-based solution. Since a stack needs something to manage it anyway, we can also make the manager handle our 'global' information, such as the player's stats and inventory.

Back to the editor, this means that we can use our test context to take the edited data in memory, convert it into a game state, and pass it to the game context to push it onto the stack. If we make an event for when the stack empties, we can also return to the edit mode automatically when something like an encounter in test mode finishes. I can also reuse this feature later to know when the final game needs to exit.

Ultimately, we get something that looks like this at a higher level:

Pretty close! There's a little bit more to figure out, but I think I've covered the important parts here.

So that's all?

Nope, not by a long shot. Iteration is key in software development, so I'm sure to return to the drawing board sooner or later. In the meantime though, this design will help make my code easier to maintain. This little diversion has slowed me down for a bit, but I think it'll be worth it regardless. Since I'm still making pretty good time right now, I can also afford to spend time on these sorts of things. As the Roadmap page shows, I'm getting pretty close to my first milestone!