4 Hugues Ross - Blog: 2017
Hugues Ross

12/16/17

Taking a Break

It's holiday season, so I've decided to take the rest of the month off from posting. I will have the usual end-of-year reflection post, so either that or the Singularity v0.3 update post will be next.

Happy Holidays!

12/3/17

"Art"

I've wanted to be good at art for a very long time. I spent countless hours trying to teach myself 3D modeling back in highschool, and I originally wanted to make art posts a regular event on this blog when I first started it. Obviously that never happened, but I haven't quite given up on art yet.

During my break in August, I decided to finally try to get good pixel art. Following through on that, I've been practicing almost every day. So far, I've made somewhere in the ballpark of 60 images. I wouldn't call myself competent yet, but I think I've improved enough to make a little "progress showcase".

Enough talking, let's get to the art

I went through my art folder and tried to find similar pieces that
  1. I had considered 'done' at the time (no WIP/unfinished pieces)
  2. Had a reasonable time difference between them
Then, I put them into groups and made some nice little comparison images:

Trees

 Rocky Walls


Sand


Foliage


Stone Bricks



So yeah, that's what I've been up to for the past 3-4 months. I'm going to keep practicing pixel art, and maybe do little gallery posts like this on once in a while. I'll also try to take my time making art for any future game projects, so hopefully my practice will start paying off once I'm back to game stuff.

11/26/17

Playing with Cairo

This week, I took a break from Singularity to mess around with my desktop a bit. In the process of that, I finally sat down and tried using the Cairo vector graphics library.

The Goal

Right now, I'm using a fork of the i3lock utility to lock my PC. Honestly, I'm not thrilled by how it looks. It basically just displays a simple indicator over an image you provide (or a blurred version of your desktop), and that's it. Here's an example from the Github page:
Lately, I've been thinking that the overall "circle with some text in it" design it looks kinda tacky. Unfortunately, I don't know of many other screen-locking options. So, I thought I'd make a small fork that provides a more interesting overlay. I have a lot of ideas for fun designs and overlays that I could use to replace the old design, but I decided to start with something basic:
Note: Colors and fonts aren't final. Just needed something to put in this mockup
I figured that a simple static design would would be pretty easy to swap in, and then I could look into some crazier ideas like dynamic overlays and procedural generation.

Current Progress

To get a new overlay working, the obvious first step is to figure out how the old overlay works. After some poking in the code, it looks like i3lock renders its overlay via Cairo, so I finally decided to finally learn the API.

Cairo is one of those things that I've known about for years, but never really had a good excuse to play with. This mini-project gave me the perfect opportunity, so I decided to make a little playground application where I could mess around. To make things extra-simple, I also did it in Vala. I'm still not sure if I want to try and hook vala-generated code up to the final product, but it's a big help in the short term. After a couple hours of playing around, I made a function to draw those colored parallelograms (which I called lozenges in code, because only a sadist would casually drop a word of that length into a function name):

   53     public void draw_lozenge(int x, int y, int width, int height, int spacing, float[] ratio)
   54         requires(ratio.length >= 3)
   55     {
   56         ctx.move_to(x, y);
   57         ctx.new_path();
   58         ctx.line_to(x + (width * ratio[0]), y);
   59         ctx.line_to(x + (width * ratio[0]) - (height), y + height);
   60         ctx.line_to(x, y + height);
   61         ctx.line_to(x, y);
   62         ctx.close_path();
   63         ctx.set_source_rgba (147.0f / 255, 87.0f / 255, 57.0f / 255, 1);
   64         ctx.fill ();
   65 
   66         ctx.new_path();
   67         ctx.move_to(x + (width * ratio[0]) + spacing, y);
   68         ctx.line_to(x + (width * ratio[0]) + spacing + (width * ratio[1]), y);
   69         ctx.line_to(x + (width * ratio[0]) + spacing - (height) + (width * ratio[1]), y + height);
   70         ctx.line_to(x + (width * ratio[0]) + spacing - (height), y + height);
   71         ctx.set_source_rgba (214.0f / 255, 165.0f / 255, 122.0f / 255, 1);
   72         ctx.fill ();
   73 
   74 
   75         ctx.new_path();
   76         ctx.move_to(x + (width * ratio[0]) + (width * ratio[1]) + (spacing * 2), y);
   77         ctx.line_to(x + (width * ratio[0]) + (width * ratio[1]) + (spacing * 2) + (width * ratio[2]), y);
   78         ctx.line_to(x + (width * ratio[0]) + (width * ratio[1]) + (spacing * 2) - (height) + (width * ratio[2]), y + height);
   79         ctx.line_to(x + (width * ratio[0]) + (width * ratio[1]) + (spacing * 2) - (height), y + height);
   80         ctx.set_source_rgba (161.0f / 255, 124.0f / 255, 91.0f / 255, 1);
   81         ctx.fill ();
   82     }

I am 100% certain that this code can be simplified further and made more generic, but for the moment I'm happy enough with the result.

Besides the missing text, this is almost exactly the same. The big difference is that whereas the previous image was painstakingly hand-made, this new version is the result of 2 simple function calls.

What's Next?

Naturally, the next steps are to add text and get the new design into i3lock. Cairo provides some text-rendering methods (i3lock uses these already), and I believe there's also a library called PangoCairo that adds rich text/formatting/markup via Pango. I haven't tried either of these approaches yet, but I will soon enough.

Once I have a working i3lock with a custom design, I'll post again and look at some of the interesting options that this opens up for me.

11/12/17

Singularity: It's the Little Things

It's been a few weeks since I wrote about some of my old mistakes working on Singularity, and I think it's time for a little follow-up. I've implemented all of the changes that I mentioned (and they work), so I'll be discussing two "smaller" features that I've been working on and what I've learned by working on them.

Look, Ma, no Feedback!

One big problem that I've had in this new version of Singularity is how opaque it is about everything. Before I started working on it again, there was no way to see if any feeds failed to load, or where feeds pointed to. As a result, a feed could go down and silently fail for months while you were none the wiser! Since I'd identified this problem before I started work again, I was already planning to do something about it. To keep things simple, I'm just making the text in the feed sidebar stand out more for now.

So that's the first piece of this puzzle. However, there remains one big problem: What do you do when you know a feed doesn't load? I knew that I had a large number of broken feeds, but without somewhere to see the url it would be difficult to know if the feed had moved or been deleted, or if it was just a parser error.

