4 Hugues Ross - Blog: 2018
Hugues Ross

12/31/18

2018 End of Year Wrap-up

Here we are, at the end of a new year. It's crazy how quick these years go by nowadays, but at least I'm still getting plenty done! Let's jump right over to some accomplishments:

Cloudy Climb

DFGame had its first field test this year, with a little platformer called Cloudy Climb. The game was very short and not great, but I was able to get things done without too much trouble. I'm in the mood to make another small game this year, but I haven't decided when. I'm focused on bigger stuff right now, so it'll probably happen much later in the year.

DFGame

On that note, let's look at DFGame. Since last year, DFGame has received dozens of improvements and 2 new modules. Despite the progress, I haven't made a new version since May. At this point, DFGame feels like it has made enough changes to consider a 2.0 version release. For the sake of making it a good one, I want to polish a little longer.

Halberd

This year also marked a return to my longest-running project: The Halberd RPG engine! This attempt is shaping up better than the previous ones, so hopefully things will continue to go smoothly next year. I'm not ready for a source release just yet, but it'll probably happen within the first 6 months of 2019.

...What about Singularity?

I've been awfully quiet about other projects for a while, and Singularity hasn't seen much attention since the release back in January. I've grown quite a bit as a software dev since then, and I want to make a cleaner and more polished release. I've scheduled an v0.4 release for next June, though obviously that date isn't a guarantee. I'll be focusing on bugfixes and polish this time around, since most of the important big features are already working.

A Little More

I didn't just spend all of 2018 programming (though I'll admit that was most of it). I also made some art! Following up on last year's attempts to learn pixel art, I kept practicing and improving. I'm not a great artist, but I'm miles ahead of where I began at this point. I can't wait to see what the future brings in this regard, who knows how my games will look in a few years!

On that note, I drew a few more things to cap off the year:
I'm also planning to look into a few other styles of art, such as digital painting. I think expanding my view of art will help me grow my style in general, so there may be more than pixel art around here a year from now...

Next Year

Besides the obvious, I have a few extra plans for 2019. I'd like to take dflib and fold it into the dfgame ecosystem, probably as its own set of high-level modules. This will not only give me an excuse to update and fix up dflib, but it'll also let any of my existing dflib projects to pick up any dfgame features they want. Most won't be useful, but there are a few interesting possibilities like audio notifications.

I also have another little something that might happen with dfgame later. We'll see about that...

12/25/18

Halberd: That's my property!

To anyone reading this on the same day that I post, Merry Christmas! Here's a little present: This year's final Halberd-related blog post.

Of my current priorities on Halberd, one of the biggest is building and integrating a property grid. I think this is a very interesting endeavor, and hopefully you'll see it the same way!

So what's a Property Grid?

When I spoke to some (programmer) friends about this, I was surprised to find out that some of them didn't initially know what a property grid was. So, let's start with definitions.

As the name implies, a property grid is a ui widget that lets the user inspect and edit the properties of an object. It usually amounts to a list of named fields, and you can find one in just about any game engine. Here are a few examples:

UE4's 'details panel' is a form of property grid
As expected, Unity's inspector panel is another good example
The ActiPro Windows UI framework also features a property grid
The GTK UI builder, Glade, also features something in this vein

If you're a game developer, you've probably figured out by now that property grids are a really important game development tool. This is even more true in RPGs, due to the large amounts of 'database' assets which lend themselves well to this type of UI pattern.

Digging deeper: How does a property grid work?

Like any programming problem, there are many ways to implement property grid functionality. However, I'd put most methods into one of 3 groups: Inspected, Declared, and Fixed. These are just personal categories, not proper terms, but I think they showcase some real differences.

An Inspected property grid assembles itself by looking at real game data and converting it to ui. This is typically done through Reflection, either by looking at data in a scripting layer or with a language that natively supports this, such as C#. For languages that can't do this out of the box, a dynamic class/property system can be added on top of the normal code. Examples of such systems can be found in Unreal Engine 4 and the GObject framework.

