4 Hugues Ross - Blog: 07/01/2017 - 08/01/2017
Hugues Ross

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!