I'm still mulling over the best solution to the problem. For the moment, I've created a properties page for feeds that contains info like the title and url. This works fine, although it could still use some polish. Another feature that I'm considering is an 'update status' indicator that could display detailed update progress and error messages. Either way, it's clear that Singularity needs to provide more feedback when things fail.

Lesson Learned: Detailed feedback can be very important, and not just as polish!

Getting Organi--Wait, Wrong Series

I'm nearly done with a new feature that, apparently, is one of the most important things to add. When I started rewriting Singularity a while back, I wanted to add folder-like entries to the sidebar so that users could organize their feeds. This seemed like more of a "would be nice" feature than an absolutely vital one, so it was left in a half-finished state.

Boy, was I wrong with this one. I decided to dedicate the weekend to finishing the feature, and it turns out to be a complete game-changer. I didn't expect it to be important, because I mostly just checked my feeds via the 'All Feeds' view. However, I had my logic backwards. I was checking the 'All Feeds' view because there was no other way, not out of preference. I figured this out after sorting all of my feeds into collections, and seeing a result like this:
In the left image, you know nothing other than the fact that there are 3 unread items of some description. What are they? How long will it take to read them? Do I care right now? The program has no answer for you, because the feeds with new items are hiding under 100 others. Even if they were at the top, you could have 30 feeds with one update each. Instead of hunting around, the most obvious solution is always just to click 'All Feeds' and read through everything.

The picture on the right gives much more info. Right off the bat, you know that 3 of the new updates are news articles. If you're about to head out then you probably don't want to check them yet, and you don't have to. It suddenly makes a lot of sense to check the categories that interest you, and leave the stuff you don't want to check for later. I'm glad to have this new feature, but I'm kicking myself over how many months I suffered without it.

Now that it actually makes sense to check things that aren't 'All Feeds', I've also added a small quality-of-life feature: Item views now display the feed/collection that they correspond to. It's a minor thing, but it's nice to have.

Lesson Learned: Just because the user always does something doesn't mean that it's the only way they ever will. Some habits may be a result of weak design.

Conclusion

For the first time in quite a while, I feel happy and optimistic regarding Singularity's future. My last rewrite ending halfway put me in a spot where I was unhappy with the result, but the polish and new features feel like a much-needed breath of fresh air. My goal of a new release by the year's end is starting to look much more realistic!

10/29/17

Roundup, October 2017: Demo Time!


As you can plainly see above, my little tussle with Glade has borne fruit in the form of a new DFGame demo! The editor module isn't completely finished, but I had enough to work with so I decided to make a video anyway. Now then, let's discuss how the demo (and by extension, the Editor Module) works.

Split Architecture

To understand the current architecture of DFGame, I think it's useful to first look at the original architecture of Halberd, my WIP RPG engine. Halberd's codebase spawned DFGame originally, so it's useful to see where things came from. As I explained back in 2015, Halberd (and later, DFGame) was split into 5 modules:
  • "Common" - Contained all code that worked in the editor and game
  • "Editor Backend" - Editor-specific code, without the UI
  • "Game Backend" - Game-specific code, without GLFW
  • "Editor Frontend" - The editor UI
  • "Game Frontend" - The game startup code, with stuff like window creation
When DFGame, I identified a couple weak points in this design. First of all, lumping nearly everything into a common module was a bit silly. Second, the backend/frontend concept felt somewhat unnecessary. To correct this, I created DFGame's current modules:
  • Core
  • Math
  • Audio
  • Graphics
  • Gameplay
  • Application
  • Editor
 The first 5 modules are fairly self-explanatory. The application module is the general equivalent to the "Game Frontend" module and the Editor module is the "Editor Frontend" and "Editor Backend" rolled into one. The idea is that both of these modules will implement a common API, allowing the game to run regardless of where it is. This is the most important part of setting up a robust set of development tools, ensuring that the game code and window/input code are seperated.

Vala Interop

Besides the architecture, there's a second detail needed to get DFGame's editor functionality working. Typically, the languages used to write software and the languages used to write games are different. This can lead to many issues getting games to embed nicely inside of their tools, especially if there are ABI incompatibilities between the languages.

This was one of my main reasons for picking Vala. The Vala compiler translates Vala code to C, so getting a Vala frontend to play nice with a C backend is quite simple. To make the triangle in the editor demo controllable from Vala, I only needed to write a simple binding treating it as a class.

Conclusion

To sum things up simply, building a good editor for your game requires two things:
  • An architecture that allows the game to run without the window/input code
  • A means of bridging the editor's language and the game's language (This could be as simple as using the same language for both)
Once you have both of these things handled, you can work on your editor without worrying much. Once I finish up the Editor module, I'll be able to do much more with DFGame. I'll still be focused on Singularity for the time being, but I'll still be working on this occasionally.

10/22/17

Dusting the Cobwebs out of Singularity: Mistakes and Lessons

I'm pretty tired today, so I'm going to talk a little about my strategy for finishing up this Singularity update and some of the issues I see in my old code.

Homecoming

Getting back to an old codebase is usually a wince-inducing experience, but this instance was worse than usual. Singularity was always a learning process for me, as I taught myself software development over the past few years. Since putting the project down, I've had close to 9 months of software development experience. Naturally, my skills have changed drastically and my old code looks terrible now.

Since I left off mid-refactor, the code is in a bit of a half-finished state. I don't want to go all the way back to the last update, so I'm trying to fix and re-purpose what I've already got to avoid some poor decisions from the past.

Static Shock

For a long time, I regarded globally-accessible data as a very bad thing. As a result, I avoided static functions and variables like the plague in most of my software. You don't want to overuse these types of things, but it's important to remember that there's pretty much nothing in programming that should always be avoided.

In this case, the most obvious use case for statics is Singularity's settings classes. That's right, there were two of them. Depending on how loose your definition of "settings" is, you could even say that there were three (One to act as an interface to the application preferences, one to provide command-line settings, and one to provide the resolved path to the database). None of them were static, so if I needed them in a class I had to make that class hold a reference to the one(s) I needed. Some of those references even had different names!