A Declared property grid is also dynamic. However, instead of inspecting objects at runtime it queries their information from a predefined source, such as a schema or similar descriptive document. Then, it sends data back and forth via Serialization instead of reflection. The result is less flexible, but it's also simpler and the underlying game code may be more performant since dynamic properties aren't necessary.

Finally, there is the Fixed property grid. I call this a property grid, but that may be an overstatement--this grid is essentially just a hard-coded bit of ui for interfacing with an object. By its nature, it's quite simple and totally static. Of course, it's also difficult to maintain and requires constant updates as the underlying data changes.

Depending on your use-case, any of the above can be valid approaches. The fixed solution may seem bad, but sometimes it's the best option: You don't need a powerful and complex solution just to edit a couple of fields.

What have I got?

At the moment, Halberd is stuck with the fixed style. I went for this solution early on to avoid getting bogged down while developing my proof-of-concept, but the scaling problems of this approach are starting to appear.

The general process of adding a new property to an object right now is:
  1. Add the property
  2. Add serialization for saving/loading
  3. Add simple getters/setters for editing
  4. Add the property to a Vapi file for interop access
  5. Add the property's editing widget to the ui file
  6. Add the widget code to the editor's vala class, including the signals for changing the property
That's a lot of steps for one property. With a simple property grid, I could skip steps 3-6 entirely and greatly streamline my development process.

A new property grid

With all that in mind, I decided to try out something better. Since most of my code is C, the declared style is necessary. But how to prepare the meta-information about the properties? In my case, it was actually rather simple. Since I already serialize my data to XML, I decided to go with the obvious option: XSD.

For the uninitiated, XSD is an XML-based schema standard for describing other XML files. While intended for databases, with a few additions the result can work quite well for defining a property grid!

The result looks like this:
You might recognize this as DFGame's editor demo which I completed last year. The controls were hard-coded since it was just a viewport showcase at the time, but now the editable parts are totally data-driven!

The schema that the editor is based on is a bit wordy, but pretty straightforward:
    1 <xs:schema
    2     xmlns:df="/org/df458/dfgame"
    3     xmlns:xs="http://www.w3.org/2001/XMLSchema"
    4     elementFormDefault="qualified">
    5     <!-- Types -->
    6     <xs:simpleType name="fill_type">
    7         <xs:restriction base="xs:string">
    8             <xs:enumeration value="true" df:displayName="Filled"/>
    9             <xs:enumeration value="false" df:displayName="Wireframe"/>
   10         </xs:restriction>
   11     </xs:simpleType>
   12     <xs:simpleType name="size_type">
   13         <xs:restriction base="xs:float">
   14             <xs:minInclusive value="0"/>
   15             <xs:totalDigits value="6"/>
   16         </xs:restriction>
   17         <xs:annotation>
   18             <xs:documentation>A decimal value above 0</xs:documentation>
   19         </xs:annotation>
   20     </xs:simpleType>
   21     <xs:simpleType name="degree_type">
   22         <xs:restriction base="xs:float">
   23             <xs:minInclusive value="0"/>
   24             <xs:maxExclusive value="360"/>
   25         </xs:restriction>
   26         <xs:annotation>
   27             <xs:documentation>An angle in degrees</xs:documentation>
   28         </xs:annotation>
   29     </xs:simpleType>
   30 
   31     <!-- Triangle struct -->
   32     <xs:complexType name="triangle">
   33         <xs:attribute name="size" type="size_type">
   34             <xs:annotation>
   35                 <xs:documentation>The size of the triangle</xs:documentation>
   36             </xs:annotation>
   37         </xs:attribute>
   38         <xs:attribute name="angle" type="degree_type">
   39             <xs:annotation>
   40                 <xs:documentation>The angle of rotation</xs:documentation>
   41             </xs:annotation>
   42         </xs:attribute>
   43         <xs:attribute name="color" type="df:color4">
   44             <xs:annotation>
   45                 <xs:documentation>The color of the triangle</xs:documentation>
   46             </xs:annotation>
   47         </xs:attribute>
   48         <xs:attribute name="is_filled" type="fill_type" df:displayName="Style">
   49             <xs:annotation>
   50                 <xs:documentation>Toggles filled/wireframe rendering</xs:documentation>
   51             </xs:annotation>
   52         </xs:attribute>
   53     </xs:complexType>
   54 </xs:schema>
One way to reduce the workload even further would be to tie this into a code generation system, but that strikes me as overkill for the time being...

What now?

I've been working on this feature for a few weeks now, but I finally merged it into DFGame's master branch yesterday. The next step will be to try and integrate it into Halberd, I'm sure there'll be more to do but I think this feature is a good investment for future work! Once the property grid's in place, the work will hopefully start moving a bit quicker.

12/4/18

Art, Take 2

Exactly one year ago, I posted some images showing my progress practicing pixel art. I've continued practicing since then, and I think the results are quite solid!

Let's get started with a quick review of the past year. Unlike last year's mostly unstructured practice, I've tried to aim for a few weaknesses in my art fundamentals and improve them. The main core skills I focused on were light and perspective, though I've been tentatively playing with anatomy and proportion lately. I also joined a couple of pixel art communities, which have been a very helpful source of critique.


With the stage set, let's make a few direct comparisons to last year:

Trees


Rocks


Tilesets

Click the image for a full-size version

As you can see, I've made some pretty good progress! Of course, I did quite a bit more than this: Here's an album with some of this year's finished work.

If you're interested in seeing more as I continue practicing, I occasionally post work on Twitter and Pixeljoint.

11/25/18

Halberd: What's a roadmap?

Since my last update back in October, I haven't touched Halberd's roadmap. The reason for this is simple: With a new work strategy, I wasn't really sure how I wanted to show and track progress. In the end, I quietly settled on using regular issues on the project's GitLab repo.

For the time being, I'm still keeping the code private. I'll make it public long before the first proper release, but I want a couple more months to get things cleaned up a little before then.

Now that all that's figured out, I think it's time to get back to posting. I have a couple of posts that I'd like to make before the end of the year, so things should soon liven up a little around here!

10/16/18

Halberd Studio: No Sleeping, Just Scheming

I didn't sleep last night. The cause had nothing to do with my projects, but I ended up thinking about Halberd for a few hours. The more I thought, the more I became certain: Something has to change.

If you read my roundup for September, you'll know that I actually made some decent progress. Despite that, I still have a lot of doubts. After last night, I re-read all of my recent posts and decided that a new strategy was in order.

There's a wall of text about my motivations between you and this strategy. Click here if you'd prefer to skip it.

...But Why?

Obviously, this is coming off as indecisive. Still, I came to an interesting reason to change things up. I wrote about a similar feeling in August. At the time, I wasn't happy with the game. I looked back at my first post on it, decided that my reasoning was still correct, and kept going.

As a refresher, here are the reasons I had for starting:
  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.
  4. 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.
I still think these points are sound. However, my current project isn't actually the best way to address them. Let's go down the list again:
  1. The first reason is spot-on. Making a game is a pretty solid validation process. Making a demo of the engine's features could also work for this.
  2. This point disqualifies a demo as a complete solution, but there's an important word in there: Good. A bad game won't convince anyone to use an engine, it may even turn them away.
  3. See point 1.
  4. Here's the other problem: I replaced one drawn-out process with a drawn-out process and a diversion that I didn't personally enjoy. Demos won't fix that, but I have some other plans.
'Henry' is not a good game. It won't be a good game, and I'd even go as far as to say that it can't be one. As I work on this project, I can feel the time I'm wasting. That has an impact on my productivity, and it's exacerbated by the fact that I was never really that interested in it. I knew that my options would be limited, so I tried to go as simple as possible. I also used the game to try a new post format. That's pretty much all I have to say about it, because there was nothing else to hold my attention.

Despite my lack of interest, I still want to make RPGs in general. I have a few 'real' ideas on the backburner, but Halberd just isn't ready for them. The engine is technically in an 'MVP' state because you can make a game with it, but it's not viable for anything serious yet.