I have since made the contents of both "main" settings classes static, and nested the command-line settings into the global settings. While I was at it, I also folded the path resolver into the command-line settings (since that's what decides the db path most of the time anyway). The result absolutely violates SOLID, but that honestly doesn't matter because it also greatly simplifies the affected code and makes it much more understandable.

Lesson learned: Trying to follow a particular coding paradigm perfectly at the expense of your actual design is, naturally, a terrible idea. At the end of the day, there's a time and place for everything.

Shameful SQL

I don't think I've ever really enjoyed working with SQL, nor do I expect this to be a particularly unpopular opinion. Within Singularity's SQLite database, there's a table containing all of the feed entries that it has saved. As it turns out, these entries have no unique keys and are subject to change. That makes swapping them out in a clean fashion damn near impossible.

So where did this terrible idea come from, anyway? The answer is GUIDs. RSS/Atom feed entries require a unique ID. However, we can't use that as our key in the database because keys could overlap between two feeds. My current plan is to combine something from the owning feed with the entry's GUID, and then hash the result. Simple and reasonable, right? Well, my OLD solution for handling updates was this:
  1. Create a new temporary table and fill it with entries that match our feed.
  2. Create a brand new unique index on the GUID (since there's only one feed, it should be unique now).
  3. Save the items to this temporary table
  4. Copy the entire thing back to its original location
  5. Drop the temporary table 
  6. Repeat for every individual feed (about 700 times)
  7. Put the kettle on the stove, because this is going to take a while
Sometimes, (exactly 50% of the time) it crashes the entire program because a GUID managed to show up twice and database errors are treated as critical. Looking back, all I can do is cry.

Lesson Learned: Just because you just learned a couple fancy SQL tricks doesn't mean you should actually use them. Instead, consider if there's a better solution that doesn't overwork your database for no reason. Or at least use a better database, like PostgreSQL or Lucene.

Think Big! No, Smaller!

Often, it's a good idea to consider how well a solution might scale. After all, projects grow in scope over time and you don't want to leave yourself with a subpar solution down the line. On the other hand, it's also important to consider the current scale of the project you're working on.

Case in point, I made the rather poor decision to load as little as possible into memory. This seems smart, since it saves on RAM, but I don't need to do it! Seriously. Let's look at the numbers:
  • I'm subscribed to ~700 active feeds
  • My current Singularity database holds ~1 year of feed entries
  • My current Singularity database is just over 100Mb in size
At this rate, singularity might end up using 1Gb of RAM...in a decade. Most modern web browsers regularly eat up that much right now! By the time the database gets big enough to fill my current machine's 16 gigs of RAM, I'll be several decades underground already. Unless I decide tomorrow to make Singularity into a big public online service, there's no point to optimizing for space.

More than just saving on RAM, I've repeatedly butted heads with a messy "clean up" system to auto-delete entries after a certain length of time passes. This is even more misguided, considering how cheap and plentiful hard drive space is. On top of adding extra bugs and code, this "feature" is much less useful than, say, a simple archival system that hides old entries while still letting you search for them. Unless a user was tracking a ludicrous number of feeds, I really don't see the point in trying any fancy space-saving tricks that slow things down and introduce bugs.

Lesson Learned: Base your projections on real use-cases, not crazy what-ifs and guesswork.

Conclusion

There are plenty of other problems left, but these are the big ones that I'm working on right now. Besides this I've still got a few other projects that I'm toying around with. Still, this one has my interest right now so you can probably count on more updates as development continues.

10/15/17

DFGame: Glade-ing Along to Victory

I planned to take a break from DFGame, but I happened to be in the mood to play around with the editor module. I ran into some issues while working on a new demo, and ended up having to do a few hours of research to get things working. Then I thought to myself: "Gee, someone else is bound to have this problem. Maybe I should write about it!"

What's New?

Sometime last year, I learned how about this cool feature in Vala, and started using the Glade UI editor with my software projects. However, it was only recently that I learned about a way to add custom widgets (such as DFGame's editor widgets) to Glade for graphical editing. Naturally, I had to give this a shot for the new and improved DFGame!

Let's discuss what went wrong, and how I solved these problems.

Problem 1: Nothing Happens?

It took quite a while for me to actually get any new UI elements to appear in Glade. There were a couple issues that caused this, primarily thanks to the documentation being rather vague about about how templates work... at least until you notice the tiny "next" button. Let's look at the example widget catalog that the documentation shows:

<glade-catalog name="foo" library="foo" depends="gtk+">
  <init-function>my_catalog_init</init-function>

  <glade-widget-classes>
    <glade-widget-class name="FooFrobnicator" generic-name="frobnicator" title="Frobnicator"/>

    ... widget classes go here
  </glade-widget-classes>

  <glade-widget-group name="foo" title="Foo">
    <glade-widget-class-ref name="FooFrobnicator"/>
    ... widget class references go here
  </glade-widget-group>

  ... widget groups go here
</glade-catalog>
(Borrowed from this page)

The difference between "name", "generic-name", and "title" isn't immediately obvious. If you look at a later page, there is an explanation:
  • "name" is the name of the widget's class in code. It also seems to be used for class references in widget groups later in the file
  • "generic-name" is used internally, I guess? Still not 100% sure on that one
  • "title" is what the user will actually see in Glade
Unfortunately, this still wasn't enough because there remained an underlying problem to address: I write my Gtk code in Vala, but Glade only cares about GObject C. For the unacquainted, Vala acts as a wrapper language of sorts, and gets converted to GObject C for compilation. This means that there are two more things to adjust:

First of all, the class names are different. C lacks namespaces, so in order to provide them Vala adds each namespace onto every class that you create. In my case, this meant changing "Viewport" to DFGameViewport.

Next, there's a less obvious issue. Vala generates something referred to as a "get type function" which does something? I assume it either returns something that represents the object's type, or it returns an instance, but I don't have enough experience with GObject to know for certain. Glade overrides this function to create placeholders, but it apparently guesses the function name based on the "name" value that's passed in. In my case, I had to pass in the function name explicitly in order to make the catalog work. This is probably just a quirk in Vala's naming conventions, I suppose.

Once that was out of the way, Glade finally displayed my new viewport widget for DFGame and all was well, right?

Problem 2: Nope, That Doesn't Exist

As any seasoned programmer will tell you, life is never simple.
The fixes above were enough to let me create the UI for a new demo, but once the time came to actually test it out the UI wouldn't load! Instead, I was left with a cryptic message:

"(demo_editor:24355): Gtk-CRITICAL **: Error building template class 'MainWindow' for an instance of type 'MainWindow': .:3:4733 Invalid type function 'df_game_viewport_get_type'"

...???????!!?!??!??!?!!!??!!?!
The class was there. I could see it in the code. The library was definitely getting linked. So why then did it fail? Given a good couple hours, I was unable to answer this question. Luckily, the internet came through for me. All I had to do was slip in a single line of code at the start of the program
typeof(Viewport).ensure();
...and that was enough.

Takeaways

 This little experience further cements my thoughts regarding Gtk and many GNOME technologies, and I thought I'd discuss that briefly before as this post wraps up.

I like working with Gtk, Vala, and so on, but I think many of these technologies share the same problem. At the same time as GNOME works to streamline the design of its software and simplify things for normal users and new devs, there's this weird dropoff point where most docs past the beginner tutorials assume that you understand the technology stack and just need a quick reference.

The result is (presumably) "intermediate" devs like myself getting lost and confused after their gentle start suddenly drops out from under them. Thankfully, I ran into most of those issues a couple years ago, but occurrences like this one remind me that they still exist.

So I guess today's lesson is...maybe I should try writing a couple mid-level Vala/Gtk tutorials? Maybe GNOME needs more acknowledgement of their newer users and non-C APIs? Beats me.

10/1/17

Roundup, September 2017 - It's done!

It took longer than planned, but we're finally there:

Additional Comments

As I said in the video, DFGame v1.0 is now out! After almost 2 years of effort, I'm glad to see this project more-or-less done. There will be more, but for now it's time to wrap things up and move on.

I had an idea for another DFGame demo, as I mentioned last time. However, I wasn't very happy after messing around with it. After giving it some consideration, I decided not to go forward with it.

Next Up

Now that I'm done with this project, I'm going back to my other projects to continue them. I haven't had much time to work since I started working on DFGame again, so I'm going to go back and work on some of my software projects. In particular, Singularity has been sitting around mid-rewrite for a long time, and I'd love to have a new release out later this year (or early next year).

9/24/17

Update: Thinking About the Future, and Looking to the Past

Thanks to my shoulder, I've had a lot of time to think lately. I'm not very happy with the work that I've produced over the years, and I think that something fundamental needs to change. If you don't care too much about the specifics, you can scroll to the last heading for a quick summary of what I plan to do.

...Still here? Alright. Let's look back over the past 5 years.


In the beginning...

In late 2012, I was an eager and bright-eyed lad who was ready to try out this whole blogging thing. I was primarily inspired by the work of Shamus Young, whose blog I'd been following for a few years. To some degree, I think it shows:

"Shamus wrote some really great D&D stories, I should document the D&D campaign that I'm playing now!"
"Shamus wrote about some cool programming projects. I should do cool programming projects and write about them!"
"Shamus has a webcomic. I should do art stuff!"

He wasn't the only influence, but certainly the strongest. I also remember seeing video creators on Youtube and webcomic artists putting out work several times a week. For that reason, I created this ridiculous daily posting schedule. One thing that I failed to consider was that these individuals did nothing but make what they were posting. Indeed, for many of them this was their job, and I've heard that many such creators work well over 40 hours a week to keep such schedules. This plan of mine was doomed from the start, because I chose to try and mimic people who were quite different from me.

Alas, looking at work made by someone else and thinking that it's cool doesn't always help your own work. I couldn't simply copy Shamus's work, so the blog spent a long time being updated intermittently, with occasional apologies and failed promises.


Good projects, and AMAZE-ingly bad decisions

Around early to mid 2013, I started one of the projects that would last throughout this blog's life: Singularity. I started it with no plan, merely creating it out of necessity. Despite that, I could argue that it's also my most successful project: I created something just for myself, with no expectations, and ended up with something nice. Keep these italicized sentences in mind, they'll be important later.

Singularity is not all that I started then, either. During the summer, I also started AMAZE and the "Games I Play" series. The latter was about as doomed as my first schedule, and here's why:

I still remember how the concept of "Games I Play" was conceived. I had the problem of having too many untouched games in my Steam library, and no time to actually play them. Why was there no time? Well, I had to work on projects and post about them online! In other words...
  1. The Problem: No time to play games, because I had to work and blog.
  2. The Solution: Make games part of the work and blogging.
Seems pretty damn stupid in hindsight, huh? But hey, "Shamus Young writes about the games he plays, I should do that!" Here we have a time commitment issue, and a response that worsens the true problem in an effort to be someone else.

Now, let's talk about my darling AMAZE. Despite how much I hate the final product, AMAZE was ok as a subject. I posted screenshots, and wrote regularly about the things I was interested in! However, there's an interesting trend hidden in the AMAZE posts. As I became less interested and more "serious" to hit deadlines that I'd set, my blog posts went from this to this. Excitement and screenshots gave way to changelogs and walls of text. Once again, these two projects demonstrate a simple fact: I produce the best content when I'm excited and engaged with it, not when I feel obliged to make it. Obvious, I know. But let's move on, there's more to cover.


Total overkill

I'm skipping Space Douchebag because the same conclusions can be drawn from it as from AMAZE. Instead, we now fast-forward to 2014, DFEngine, and Akradion. Technically, DFEngine began with AMAZE, but this point is when I really got serious about it. As I've elaborated before, the concept of DFEngine was flawed. Trying to make a full-blown game engine because I'm too slow to iterate is like trying to build the LHC because there's a mosquito in your room: Not only is it a glorious waste of time, it also makes absolutely no sense. I still believe that DFGame will be a better bet in the long run, as it's mostly just a way to skip writing boilerplate code.

So, what about Akradion and Cloudy Climb? Besides being the first projects made after a DFGame version, they have one other thing in common. Rather than being games that I dreamed of and was excited for, they were instead an attempt to prove something. Ultimately, both games suffered dearly because of that. My line of reasoning when making these games went a little like this:
  1. If I'm making a game engine, it obviously needs a physics engine. That's a thing that game engines have.
  2. I need to make a game to prove that this game engine idea works
  3. My game engine has physics, so I need to make a game with physics to prove that the physics engine works.
 That set of thoughts above has many problems. Let's dissect them a little:
  1. My games have always been simple and 2D. Obviously I didn't need a physics engine, I had never used one before!
  2. As it turns out, making a full-length game just to be sure that some tech works is a huge waste of time. I keep doing it too, it's a bad habit. This is why I forced myself to keep the demos I'm making for dfgame as small and simple as possible.
  3. Neither Akradion nor Cloudy Climb are actually good choices for testing a physics engine! Seriously! Akradion is a game that relies on an object that retains constant velocity at all times, a worst-case scenario for physics! Cloudy Climb only really makes use of gravity, so a big physics engine is totally unnecessary.
In other words, a project that started as a supposed time-saving measure wandered off course in an attempt to make a fancy game engine. It then split into more projects, which were doomed from the start because I'm a bad planner. Ultimately, DFEngine was about a one and a half year-long diversion from what I cared about. I'm actually ok with most of that, since trying out things that interest me is fun. However, looking at the posts you can see the usual changelog post structure from AMAZE take over after a while.


Why teach?

Next, let's discuss tutorials. The roguelike tutorial series that has been in progress for years has never really reached a point where I was happy with it. So why did I start it? For that matter, why am I still writing it? Let's discuss.

I spent many years learning to program and make games. I actually started all of this back in middle school with Game Maker, only transitioning to more "professional" tools once I started college. Throughout my life (even now, in fact), I've regularly referred to guides and tutorials in order to learn various tricks and techniques. For much of that time, I felt a desire to give back with tutorials of my own once I got good at my craft.

Unlike the many of the blog-related decisions I've made, the decision to write tutorials in general had decent reasoning behind it. Furthermore, I think it'll work out eventually. So, why was the roguelike tutorial a failure for me?

At the time, I wanted to make an ASCII strategy game of sorts. When I returned to the project, I had a cool roguelike idea that I wanted to make. I don't think that's a coincidence. Rather than simply make the games that I wanted to, I found an excuse to try and work on something similar, via tutorials. Rather than just doing what I wanted, I invented a new series of posts to 'legitimize' my desire as an extension of my blog. It's no wonder then that the tutorial was never well thought-out or exciting to me. I wanted to do something else the whole time! Compare the forced and lackluster entries that I've been putting out lately to something like this post, and you'll see a world of differences.


Unfortunate truths

Ok, I think that's enough tiptoeing around the subject. What do all of these events point to? What's my point writing this? Well, it's really quite simple:

By forcing myself to only do "blog-worthy" things, and acting beholden to a theoretical reading audience, I'm harming both my blog's quality and my own life.
That's a conclusion that's taken about 2 months to reach. The one thread that ties many of my threads together is an attempt to emulate the content creators that I like. I envision myself as them, and imagine that I have an audience the same size that they do. Often, I make decisions based off of this. It's why I feel an urge to apologize at every delay and schedule change. It's the true reason why I just can't leave a series that I don't enjoy alone. To some degree, it also stops me from making progress. Every month, I spend:
  • ~1 week preparing, recording, and editing an update video
  • ~1-2 weeks writing a new segment of the roguelike tutorial
  • 2-4 days writing some other post
That leaves me with only a week or two to actually work on DFGame. It also keeps me from trying out new ideas and iterating. I've had a lot of really cool project ideas since I started work, and I've had no choice but to put them off until "after DFGame".

Except, that's not true at all. I have a choice to stop and do what I want, whenever I want. The only thing that stops me is my schedule. The only reason I have a schedule is to guarantee regular content on my blog. And why do I need to guarantee that? See Above.


The almighty power of boredom

Let me tell you a little story:

About a year ago, I had a cool game idea. The game in question would involve some fairly heavy adult content, so it wasn't "blog-worthy" at all. At the time, I was still adjusting to life in Montreal and figuring out post-immigration stuff. I also had a few issues in my life that put me in a bad position for a while, and I wasn't sure if I could keep writing the blog due to my job.

Since I didn't want to work on my blog, I worked on the game. In just a few scant months, I wrote an entire engine from scratch, complete with a data-driven dynamic UI system. I started writing down ideas, building roadmaps for development, drawing first-draft animated sprites for characters, etc. Then, I got the greenlight to blog again and I haven't touched the project since!

Flowcharts tracking development progress.
The bottom red circle was a public demo release.
So close, yet so far...


You see, I've written in the past about how blogging with a schedule keeps me productive and how vital it is, but at the end of the day you can lock me in a room for 3 months with no blog and I'll still write yet another game engine. Development is what I do. It comes naturally, and trying to keep to a rigid schedule or only focus on one thing for a long time doesn't help.


If you're scrolling past the wall of text, you can stop now

Ok! That's it! No more long-winded storytelling! It's time to talk about how I'm going to fix this problem. I'm going to keep this short and sweet, you just read the whole story so you don't need much more:

  • Effective immediately, I am cancelling the roguelike series. No hiatus. It's over, it was a bad idea, and I can always revisit the subject when I'm older and wiser. I'll leave the text around for now.
  • Starting next year, no more schedules and no more promises. I'll write when I feel the urge, and I'll develop whatever I damn well please. There will be fewer posts. I guarantee it. But every single one of them will be carefully written and edited for maximum quality.
  • When that happens, I'll finally redirect the huguesross.net domain to my site's landing page. That page and the about me page have been redesigned, and I'm working on the tutorials section. That section will hold both longer tutorial series and any informative posts that I think are useful and good enough to share.
If I change my mind about all of this, I may still keep the schedule. It's possible that I'm just in a rut, or mildly burnt-out. I'm giving myself 3 months to reconsider this decision, to ensure that it's really the right way to go. At the end of the day, I don't want to drop the blog. I think keeping a blog that shows your process of working and shares your knowledge is awesome, but I need to remember that blog posts should not be my biggest source of work.

This is a blog about programming, not time management. (except here, I guess)

9/10/17

Let's Make a Roguelike - Stats, Items and, Messages

Well, here's a new tutorial segment!

This one was pretty awful to write, mostly because I chose too broad of a topic. As a result, it's also quite a bit longer than most of the others (~14 pages, with a previous record of ~11). On the upside, I'm very nearly done here. Currently, I'm planning the remaining 3 segments to cover:
  1. AI and combat
  2. Generating artificial spaces (e.g. mazes, dungeons, buildings, etc.)
  3. Various remaining loose ends, like visibility and overall game structure
I didn't quite do item systems justice here, unfortunately. I seem to have missed dropping/equipping items in particular, although these actions should be fairly trivial to implement with the knowledge from the tutorial.
Since it looks like things are mostly on schedule despite last month's delays, I'm currently pegging the completion date as December 17th, 2017. This will be one full year after I restarted the series, minus a couple days to make it land on a Sunday.

Speaking of dates, this series will be 3 years old in a couple weeks. All I can say at this point is that I'm glad it's coming to a close. It's going to be a while before my next series, I have a few ideas but I want to put a lot of consideration into any future endeavors. However, I do have a one-off informative...thing that I'll be putting up on the tutorials page not too long after this series.

8/13/17

Update - Sorry Guys!

Hello everyone, I have some unfortunate news today:

For various political reasons, my shoulders have decided to let burn the fires of revolution, which would be entertaining if it wasn't so darn painful. It hurts in general, which makes it difficult to focus, and it also hurts extra-hard to type! As a result, I've decided to postpone everything by a full month to allow my body time to recover.

This means that dfgame is now slated to release at the end of September, the tutorial is likely to end in December, etc. I was planning on a little "looking back" post for this blog's 5th anniversary on the 20th, and I might still do that. It's a big date, and most of the work is reading, not writing. My right arm is ok, so I might also bust out my tablet and chance a few sketches. We'll see.

Ultimately, I'm extremely disappointed in myself. I took the first week off this month in an attempt to deal with the issue, but it's been over 2 weeks and I'm still out of commission. I apologize for the delays and such, and you'll probably hear from me again in 3-4 weeks or so.

7/30/17

Roundup, July 2017 - Rock & Roll

Another month has passed, and it's time for a new update video:

Additional Comments

In addition to these demos, I also made a few nice additions to DFGame's API. Since it's mostly a grab-bag of small additions, here's a list:
  • Predefined colors to use for rendering
  • Simplified main loop function
  • mesh_render can also bind mesh attributes, which had to be defined separately before
  • hashmaps can now be told to delete their contents when being destroyed
  • sprites can be told to delete their source when being destroyed
  • Window init now enables transparency and depth testing by default
  • Function to create a new 2D camera based on a window's dimensions
  • Added transformation macros for cameras, to simplify transform_FOO(camera_get_transform(c)) syntax to camera_FOO(c)
  • Added a simple version of "copyadd" to data structures, which measures and copies non-pointer values
  • Attempting to lerp int literals now uses float lerp, since that's what most reasonable people would expect
  • Added an "almost zero" macro for testing floats and doubles
Writing them all out as a list looks pretty impressive, but most of these additions are quick 5-minute changes. Still, it's good to add them in before release.

Goals

  • Time Left: 3-4 weeks
  • Logo Demo: Done
  • Comets Demo: 90%
  • Heightmap Demo: 60%
  • ??? Demo: Not Started
  • ??? Demo 2: Not Started
I have 2 more demos planned, and a little more work for the existing demos. This puts me at about halfway through, with a month or so remaining. This means I'll have to stay focused if I want to get all of that done, and possibly a game jam as well.

Some Code

As I mentioned in the video above, the Logo Demo was designed to present a simplified example of the init, cleanup, and looping code. To demonstrate that, here's the code:
    1 #include "camera.h"
    2 #include "color.h"
    3 #include "interpolate.h"
    4 #include "mainloop.h"
    5 #include "mesh.h"
    6 #include "paths.h"
    7 #include "shader_init.h"
    8 #include "texture_loader.h"
    9 #include "vector.h"
   10 #include "window.h"
   11 
   12 GLFWwindow* win;
   13 camera c_main;
   14 shader s_default;
   15 float  timer;
   16 gltex  t_logo;
   17 vec4   color;
   18 
   19 bool loop(mainloop l, float dt) {
   20     timer += dt;
   21     color.a = lerp(0.0f, 1.0f, timer) + lerp(0.0f, -1.0f, timer - 2.5);
   22 
   23     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   24 
   25     glUseProgram(s_default.id);
   26     shader_bind_uniform_name(s_default, "u_transform", mat4_mul(camera_get_vp(c_main), mat4_scale(mat4_ident, 400)));
   27     shader_bind_uniform_name(s_default, "u_color", color);
   28     shader_bind_uniform_texture_name(s_default, "u_texture", t_logo, GL_TEXTURE0);
   29     mesh_render(s_default, mesh_quad(), GL_TRIANGLES, "i_pos", VT_POSITION, "i_uv", VT_TEXTURE);
   30 
   31     glfwSwapBuffers(win);
   32     return !glfwWindowShouldClose(win) && timer < 4.0f;
   33 }
   34 
   35 int main() {
   36     win = window_new_default(1280, 720, "Logo Demo");
   37     init_base_resource_path(NULL);
   38     shaders_init();
   39 
   40     s_default  = shader_basic_tex_get();
   41     color      = color_white;
   42     c_main     = window_create_2d_camera(win);
   43     char* path = assets_path("logo.png", NULL);
   44     t_logo     = load_texture_gl(path);
   45     sfree(path);
   46 
   47     mainloop_create_run(loop);
   48 
   49     glDeleteTextures(1, &t_logo.handle);
   50     camera_free(c_main);
   51     shaders_cleanup();
   52     resource_path_free();
   53     window_free_final(win);
   54 
   55     return 0;
   56 }
There are still a few things that could be simplified here, but this is still much less code than would be required without DFGame. That's the primary goal of the framework, so I'm pretty happy so far!
With DFGame's release now imminent, and the upcoming 5-year anniversary of this blog, next month ought to be pretty exciting. Until then, keep on reading!

7/23/17

Let's Make a Roguelike - Example: The Swamp Cave

EDIT - Tutorial link was dead yesterday, sorry about that! The page is up now.

Sometimes, when I'm working on my website late at night with the lights off, I hear a voice coming from the Tutorials page:
"Huey, you cantankerous crayfish! You claimed that the roguelike tutorial wasn't on hiatus, but it's been five months since your last post! Fess up!"
...Nope. Definitely not on hiatus. I had to, err....pickle the ASCII. To make it green. That's my story, and I'm sticking to it.

Anyway, there's a new segment of the roguelike tutorial. You can read it here!

Being ever-so-slightly serious for a moment, I didn't (and still don't) really want to work on the tutorial. But, I also want to get it done. That means that I have to write up tutorial segments eventually, even if I'm not really inclined to do so. I also have some other tutorials that I'd like to start, but I'm unwilling to do so before this series is over.

This part serves as a sort of culmination to the last few. It shows how to take the techniques shown so far, and combine them to make a greater whole. My goal now is to introduce the rest of the basic techniques and mechanics commonly found in roguelikes, tie it all back together into a simple package, and mark the series as complete. I've mapped out the remainder of the tutorial at this point, and it looks like it'll be another 5 parts, including the conclusion. My goal for this series is now to be done with it before this series becomes a year old. If I can manage that, then I think I can happily call this 3rd attempt a success. You may notice that the code is quite a bit messier and uncommented. That's also a result of my rush to finish this series up. Once the series is over, I may go back to clean it up and make it more readable, but for now I'm more concerned with speed than quality.

7/16/17

Getting Organized - 6 - Tick Tock

Hello again, dear readers. Once again, it's time to make my life a little more productive. In my previous post, I grappled with my computer a little bit in order to bring my to-do list up every morning. This month, I'm going to work on my time management a little.

When I mentioned that I wanted a timer back in May, I said that I wanted "I'd like something that fits with everything else". I'm not entirely sure how many purely hypothetical beers I drank before writing that thought, but looking back it sounds more like the mutterings of the local town loony than anything important. I assure you, however, that this strange little collection of words will make sense if you read the following two paragraphs. So, y'know, you can just skip them if you're up for a challenge.

So, if you've been reading these posts religiously then you'll know that I use Awesome to manage my desktop. This gives me lots of control and customization options, but also makes using "traditional" desktop apps cumbersome at times. In this case, a quick Google search will find you endless pages of linux timer apps, coming in exactly two flavors:
  1. Pretty (useless) dialog windows that take up half your screen with fancy Large Text
  2. Icons in your system tray
Option 1 is unappealing in general, but also breaks with my window-management preferences. I could let one of these apps ignore Awesome's tiling rules, but then it would also block me from interacting with whatever's underneath it. Oh, and it's definitely not getting its own special desktop, so that's out. Option 2 would work nicely...if I had a system tray. I could add one and watch it fill with useless incongruous icons, or I could not do that and sleep well at night. But, there's another solution. Let's take a look at my bar for a moment:
Pretty much all of those nice little UI bits are custom. So, I can make my own "Option 2" that fits with the visual style of my desktop and does exactly what I want.

If you're still following along with my little scheme to make a timer but you're not sure it's quick or feasible, then I have some good news: It's done. I secretly went and did it this morning. Normally, I write and code together, but I just wasn't in the mood for 6 AM blogging. What was in the mood for was Runescape (???), and I didn't want to miss any deadlines in the process. I suppose you could say I was motivated by laziness, but I'm not about to complain!

The Implementation

The result of my mad morning keyboard mashing was just under 100 lines of Lua code. Most of that is UI boilerplate, but there's about 40 lines of actual logic in there that might interest someone, so let's give that a look:
   52 local timer = gears.timer {
   53     timeout   = 1,
   54     autostart = false,
   55     callback  = function()
   56         seconds_left = seconds_left - 1
   57         if seconds_left == 0 then
   58             awful.spawn({"mplayer", "/home/df458/assets/se/Notify01.wav"});
   59 
   60             local message = string.format("Your timer of %02d:%02d has ended", math.floor(seconds_total/3600), math.floor(seconds_total%3600/60))
   61             if seconds_total < 3600 then
   62                 message = string.format("Your timer of %02d:%02d has ended", math.floor(seconds_total/60), seconds_total%60)
   63             end
   64             naughty.notify {
   65                 title = "Time's up!",
   66                 text = message,
   67                 timeout = 300
   68             }
   69         elseif seconds_left < 0 then
   70             widget:set_visible(false)
   71             timer:stop()
   72         end
   73         progress:set_value(1 - (seconds_left / seconds_total))
   74         if seconds_left < 3600 then
   75             label:set_markup(string.format("%02d:%02d", math.floor(seconds_left/60), seconds_left%60))
   76         else
   77             label:set_markup(string.format("%02d:%02d", math.floor(seconds_left/3600), math.floor(seconds_left%3600/60)))
   78         end
   79     end
   80 }
   81 
   82 function activate_timer(seconds)
   83     seconds_left = seconds
   84     seconds_total = seconds
   85     widget:set_visible(true)
   86     progress:set_value(0)
   87     if seconds_left < 3600 then
   88         label:set_markup(string.format("%02d:%02d", math.floor(seconds_left/60), seconds_left%60))
   89     else
   90         label:set_markup(string.format("%02d:%02d", math.floor(seconds_left/3600), math.floor(seconds_left%3600/60)))
   91     end
   92     timer:start()
   93 end
As you can see, this little code block could probably use some cleaning. With that said, it works pretty well and demonstrates just how easy it is to make a timer. All I really do is set two numbers to how many seconds I want to wait, then subtract one from the 1st number every second. The second number isn't even necessary at all, but I use it to add a progress indicator. Beyond that, the rest is just making a nice text representation that switches between hour:minute to minute:second as necessary. When the timer's running, my little info are looks like this:
It's simple, sure, but it works quite well! Next time, I'll be wrapping up this series with some final touches to task management.

7/2/17

Roundup, June 2017 - Lost in another dimension

It's that time of the month again, and I've made great progress!

Additional Comments

In addition to what was mentioned in the video, I also went back and re-added joystick emulation to the input code, as well as adding a few minor features and fixes all around. Besides the lackluster demo, this has been one of the best months for development this year.

Goals

  • Time left: about 1 1/2 months
  • Application Module: Done 
  • Audio Module: Done
  • Core Module: Done
  • Gameplay Module: Done
  • Graphics Module: Done
  • Math Module: Done
  • Resource Module: Done
As I said in the video, and as is apparent from the list above, I'm just about finished with dfgame for the time being. If you've been following along, you've probably noticed that I quietly removed particles from the goal list. This is because particles are a bit of an unknown for me.

"But wait!" I hear you cry. "Didn't DFEngine have particles?" This is correct, but DFEngine's implementation was super basic and not very good. My standards for features, while not amazing, are definitely higher than they used to be. If I were to make particles now, I'd want to use the GPU or at least some form of SIMD to get good performance. I played around with GPU particles last summer, but I ultimately ran into a few issues that halted progress and moved on to other things. A decent particle implementation will take some research and effort, but I don't know how much so I'm putting it off for the sake of polish.

Some Bad News

The main goal of my "End of August" timeline was to use dfgame for an actual game jam entry. Unfortunately, I just found out that for the first time in 15 years, Ludum Dare is being held at the end of July. Why? I have absolutely no idea. I could theoretically still enter, since dfgame's release is now feature-complete. However, I would be sacrificing about 50% of my polish time to do so.

Instead, I'll just keep an eye on the itch.io game jams page and select one in the right general time period.

As for next month's posts...beats me, I forgot to plan anything. Whoops!

6/26/17

Happy birthday to Me!

First off, let me apologize quickly for missing my post deadline last weekend. I decided to take a second break this month in order to celebrate my birthday without the stress of writing another post. As much as I love working on this blog, it takes enough time and effort for me to want breaks here and there!

Anyhow, you can expect this month's roundup to land on Sunday at the usual time. I've made great progress, so I think it'll be a pretty good update.

6/11/17

Getting Organized - 5 - Some Awesome Work

When we last left off on my quest for good time management, I decided to share my pizza recipe instead of being productive. Clearly, I'm making good progress. Now then, it's time to do some actual programming.

Awesome!

No, that's not your cries of joy. Awesome is the Window Manager that I use on all of my machines nowadays. In addition to laying out my windows in a pleasing fashion, it also exposes a powerful lua API for customizing and scripting, well, everything. This includes the UI, allowing for some very in-depth customizations!

Last time, I made a list of tasks to complete:
  1. Automatically opening my wiki every morning
  2. A simple timer that fits with my workflow
  3. A way to create tasks remotely while at work
Today, I'm going to finish off the first task. Furthermore, Awesome is going to help me with that.

Hello, Wiki!

Originally, I said that opening my wiki in the morning would be "super-easy to do". I lied! I lied to everyone, even myself! And what a lie it was.

An Unexpected Snag

The easiest way for me to make programs start on launch is to add them to my xinitrc file. In this case, I actually can't do that. Because the terminal that I run vim in won't have its settings ready before my xinitrc finishes running. That means that if I use my xinitrc to bring up my wiki, the colors and fonts will be wrong and it'll have a horrifying scrollbar that looks like it crawled out of Windows 3.1.

Obviously, I don't want that. Awesome gives me the ability to run applications, so I can have it launch my wiki. Perfect, right? Wrong! To help debug scripts and configuration, Awesome provides a mechanism to restart it without closing anything. This is also great! However, this means that every time I restart Awesome it'll also open the wiki again. So, we have a conundrum.

The Solution

The second problem can be solved, but it'll take a few small additions. The goal here is to have Awesome run certain programs on startup, but only if it isn't restarting. To do that, I need to store some information across runs.

Conveniently, Awesome has an event that runs when it exits. Even better, that event tells you whether the exit is part of a restart or not! So, I simply write a value to a file based on whether Awesome is restarting or not. Then, Awesome can read the value when it starts and use it to make decisions. The result looks like this:
awesome.connect_signal("exit", function(restart)
    local lastrun = io.open("~/.config/awesome/lastrun", "w")
    if lastrun ~= nil then
        if restart then
            lastrun:write(0)
        else
            lastrun:write(1)
        end
        lastrun:close()
    end
end)

...

local lastrun = io.open("~/.config/awesome/lastrun", "r")
if lastrun ~= nil then
    local was_quit = lastrun:read("*n")
    if was_quit == 1 then
        for i,e in pairs(autostart_once) do
            awful.spawn(e)
        end
    end
    lastrun:close()
else
    for i,e in pairs(autostart_once) do
        awful.spawn(e)
    end
end

for i,e in pairs(autostart_each) do
    awful.spawn(e)
end

As you can see, it's actually pretty simple. Anything that I add to the autostart_once list will only start if Awesome shut down properly last time it ran. On the other hand, anything in the autostart_each list will run every time Awesome runs. This makes for a convenient solution that I can use as much as I want going forward.

So, that was a semi-complicated solution to a relatively simple problem. Come back next time for some tougher-but-more-straightforward scripting.

6/4/17

Roundup, May 2017 - Oh man I sure do hope the mosquitoes don't--

It took great courage and perseverance, but I finally drove back the mosquitoes that definitely ate all of last week's update. So, here it is:


Additional Comments

I had some difficulty capturing/rendering this video. Last time, I used glc for the video capture. However, glc's audio recorder is really buggy and doesn't work on my machine. It's also quite old, so I'm worried about relying on it too much. This time I made a recording with FFmpeg, but it's just a normal desktop capture so it's a bit slower than I'd like. Next time, I'll probably try to capture the video and audio separately. It might be annoying to line the two up in editing, but it will probably result in a higher-quality video.

The big gain from rewriting the audio system is that multiple audio players should now be able to play audio from the same source at the same time. This means that I don't have to reload a sound effect every time I want to use it, and instead I can easily load once and play hundreds of times. As you can guess, this is really useful for games where you could easily have a couple dozen objects that can make the same sound.

Goals

  • Time left: about 2 1/2 months
  • Application Module: Done 
  • Audio Module: 95%
  • Core Module: Done
  • Editor Module: Not Started
  • Gameplay Module: 80%
    • Missing joystick emulation for input
  • Graphics Module: 65%
    • Missing sprites
    • Missing text
    • Missing framebuffers
    • Missing particles
  • Math Module: Done
  • Resource Module: 65%
    • Missing sprite loading
    • Missing font loading
This month went a little slower than I'd hoped, and some of the code that I wrote feels a bit rushed. As a result, I'm going to need to do another quick pass on the audio and resource modules at some point, just to tighten them up a bit. That's not what I'm doing for June, however. I want to get the last couple essential features, sprites and text, done. This will happen as part of a greater attempt to finish off the graphics module as a whole. I don't expect to finish all of it this month, but it wouldn't surprise me too much if I could sneak framebuffer support in.

If all goes to plan as it has so far, I'll have over a month left over to clean up any loose ends and improve my workflow in preparation.

Next month's posts will feature lots of Linux shell scripting. Much like in May, I'll be kicking off next week with some more organization work.