The Plan

That last section went long, but it felt good to get it out. Next, let's talk solutions. Back in August again, I listed some wants. After re-reading them, I can confidently say that they mostly hinge on being more patient and giving Halberd the time it needs. Working solely on Halberd brings up the issue of fatigue, but nothing is stopping me from keeping my current 'alternating weeks' strategy. Let's run with that concept.

Halberd is a huge project, and there are a lot of very different tasks needed for its success. I've split them into roughly four different categories:
  • Foundations
  • Progress
  • Polish
  • Content

Foundations

Halberd rests on top of DFGame, and I've regularly had to dive in to fix issues and add features for the engine's sake. One thing that bothers me is that I never have enough time to polish all of this internal code. With the pressure of getting a feature to work so that I can finish whatever I started on Halberd, it's hard to spend extra time on code clarity, tests, refactoring, and so on.

Long-term, these things are necessary for a healthy engine.

Progress

The 'critical path' to making my dream games, if you will. This category represents the features needed to make a powerful and flexible engine, things like custom equations, items, cutscene and dialogue tools, etc.

Polish

Just getting Halberd to work well is enough for me, but to really sell (figuratively) the engine to the public I need to make sure that it also feels good to use. That means taking time to fix minor gripes, improve workflows, write help docs, and work on unifying the engine's look and 'brand'.

Content

I've never brought it up, but I think a big factor in novice-oriented engines is the quality and variety of the assets they pack in. I'm convinced that this is partly why so many people are attracted to RPGMaker, and also why some people look down on games made with it. Assets matter in the market that I'm planning to enter, and they're also a good source of practice.

If I spend enough time building my art and audio skills before I start my RPGs, I can make them truly live up to my expectations.

Conclusion

With some diverse long-term tasks prepared, the remaining question is how to divvy them up. Conveniently, I found out last month that I can get a couple solid features done per week. For now, I'm going to try focusing on each of these categories for one week every month. I'll keep this up until the end of the year, then I'll re-evaluate if I'm still not happy.

Looking further ahead, I'm about 5 1/2 months away from the first anniversary of Halberd's announcement. I don't think it'll be ready for release at that point, but I'd like to at least have some convincing demo videos by then! I'll also make the code public some time in the next few months, so that I can point people there for more detailed progress.

10/2/18

Halberd: September Roundup

It's been a pretty long month. A lot of general life issues cropped up, and I honestly feel like I didn't accomplish enough overall. I also didn't find the time to write any blog posts either, so I thought I'd try and go over the current state of things now.

Where we last left off, I was trying to find a balance between engine and game progress. For the time being, I've settled on alternating weeks. A single week comes out to be enough time to get one or two notable things done, so that seems to get me slow but steady progress on both projects.

Given that the aforementioned life issues probably cost me a week or two, it's hard to tell if the resulting development speed is actually acceptable. I'll probably have a better idea after next month.

State of the Game: Audible frustration

With all that said, I've actually made very little progress on the game. The main culprit is, as with Cloudy Climb, my complete lack of musical skill. I'm slowly improving but making music is still a difficult process for me. I think this problem will eventually go away, but in the meantime it's still a major roadblock.

I've made some progress on the art front, with a finished player sprite and the beginnings of the second area's tileset. Once the music problem is resolved, I should be able to keep going at a steady pace.


State of the Editor: Polish!

One of the things that concerns me about working on Halberd while making a game with it is how to resolve the potential for feature creep. Let's imagine for a moment that I decided to focus on adding NPCs to Halberd. If I succeeded, there would be a pretty strong temptation to add NPCs to the game as well. They would certainly make the game better, but they would also increase the scope of the final product. With enough features, I might find myself overextending the game way too far. Thankfully, I have a long todo list and many items on it have no effect on project scope. This month, most of my focus has been on UX and 'branding'.

UX

Improving the general workflow and looks of an engine is pretty much always useful, especially since Halberd is still so unpolished. So, I spent a couple weeks on making it look and feel better to use. I've been posting occasional screenshots to my Twitter account, here are a few for those who don't want to bother looking for them:
New landing page with a list of recent projects

Asset icons, and a new quick asset selection button

Settings split into sections, and a new vector editing widget with custom icons

There's more than this, but that covers most of the juicy bits. When the time to release this thing comes, I'll probably make another video in the 'walkthrough' style like I did last time.

Branding?

I've never liked branding, advertising, community building, and other 'tangential' aspects of development. This is probably because I'm not a social type, I prefer to sit in a dark room and create. However, reality dictates that if I ever want Halberd to be successful, I need to 'sell' it to its target audience.

Halberd will always be free (in every sense of the word), but in this day in age that's just not enough. I need to convince others that my work is worth using, and one part of that is building a consistent presentation and messaging. To that end, I decided to start thinking about this problem early.

"What should Halberd offer?"

This is an important question, one that I believe is core to making the engine more than just a technical success. A common question that I see whenever a new engine is announced is:

"Why use this instead of insert established competitor(s) here?"

I know that this question will come for me too, and I want to have a real answer ready ahead of time. I already discussed some of my motivations in my original announcement post, but I now have a pretty specific idea of where I want to take Halberd in the future.

Right now, I think there's still a divide between engines that are immediately accessible to newcomers and engines with modern and efficient development pipelines suitable for serious commercial work. Engines like Unreal and Unity have tried to style themselves as welcoming, but the fact of the matter remains that developers must learn to program to make much with them (yes, UE4 blueprints are programming). On the other side of the spectrum, some engines like GameMaker: Studio have tried to modernize and improve. This development is more interesting to me, but curiously a lot of more targeted engines (such as RPG Maker, SRPG Studio, Wolf RPG Editor, etc.) don't seem to have kept up as well.

Not that this has stopped developers, of course. I believe that good games can be made with any engine, but games are best made with a good engine. My hope is that Halberd can someday offer itself to RPG devs as an engine that's dead-simple to start, but offers enough power and depth to be ideal for professional-grade work. It can't live up to that dream yet, but I think having a strong vision from the outset will help ease people's fears.

Thinking about names

I like Halberd. It makes for a simple and memorable name. On the other hand, it's a noun that doesn't really describe anything. That's not uncommon in game engines, but I decided to try and find some other possible names.

To that end, I threw together a bunch of words that I could fit together to try and find something better. I mostly stuck to descriptive words like 'builder', 'editor', 'engine', 'game', 'rpg', etc. Most of the results didn't really impress me, but I do like the ring of Halberd Studio. It's not really any more descriptive or SEO-friendly, but it has a more official tone to me.

Given my end goal, it might be worth sticking to. My only concern is that there are already several 'studio' game engines hanging around, and throwing another one on the pile might not be a good move. I've keeping that name for now, but it's still not a final decision.

Next up

Looking back on this post now, I suppose September was actually rather productive! I'll probably try to focus a little more on the example game next month, since that hasn't seen as much progress lately. I still don't know how long it'll take to finish, but I'm hoping for some sort of official release before the end of the year. We'll see how that works out over the course of the next month or two!

8/20/18

Changing gears on Halberd

Right now, I'm in a bit of a difficult situation. My current game project has been taking much longer than I'd hoped, and I still haven't made a first release of Halberd. I don't make release dates anymore, but I'm still not happy with my current progress.

When I originally announced the game project, I acknowledged the risks and gave a few reasons why I felt the project was a good idea. Unfortunately, my arguments are still sound. The game has a reason to exist, and dropping it to speed up development doesn't strike me as a good option. So, I need to rethink my overall strategy.

What do I want?

When coming up with a new approach, figuring out I think it helps to consider what you want and why don't have it. The former helps you shape a goal, and the latter indicates the obstacles that you need to deal with to attain it.

In my case, there are a few things that I want:
  • I want Halberd to become a useful, successful game engine - That much should be pretty obvious, most people don't set out to fail.
  • I want to make good games - And, hopefully, have people play and enjoy them.
  • I want to make tutorials - To give back to the internet, of course!
On the surface, these goals seem pretty simple. However, I think the biggest reason why I keep running into problems is that these goals are in conflict with each other. And where does the conflict stem from? That's right, it's time! All of these goals are achievable for me on their own, but they're time-consuming enough that juggling them all is difficult.

Fixing the problem

Like with any other resource, the only ways to resolve a lack of time is to make more, or to use less. Making time isn't an option for me (besides quitting my job, which would be a terrible idea), so instead I need to find ways to balance time and quality.

I can start by striking tutorials from the list. I don't spend time on them now, and it's unlikely that I'll suddenly start later. That leaves me with just my programming projects, which are currently the main problem.

Another common option for reducing the time spent working is to collaborate with others. This is how most people cope with a lack of time, since dividing work isn't too difficult. However, freelancers are expensive (they need to live too, after all) and volunteers are typically less reliable. I don't want to shelve the idea entirely, but I think I'll at least need to save money or produce work that's more exciting before I can take advantage of this option.

Making Changes

In the end, I don't have any strong solutions to this problem. Working on one item to the exclusion of the other (as I have been recently) doesn't work well, so I need to find a way to reasonably balance out 'engine time' and 'game time' so that they can coexist. Here's my current plan:
  1. Go back to my regular posting non-schedule. I was using this game project as an experiment, but I'm not impressed by the results. I don't think I produced much interesting content, and I ended up spending a ton of time writing posts.
  2. Resume work on Halberd. I'm going to get started on the next release while this game project continues on the side, so that Halberd doesn't get bogged-down too much by side work.
  3. If I finish the next release of Halberd before the game, then I'll try to devote more time to finishing the game with that release. Otherwise (more likely) I'll wrap up the engine when the game finishes and release both together.
Future releases of Halberd will probably work the same way, with one game on the side dictating the engine releases. This lets me make plenty of games, but doesn't stop the engine dead in its tracks if the process gets bogged-down. In the long run, I'll probably also see if I can split things up in a more decisive manner with scheduling. That seems like overkill for the time being, so I won't try anything like that yet.

What this means for you as a reader is that I've split up the Halberd roadmap into two pages, one for the game and one for the editor. The blog will be getting occasional updates about both, and hopefully things will work out nicely!

8/16/18

Making the first Halberd game: Is this still a mountain?

Last time, I started building the actual first map for my game. A bit of messing around later, and...

I'm not really sure how to feel about this. It feels a bit noisy and chaotic, and it's clearly not very mountain-like anymore. Even running at my target resolution, the result is a little too confusing:

Clearly, I've over-corrected a bit. After simplifying the terrain a bit, I end up with this:

It's alright. I'm not thrilled with my results, but I think they look good enough. There's a line to be drawn in terms of polish and I've already spent a week on this map alone, so it's probably better to keep moving for now. If I feel a strong urge to do so, I can do another polish pass on the maps later.

...But Wait!

Unfortunately, we're not out of the foothills yet. After all, there's no music and no enemies! Given the fact that is is supposed to be a fairly short project and I'd like to avoid holding up Halberd's development for too long, I'm going to try sticking to more of a 'sketch' quality level, something like this:

This will be the combat background for the first area. It's rough and not really that detailed/attractive, but it's god enough to work as-is. If I can match this level of detail in the rest of my assets, it should be easy to complete the project quickly.

Moving on to the actual enemies, I need to keep the designs reasonably simple to draw as well. After all, some subjects are much harder to depict than others. To that end, I've made a couple simple designs for the first area:

They're not the most exciting creatures you've ever seen, but I think they'll work well as cute little monsters to deal with early on. Now I just need to add them in and take a crack at music, but that can wait for a future post. For now, I rest.

8/8/18

Making the first Halberd game: There's no math in this blog post, I promise!

In the last two posts I did a ton of math, all to make a squiggly line. That's peak efficiency right there, nowhere to go but down!

Anyhow, today will be a little more hands-on than that. To that end, I've produced a gorgeous tileset:

Being serious for a moment, this tileset should cover all of my basic needs for laying out a path. It has 3 colors, representing floor, stairs, and wall. For a  little winding path in the foothills of a mountain, that should be all I need to start with. Next up is the map itself:

This is the first time I've really been able to appreciate the scale of what I'm building. It's big, bigger than I'd really pictured in my head! And of course, I'll be building several areas of similar scale. It shouldn't be a problem, but man. That's a lot of map.

Well there's no time to spend crying over map dimensions, so let's dig in. First of all, I can cut out the margins...

...3 minutes in, I feel the sweet embrace of Carpal Tunnel Syndrome approach and hastily add a 'paintbucket' tool. Some limitations are just too harsh.

With that roadblock out of the way, putting together a path that mostly matches the calculations from earlier is child's play:

...it's not the most awesome map I've ever seen, but it'll serve as a good template to work with. Next, I abuse the properties of Manhattan Distance to make the path much more interesting with little change to its actual length:

After measuring, this path is pretty close to my 250 tile goal. Finally, I widen it out a little bit:

I can fix any errors and smooth things out as I go, so this feels like a pretty good base to work with. Next up, we need some art!

Art, and problems

Over the weekend, I assembled the start of a tileset for this mountain path:

One thing probably stands out here--There's a lot of brick, but not much natural stone or dirt. I tried a few rockier walls at first, but I had trouble getting them to look good with the rest of the tiles. In the end, I decided to go with retaining walls, as you might see in a couple spots on a well-maintained trail. I'll probably keep looking for a good rough stone wall for some of the higher parts of the trial, though.

Once that was done, I put the new tiles into the map and came to a terrible realization:

The walls have inconsistent heights, royally screwing up the perspective. It's blindingly obvious in retrospect, of course the edges of the terrain need to line up!

Unfortunately, this means that I have some fixing to do.....

8/6/18

Making the first Halberd game: Measuring foothills

In my last post, we did some simple calculations to estimate the amount of walking and combat to put into the game. Now, I'm going to use that data to do some real testing and level-building. But first, let's do a little more math.

Right now, Halberd's ability to resize maps is rather clunky. To make up for that fact, I want to get an idea of how big any given map should be before I make it. We can do this because we have the final length of the path the player has to follow: 250 tiles.

When in Manhattan...

The player won't have free movement in-game. Instead they'll be locked to the tile grid, with only north/south/east/west and diagonals available to them. Since position is locked, They're probably not going to take diagonals too often. So, we can get an estimate of our length using Manhattan Distance.

Unlike direct distance, Manhattan distance is just the sum of the distance on each axis. For instance, let's say your friend lived in a house 10 blocks north and 20 blocks west of you. With the Pythagorean Theorem, you could determine the distance "as the crow flies" to be ~17.3 blocks. But for the Manhattan Distance, you can just add the numbers together and get a distance of 30 blocks (the distance you're likely to walk to get there).

This can also work in reverse. Given a final length, we can subtract numbers from it to form a path, then add the segments on each axis together to get the dimensions of the map. It's hard to explain, so let me show you instead. Let's say we wanted to make a path that was 10 tiles in length. There are many ways to do this:

Even without drawing a box around these paths, we can still get their bounds by following them. Take the green one, for instance. It goes 5 units up, 4 to the right, then one more up:

Up 
  • 5
  • 1
Right
  • 4
If we add all of the numbers together, we predictably end up with 10. However, we can also add them in their respective groups to get 6 up and 4 across. Taking the first corner into account, that gives us a 5x6 area for this path.

So why are we doing this?

Let's get back to the spreadsheets. We already have a predetermined length, so we can get either of two things by picking the other:
  1. Map dimensions from the number/frequency of turns (as seen above)
  2. Ratio of up/down to left/right paths from a ratio of map dimensions.
For now though, we'll put this work aside. We can't make this decision before making some others first.

What is Area 1?

If we want to decide what our new path should look like, it would benefit greatly to know what the area should be like terrain-wise. I already know the answer, and so do you if you read the title of this post. However, I think the process is more useful than the solution.

Because Halberd is as limited as it is right now, a lot of my design decisions are derived from those limits. When I discussed narrative earlier, I brought up the transition from known/safe to the unknown, and used woods and plains as examples. In retrospect, I'm not fond of either solution:

Plains are generally very open and exploratory affairs. This can be great if exploration is the goal, but in a limited game with few mechanics on offer an open field isn't really that interesting. They also tend to be pretty sparse, which isn't a good first impression for a game that will mostly live or die on its environments.

Woods are fairly ideal in general. A forest offers a lot of opportunities for interesting environmental details, and trees are good for creating paths (and hiding little passages for keen eyes to find). However, such a solution won't work too well in Halberd's current state: With no layers in maps, we can't make tiles overlap anything. Not each other, and certainly not the player! As a result, an environment full of trees would be a nightmare scenario.

Clearly, I needed something else. I chose the foothills of a mountain for a few reasons:
  • On their own, the foothills of a mountain aren't as imposing or dangerous as the peaks. They also tend to have more greenery which helps lighten the atmosphere a bit.
  • Mountains seem to get used a lot as a symbol for a challenge or ordeal. So, starting in some foothills implies that the real danger is up ahead. To me, this fits well with the progression established earlier.
  • Mountain trails and the like are pretty restrictive. This presents the opportunity to add more interesting or complex scenery bits (translation: trees) where the player can't possibly reach and/or clip into them. Tile overlaps can be faked if you don't need tons of them, so it works for this situation.
Of course this isn't the only possible option, just the one I've chosen. Now that we know what the map will offer in terms of terrain, we can use this to get a general idea of the map's size. Since we're building a mountain trail, it stands to reason that we want our player to head up. This is especially true since making sloped tiles that work properly isn't yet possible in Halberd. However, most gentle trails have a lot of winding to them. If you look at any local mountains you'll probably see a long and circuitous 'easy trail' and a few more direct 'hard trails'. Since we want the first area to feel pretty non-threatening, I think it makes sense to have a winding path.

Whoops, more math!

Since the two ideas that I just outlined contradict each other, I think I'd like to see a fairly even map ratio. Unfortunately, getting the dimensions and path lengths will be difficult because the path winds back on itself. So, we need some more complicated calculations.

Lets say that we want a path that crosses the width of the map twice, like so:
Let's also assume that we know the path length (since in our real path, we'll know that too). In this case, we'll go with 100. Given that, the target map ratio (1:1) and the number of crosses, how do we determine the size of the map?

Since we have the width-height ratio, we can also determine the horizontal movement to vertical movement ratio by multiplying by the number of crosses. Better still, we can use this number with the total length to get the amount of horizontal/vertical movement and the width/height of the total map!

Let's try with a real example now. I want my 250-tile path to fit a map with a 2:3 ratio. So, I plug that information into this handy spreadsheet I just made:


Just like magic, I now have map dimensions! The 'pad' entries at the bottom represent the map dimensions with enough extra space to prevent the edges from scrolling onscreen. With this, everything is now in place to (finally) begin working on the map!

As a side-note: I think I'm starting to like spreadsheets a little too much. I suppose that's a fine quality for an RPG engine-builder, but still.....

8/1/18

Rearranging things

As you've almost certainly noticed, urls around here have changed a bit. There was a short kerfuffle but everything is now in working order. As I promised several years ago, the main www.huguesross.net domain now points to the main site. To keep this blog reasonably easy to access, I've moved it to the blog.huguesross.net.

At some point, I'd like to set up something better for hosting and running my site/blog. I'm not sure what the specifics will look like yet, since I have a lot of options for hosting, blogging engines, etc. It's also not really necessary yet. As long as Google doesn't lay out plans to shut down Blogger (wouldn't surprise me, given the few updates it gets) I'm not in a huge rush to leave.

Still, it's something to consider. If I ever decide to try and make something bigger and more polished (Halberd, perhaps?), it would be nice to have something established for presenting another site. Moving out isn't a priority of mine, but it's somewhere on my radar.

For now, enjoy the shiny new URL!

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!