4 Hugues Ross - Blog: 2015
Hugues Ross

12/31/15

2015: A Look Back, and the Road Ahead

Well, it has been quite a strange year!
In fact, strange might be an understatement.

I spent the first half of 2015 rewriting the entirety of my personal game engine from scratch, and the second half of 2015 deciding that maybe it's not worth keeping to begin with.

I announced a whole bunch of stuff, and while I made no real attempt to follow up on some of those things, I actually succeeded at some of them. Akradion has been done all semester, but I keep forgetting to test it, and Halberd's going strong. Speaking of which...

I went back to my roots! Halberd was this blog's first project, started 3 1/2 years ago. It feels like an eternity now, though.
Also, somewhere along the way, my small relaxed "Get into the college mindset" project turned into an epic quest to create the world's most absurdly powerful retro tile-based RPG engine, so that's something.
For those curious about how it's doing, have a courtesy link.

I spent a quarter of last year making a big update to Singularity, and then neglected to touch it at all this year. Just kidding, I started yesterday. That counts, right?

Speaking of not doing things, I wrote the first part of a tutorial last year, and wrote another part 5 days ago. My goal is to release a part every other Monday, and so far things are looking ok.

I also got a job! (Two, in fact) They were only part-time, but it's nice finally seeing a return on the skills I've been carefully honing for nearly a decade. Will any luck, I'll be able to find work after college. Either way, I'm not going anywhere; this blog has grown on me.

2015 is also the year that I started posting code on my programming blog, three years later...
    1 #include <stdio.h>
    2 
    3 int main(int argc, char* argv[]) {
    4     fprintf(stdout, "I\'ll award myself a gold star that says \'You tried\' on it.");
    5     return 1; // This is not a success
    6 }

I quietly released a piece of software that's been in development for a year or two. I'll finish the the post for it eventually.

So...

What's Next?

I've talked a lot about last year, but you might be wondering what I'm up to, besides Halberd. You know about my plans for the tutorial, and for Singularity, but what else do I have in store?

My next step will probably be ditching DFEngine. It's a really hard decision to make, honestly, because DFEngine has been around since before Sophomore year. Nonetheless, I don't see myself using it like I see myself using Halberd. I think this is the case for a few reasons.

Why Drop DFEngine?

DFEngine is primarily operated by writing xml files and lua scripts, which define the game's assets. Halberd was designed with an actual human user in mind from the start, so it's built entirely on top of an interactive GUI-based editor. The thing is, Halberd is still mostly xml-based. It just lets you fill forms and click buttons instead of painstakingly entering information with a text editor. It even has a play button, for instant feedback.

I can't really fix this problem. Not well, at least. DFEngine is C++, and I write my UI code in Vala, which is C-based. The two don't mesh well. I could write my UI code using gtkmm, the gtk C++ bindings, but that just leads to the next problem.

I don't really believe in Object-Oriented programming the way I did coming into college. I used to be a huge fan of C++, until this year when I finally started using C. Don't get me wrong, OO is perfect for solving a few specific problems, such as UI code. Of course, that last bit applies more to simpler OO languages, such as Vala and C#.

More often than not, I feel like OO tends to put you in a mindset where you have to make the perfect hierarchy, and you lose sight of your real purpose. It feels like a trap that wastes resources for code that is ostensibly easier to extend. From my experience, it's the opposite: I find it much easier to extend C than C++, and my code usually feels more concise and easier to read. I've been looking at Go recently, and I think they might have the right idea. I'll have to play with it in the future.

The Solution

Ultimately, DFEngine lacks the ease of use it needs to be good. I started the project because I wanted a framework for quickly getting started during game jams. I'm ending the project because I no longer do game jams, and that's just a little bit sad. I've rewritten DFEngine twice, but each time it has only marginally improved. It's time for a different approach.

Of course, making my game jam entries from scratch in C isn't all that doable, so what will I do instead?

When I refactored Halberd, I split the engine into 5 separate modules. 3 of them are compiled into static libraries, for the sake of flexibility. That's what really got me thinking: What if I just took all of this great, simple, useful code, and just made utility libraries with it? How convenient would that be?

I haven't tried it yet, but I already think I know the answer:
  • Want resource loading code? Here.
  • Want a hefty project file manager? Here.
  • Want a widget for selecting assets, with as-you-type searching? Right. Freaking. Here.
It's easy. It's convenient. Best of all, it's a standard. If I use a common set of libraries for my projects, most of my work disappears and I can focus on the details of each project. Better yet, I basically get a free head start on making editing tools.

One of my first goals this year will be to split some of the Halberd codebase into a separate collection of libraries. After that, I can see about getting back to my other game projects with a new set of tricks up my sleeve. For now though, Halberd and Singularity are my main concerns.

Oh, and here's a little gift for surviving my +3 Wall of Text:
A mockup of Singularity's new UI. It hasn't changed immensely, but there are a few cool new bits in there.

12/29/15

Let's Make a Roguelike - 2 - Beginning the Project

Now that we've discussed some of the prep work we need to actually set up and create our project. In this tutorial, we'll be setting up a title screen and starting menus. This project assumes that you've set up your work environment how you want to and made a fresh project, so if you haven't done that yet, then go do that now.

Drawing Text

Now, we're going to get into some actual code. We start by setting up NCurses:
    1 #include <curses.h>
    2 
    3 int main(int argc, char* argv[])
    4 {
    5     /* Start Curses
    6      *
    7      * clear()  clears the terminal, giving us a blank canvas to work with
    8      * noecho() prevents getch() calls from displaying the typed character
    9      * cbreak() ensures that typed input is received immediately by curses
   10     */
   11     initscr();
   12     clear();
   13     noecho();
   14     cbreak();
   15 
   16     /*
   17      * The program body will go here.
   18      */
   19 
   20     // End Curses
   21     endwin();
   22     return 0;
   23 }
If you try running this now, you won't see any output because all we're doing is setting up and shutting down. Let's fix that next.

A Centered Title

To start things off nice and easy, we're going to make a simple title screen. All it'll have for now is a line with the title and a line prompting you to press any key. Next week, we'll begin making things interactive, but for now let's stick to baby steps while we start out.

Terminal Size

Terminals come in all shapes and sizes nowadays. As a result, you'll want to be able to handle situations when you encounter a terminal with odd dimensions. While it's up to you how you handle different sizes, they can be broken into two main categories, resizable views and fixed-size views. Either way, it's recommended that you account for situations when the terminal is too small.
First, you need to determine the minimum size of your game, in characters. While there's no official standard, few if any terminals default to a size below 24 rows by 80 columns. This size is that of the VT100 terminal, which many emulators either default to or follow.

Note

Be aware that in this tutorial series, I will be referring to all coordinates/sizes in a rowxcolumn format. This means that the vertical/y-coordinate will be listed first. This notation is used by curses, and I'll be using it to try and stay consistent with the code.
It's up to you whether or not to support larger or smaller sizes, but I recommend keeping the minimum at or below 24x80.

Now, let's update the program to warn the user if their terminal is too small to use. The curses function getmaxyx() will let us do just that. This function takes in a handle to a curses window, as well as two integers for storage.
We haven't touched on windows yet, but you can use the stdscr variable as a replacement. stdscr represents the main window of the curses environment, which is created at the start and fills the entire terminal. getmaxyx(), as the name implies, gets the number of rows and columns in a curses window. Now, we can use these functions to test our terminal.
    3 #define MINIMUM_TERM_ROWS 24
    4 #define MINIMUM_TERM_COLS 80
  ... 
   23     // Test the resolution of of our terminal
   24     int rows, cols;
   25     getmaxyx(stdscr, rows, cols);
   26     if(rows < MINIMUM_TERM_ROWS || cols < MINIMUM_TERM_COLS) {
   27         endwin();
   28         fprintf(stderr, "Error: Your terminal is too small.\nThis application expects dimentions of at least %d rows by %d columns.\n", MINIMUM_TERM_ROWS, MINIMUM_TERM_COLS);
   29         return 1;
   30     }
With this, we can now rest easy knowing that the user won't be launching our game in too small of a terminal. We can handle changing our game based on the size later. For now, this will do.

Note

If you're planning to use a graphical curses implementation, like pdcurses with SDL, then changing resolutions is probably not a huge problem for you. Regardless, it may be good to implement the above in case you want a fallback version that runs in the terminal.

Printing Text

Let's finally get some text on the screen. I'm going to start by showing the code, then we'll go through it line-by-line to examine how it works.
   28     // Print the title, then wait for a button press before exiting
   29     mvaddstr(3, cols / 2, "Cool Game Title");
   30     mvaddstr(rows / 2, cols / 2, "Press any key to continue");
   31     getch();
On the first two lines, we call the function mvaddstr(). This function is actually a sort of shorthand. In curses, the move() function changes the cursor's position, and the addstr() function places a string at the cursor's current position.

As you work with curses, you'll find that a lot of functions have common prefixes that can be added to simplify your code. move() takes the row and column positions to move to as basic integers, and the mv prefix on a function adds these arguments to the start, allowing you to move the cursor then do something, all in one function call. Again, keep in mind that curses starts with the row number, or the y. Here, I use the rows/cols variables that we used to check our terminal above to center our text. It's always helpful to have the current (or expected, for static views) screen size in a variable for the purpose of placing elements, especially since it'll result in less breakage if you change your mind later.

So, what does getch() do here? getch() is one of the most basic tools at your disposal when working with curses. With getch(), you can check for a single keypress at any time, getting back an integer with the character code (if it was a character), or a const value representing some other key. By default, the function waits indefinitely for a keypress, effectively pausing until the user decides to enter a command, but there's a way to prevent this that I'll cover in a later tutorial. For now, we're using the getch() call to pause the application before we exit (This is also why I added a "press any key to continue" message).

At this point, if you've been following along, you'll have some text showing up on screen. Next time, we'll start looking at drawing more interesting things in our terminal, and play with color.

Next Steps

  1. Our centered text is slightly off-center. Can you figure out why? I'll provide an explanation (and solution) at the beginning of the next part.
  2. Take the text that you fixed in part 1, and create a function that draws any text that you pass in centered on your screen. Bonus points for proper error checking (What happens when your text is too long?) and the ability to specify the curses window.
  3. Delete the clear() call at the start. Do you notice something odd? Take a look at the documentation and try to figure out what happened.

Important Terms and Functions

Note

These sections will contain an overview of the new things that we covered in any given part. My hope is that it'll be a useful reference for following the next steps, although you may still need to refer to the API for more details.

Windows

  • initscr() Initializes curses.
  • endwin() Resets the terminal. It should be noted that endwin() is not necessarily final--you can continue using curses as long as you refresh the screen when you're done, making endwin() useful for temporary trips to the command line.
  • getmaxyx(WINDOW *win, int y, int x) Gets the size of a given window. Note that y and x shouldn't be passed by reference, because getmaxyx() is a macro.
  • stdscr The default curses window

Input

  • getch() Returns the next character of keyboard input. If echo is enabled, characters are printed. By default, getch() waits until input is given.
  • noecho() Disables echo, which is enabled by default. A corresponding call to echo() will re-enable echo.
  • cbreak() Enables cbreak, which prevents the terminal from buffering keyboard input. If cbreak is off, input won't be received by curses until a newline(\n) is added, probably from the enter key. A corresponding call to nocbreak() will disable cbreak.

Output

  • clear() Clears the current window.
  • addstr(const char *str) Draws a string at the cursor. The cursor is advanced to the end of the string.

Other

  • move(int y, int x) Moves the cursor to [y, x] in the current window.
  • mv- Prefix for some functions, mostly output functions. Moves the cursor to [y, x] before the function is called.

Final Code

Note

I probably won't always include this part, but I think it's helpful to include the full code that I wrote in a tutorial when I can. Some tutorials might not lend themselves as well to this, but I'll be providing Github links to the relevant commits otherwise, like this one.
    1 #include <curses.h>
    2 
    3 #define MINIMUM_TERM_ROWS 24
    4 #define MINIMUM_TERM_COLS 80
    5 
    6 int main(int argc, char* argv[])
    7 {
    8     /* Start Curses
    9      *
   10      * clear()  clears the terminal, giving us a blank canvas to work with
   11      * noecho() prevents getch() calls from displaying the typed character
   12      * cbreak() ensures that typed input is received immediately by curses
   13     */
   14     initscr();
   15     clear();
   16     noecho();
   17     cbreak();
   18 
   19     // Test the resolution of of our terminal
   20     int rows, cols;
   21     getmaxyx(stdscr, rows, cols);
   22     if(rows < MINIMUM_TERM_ROWS || cols < MINIMUM_TERM_COLS) {
   23         endwin();
   24         fprintf(stderr, "Error: Your terminal is too small.\nThis application expects dimentions of at least %d rows by %d columns.\n", MINIMUM_TERM_ROWS, MINIMUM_TERM_COLS);
   25         return 1;
   26     }
   27 
   28     // Print the title, then wait for a button press before exiting
   29     mvaddstr(3, cols / 2, "Cool Game Title");
   30     mvaddstr(rows / 2, cols / 2, "Press any key to continue");
   31     getch();
   32 
   33     // End Curses
   34     endwin();
   35     return 0;
   36 }

12/28/15

Let's make a Roguelike - 1 - Limits

Note

This is a reworked and updated version of a post from about a year ago. Since I've decided to try my hand at this again, and this time in a more organized manner, I felt is would be best to repost this with the necessary edits to catch any newer readers up.

In this new tutorial series, I'm going to be walking you through the process of making a roguelike game from start to finish, with text-based graphics. This tutorial will be written alongside the development of my first non-7drl roguelike project, and all code will be available on Github around the time of posting, with an appropriately-named commit.
This series expects at least basic knowledge of the C programming language, but you can probably follow along in C++ as well, though you may need to adapt some things later on to take advantage of its object-oriented capabilities. If you're new to programming, don't fret--there are plenty of good learning resources online for C, and I'll try to keep my explanations fairly simple.
Lastly, while I'm hoping to teach you something, if you think I've made a mistake or need to be informed of something, then by all means email me or leave a comment below.

Warning

The following tutorial segment is entirely preparatory. There is no code here, only reading. I think this information is important, but if you don't want to read it then just get through the final section. The next installment will be a bit more exciting.

When you start any coding project, it's especially important to know the limitations of your platform. If you don't, you're liable to cause yourself all kinds of problems later down the line. This can be especially true when you work with something as 'different' as your average terminal. Terminals can be quite limiting environments compared to your average graphical medium. Let's examine some of these limits:

Lines

The first of limiting factor relates to how things are displayed in a terminal interface. Generally, text is added line-by-line to the window, and there's no apparent way to alter this. It is possible to do so, however. Most (all?) terminals provide a set of special escape sequences that allow you to perform various functions, like moving the cursor, changing text color, and so on. You can actually use these yourself if you know what they are, but I wouldn't recommend it. Instead, the best solution is to use a library.
I'm going to be using ncurses, an implementation of the curses spec. You should be fine with most curses implementations, however. if you're on Windows, or you want your game to be playable outside of a terminal, I would recommend pdcurses. It does a few odd things, but it's common and reliable.

Note

There seems to be an even better version of pdcurses for Windows, available here. I would give it a proper recommendation, but I haven't tried using it myself.

Draw Speed

ncurses, wonderful as it is, is a bit slow compared to modern hardware-accelerated graphics libraries. It doesn't take long to display things, but if you expect to have a gorgeous 1080p 60fps action game, then you are in for a major letdown. This is probably why most command-line games are either designed to refresh less than once per second, or don't update unless they absolutely must. In fact, if you're making a turn-based game you may be better off forgetting regular draws altogether.
You'll probably want output to be more reactive, only redrawing when things actually change. If you do this, the game will never feel sluggish, and it will use fewer system resources too. This means forgoing most animations, but it also makes things much simpler to work with. Not only that, it may also let you get away with complex calculations, given that you don't have to worry about frame time.

Color

Next, we have a tougher issue. Depending on what sort of terminal or terminal emulator is being run, you're likely to run into a number of color configurations. Most terminals fall under one of these categories regarding color:
  1. Black and White Monochrome terminals aren't as common as they used to be, but they still exist here and there.
  2. 16 colors As far as I'm aware, most color-supporting terminals have the same general default 16 colors. They are split into two sets, 8 normal and 8 bright. The colors are black, red, green, yellow, blue, magenta, cyan, and white. Generally, this makes the first 16 colors set for a terminal easy to guess.
  3. 256 colors I believe this trend started with xterm, but nowadays this is fairly common, albeit less so than the basic 16.
  4. 24-bit color support These are rare, but they definitely exist. 24-bit color (To avoid any confusion, I'm talking about 3 8-bit color channels, rather than 3 24-bit channels) is equivalent to what you can normally draw to a screen (ignoring alpha). It looks like most curses implementations don't currently support this feature, so I won't be covering it.
As you can see, that's an incredibly wide range. Terminals will support fewer colors than their maximum, so most games and applications generally seem to target 2 or 16-color terminals.
Another potential feature is palette swapping. While the default set of colors is fairly predictable, many terminals allow you to change them, giving you more choices to work with if you're careful about managing your colors. However, just like every other feature it isn't guaranteed. Palette swapping can get very messy, but can have a great payoff if you have a solid understanding of it. If you don't believe me, look at these demos.
Depending on how many optional graphical features you want to add, the complexity can ramp up significantly. I've decided to try and cover whatever a given terminal throws at me, but I'd recommend that a less experienced coder try to stick to simpler configurations. A good easy setup would be to try 16 color support, and maybe add support for other color setups later down the line.
One upside is that these all have one thing in common: Colors are defined and used in foreground/background pairs, giving you the opportunity to draw 2 different colors per space.

Text

The final, most obvious limitation is the medium: In the terminal, everything is text! In fact, it's usually just ASCII. Sometimes other fonts and character sets can be supported, but that isn't necessarily guaranteed. Depending on what is being represented there are a number of methods for displaying things. If you want to draw something large and potentially elaborate, then ASCII art may be the right choice. However, if you want to draw a lot of smaller things, then you may want to only give them one character each, based on what they are. Players are often represented with an @ sign, a dragon could be an uppercase D, and so on. You aren't restricted to using one form of depiction in a game, but you need to keep them consistent.

Now that we've examined our target platform, we can really start. That will have to wait until the tomorrow's installment, though. For now, let me thank you for reading through all of this. I promise we'll start coding soon!

Next Steps:

Note

Since there will be a short wait between segments, I plan on ending each one with 'homework'. These tasks are designed to build off of whatever I discussed in the tutorial, and if they involve coding I'll usually address them at the start of the next post.
  1. Come up with an idea for a game. If you need inspiration, take a look at Roguetemple for some ideas.

  2. Decide what sort of terminal features you'll be targeting.

  3. Get set up. Make sure you have a decent environment for C programming, and a curses implementation. Ensure that a test program will compile and run properly. While you're at it, make sure that the terminal or platform that you use matches your target(s). If you have multiple targets, you need to make sure that you can test for all of them.

  4. Look over an ASCII table, and think about how to best depict the elements of your game. If you plan on using Unicode, browse the charts a bit.

  5. If you don't already know how, learn to use a version control system. I recommend and will be using Git, but plenty of options exist. This isn't required, but it will really help.

12/21/15

Update: My Domain

If you're reading this, you may have noticed already--I've given the blog a domain of its own, huguesross.net. If we're being perfectly honest here, I should have done this a long time ago, it was quite cheap.

Anyway, I've begun working on a small personal site that will connect to this blog, but I need to finish it before hooking it up to the domain. I also need to figure out how I want the blog to look, which may result in me switching back from dynamic theming again.

I'm still figuring out how I want all of my things to be organized, so please bear with me for the moment!

12/6/15

Halberd Update 3: Scaffolding

It has been a long time since the last update post, and I've been quite busy!
I've been wanting to write this post for a while, but kept thinking "one more feature", and now 3 months have passed and I still don't have a post, so I'm going to just do a general writeup of what I've been up to. Hopefully I can get back into the posting rhythm by getting this out of the way.

Refactoring

 I realize that not everyone is as excited by the prospect of refactoring as I am, but it has really done this project a lot of good. The main focus of my latest batch of refactoring was to make Halberd's codebase more modular. Before, I had a single set of code that was sort-of broken up, but not well. Now, I've broken things up into 5 discrete segments, each with a very specific purpose. They can be arranged in a hierarchy as follows:
  • Engine
    • Editor backend (The base editor functionality, with no user interface)
    • Game backend (The base game functionality, with specifics like context creation and hardware input handling missing)
    • Common library (A library containing all the code that's shared between both the editor and the game)
  • Interface
    • Editor interface (The actual editor front-end)
    • Game interface (The executable that the user runs)
The code is still all in C, with the exception of the editor interface which is written in Vala. There's a good reason, of course...

UI Overhaul

...And that reason is the UI.
I tried writing a GTK-based UI in C, and although it worked it was annoying and clunky to write. I decided that since Vala translates to GObject C anyway, it would be easier just to write bindings for the backends than to continue working on this specific part in C.
The startup dialog and project creation workflow are probably the most finished parts, so far.
So far, things have been going well. I've made GTK UIs with Vala a few times now, but this time I'm trying to pay more attention to the details and make things look just a tiny bit nicer.
At this point, the majority of the UI elements above function as intended.
The editor interface is starting to look more like an actual game engine, which is great! This is my first time making an editor with this sort of scope, but I'm pretty happy with my progress so far.

Projects 

Apart from the UI, the other main improvement to the game is the addition of projects. The engine now has actual projects that separate different games being made. This is useful for a lot of obvious reasons, so I won't go too far into it. Overall, though, this will make things much easier for me once I actually start making games with it.

Up Ahead

Even with all that I've done, there's always plenty more. My next goals are as follows, in order:
  • Finish project support, at least as far as file handling goes. This means creating, importing, renaming, moving, opening, and deleting assets from the bottom pane. You can currently open and import these files, but that's about it. I'd also like to get the search feature working.
  • Re-add support for tilesets. Right now, the editor is using garbage data left behind by the graphics card as a temporary stopgap, but I want to be able to use actual tilesets again, as well as tie tilesets to specific maps.
  • Start adding more game/engine features. The only thing you can really do right now is walk around (You can interact with NPCs, but they can't be spawned in yet), and I have quite a bit that needs adding before I can call this a real RPG engine.

12/1/15

Capstone - A Postmortem for Dungeon Restocker

It has been 2 weeks since my last update post, and the verdict is in: Dungeon Restocker isn't going forward to next semester. This is being posted later than expected, because it has taken a long time to write and consider. To be perfectly honest, I'm a bit relieved. Despite the sunny disposition of most of my posts, this project has been fraught with issues, and I'm not sure I could take a second semester of this.

The Project

I think I'm going to kick things off with our meeting schedule. I've always been a supporter of short, infrequent meetings that serve to make sure that the team is still on track. Sadly, this was not the case here.
Our meeting schedule consisted of in-person meetings on Tuesdays, Wednesdays, Fridays, and Sundays every week. Each individual meeting lasted between 1 1/2 and 2 hours, resulting in the team spending about 6 hours a week on meetings. Note that while we did meet on Wednesdays in class, this was not the Official Wednesday Meeting. That one was about 5 hours later. By the way, I live about 15-45 minutes from campus, so I spent an additional 3 hours a week in transit because of these meetings, tallying up to a personal total of 9 hours a week spent on these things (although, only 6 were logged).
On the day that our team was cut, we spent almost 2 hours in an online meeting, in which we made the decision to have a meeting the next day in order to make the actual decisions we wanted to. This meeting lasted 3 1/2 hours. That's right, we spent 5 1/2 hours over the course of 2 days making decisions that didn't actually matter. I think this little anecdote best describes our team's decision-making process.

Next I should probably address the game itself. Dungeon Restocker's design underwent numerous changes as we worked on it, and I don't think all of them were good. I think the main problem with the design can be summed up simply: There are two games in this concept that oppose each other. My view of how the game ought to function differed from the rest of the team, and I had difficulty seeing the value in their concept. To some degree, this is my own problem, but I'll try to address each evenhandedly so that you can decide for yourself which direction is more engaging.

Concept 1

The team's concept is that of a slow, methodical game. The player acts as a sort of hidden caretaker for the Hero, taking time to prepare the 'perfect experience', and then watching and waiting as the hero goes through it. An infinite number of heroes pass through the dungeon, but there's a long break between the exit of one and the arrival of the next. To end the stage, the player must complete certain objectives, usually making the heroes do a cumulative X of Y (e.g. loot 20 chests, kill 10 monsters, etc). Hero emotion is treated more vaguely, instead relaying various needs to the player (This hero wants loot! This hero wants to fight things!). Making heroes happy is a secondary objective, which rewards the player with resources.

Concept 2

My concept is a fast-paced, frantic juggling act. The player must constantly sneak around behind the hero's back, resetting traps, closing doors, and refilling chests without being noticed. A limited number of heroes enter the dungeon at timed intervals, such that in a perfect game the previous hero exits just as the next enters. To be successful, the player must prepare while a hero is exploring, while making sure that the current hero doesn't start messing with the old preparations. Hero emotions are given freely, along with the addition of a suspicion/confusion meter that fills if things are out of place. Screw up a hero too much, and they'll start moving and acting more erratically, trashing your dungeon, and ultimately leaving. On the way out, they'll confuse the new arrivals, resulting in a entertaining spiral of destruction where a loss is its' own reward (This is admittedly inspired by the classic Dwarf Fortess tantrum spiral). Making the heroes happy is a secondary objective, but is necessary to keep the show running smoothly.

Who's right? Beats me, but our current concept (closer to 1) was unable to properly convey the hero's needs and emotions, which is what ultimately resulted in our failure.
As a gamer, I find concepts like #2 to be more fun and engaging (Hence the chaos that was Sports Game), but it's entirely possible that the rest of my team was correct here. The main thing that bothers me is that I felt like I was left out of the decision-making process. I could speak, but since the rest of my team had all silently agreed on #1, my input would never be used or even acknowledged.

The Team

 I'm just going to go down the list when talking about my team. Note that I refuse to name any  names here--My teachers will know them already, and I see no reason to call anyone out publicly for anything they did or didn't do.

I should also stress that while I may come off as being rather negative, I really do like these people. Many of them had to deal with external issues, which affected their work, and I don't think they were able to give their all as a result.

Producer

My producer is the easiest to criticize here. On a 4-person team with 504 hours logged, he has logged 50, and never reached the weekly minimum hours on even a single week. He was absent from the majority of our meetings, and pretty much never did anything apart from the occasional piece of documentation. I understand that he was having issues with other classes and his job, but logging 10% of a 4-person team's hours is rather unacceptable.
I think a team can live or die by it's producer, and this one certainly made things difficult for us.

Programmer

If I had to pick phrase to describe my counterpart on this project, it would have to be "too little, too late". He did good work, but it was always a couple of days later than I expected to see it, and less complete than I'd hoped. If that was all, I wouldn't mind, but he did a rather poor job of communicating in general.
He was prone to disappearing for days at a time, without any warning, and failing to respond to any communications. One time he lost his phone, and inexplicably wouldn't just check the team Slack on his computer like I did for the entire semester. Another time, he was having family issues right before the day of a major presentation, and failed to even send a text (he had his phone this time) informing us of his absence. Instead, we were forced to present with him effectively MIA, only to find out where he'd been that evening.

Designer

 I'm somewhat torn about our designer, because most of the issues I've had with him relate more to the way he acts, and it's hard for me to tell if what he's doing is intentional or just a simple miscommunication. If we had a more active producer, they probably would have had plenty of opportunities to mediate and 'translate' for us, but as it stands I've just put up with his behavior and tried to ignore anything that feels odd or out of place.
Another reading of his actions, the one that I've been considering more lately, is that he simply takes input and criticism poorly. Every time I try to suggest something or point out a potential stumbling block, he immediately gets to work ripping apart what I just said or otherwise attacking my proposals. I initially figured it might have to do with my point above about there being 2 opposing designs, but then I realized that he'd been doing this since long before we decided to go with Dungeon Restocker in the first place. I might even be as bold as to suggest that he's been doing this from the very beginning.
I don't think it's appropriate to discuss any specific instances of this, given that this is such a personal thing and I'm not even sure if he was doing this on purpose, but I'm prepared to give specific examples if asked.

The other issue, which I will go into more detail with, pertains to this old post, or at least the aftermath of it. After superseding me as the team's de facto artist, he proceeded to achieve...nothing. No assets, no concepts, and no documentation. Over the course of almost a month, he modeled and rigged the character base. He finished it a day or two before our final presentation (with no animation), and it never made it into the game. I would be more understanding, but the last time I checked he'd put in close to 50 hours on it. Those 50 hours could've been much better spent, given the state of our game, not to mention that I found out later that he'd never done this before. What this means is that, having made fully rigged and animated humanoid models before, I would've been a significantly better choice for team artist, at least in this instance. I'm over it at this point, but I wasn't happy finding that out at the time. Worse yet, he also proceeded to completely ignore the standards that I set in our art bible when designing our proper level, but also failed to alter any of our art documentation in the process. Rather than talk to the team and make changes to the art direction, he simply chose to ignore it.
At the time this all bothered me quite a bit, given how abruptly and confidently he took on the position.

Me

I'm certainly far from blameless. For instance, most of the issues that I've had with our designer and other programmer are caused by my own perception, and it's quite possible that the others disagree. I also held on to my beliefs about what was best for the game, despite the fact that my team felt otherwise. All of these factors made it difficult for me to get excited about the project. I put in exactly the amount of effort I needed for a decent grade, and no more, because I any passion I had was suppressed by the situation I was in.

Even now, I feel like I'm betraying my team by writing this, but I need to get these feelings off of my chest once and for all. I can only hope that the others felt the same, because I'm not sure I could face them if they read this.

Conclusion

After reading this post over, I really don't know what to think. This is certainly the worst, most negative and venom-filled postmortem that I've ever written, and I don't know if it should be. A few times this semester, I considered the possibility that I might be the problem with this team. Either way, I hope this little insight into a failed project is useful; I think I've learned quite a bit from this myself. Hopefully, next semester will be better. I've found a team that wants me on board, and with any luck that'll work out nicely.

11/16/15

Capstone Update 9: "Who's that handsome fellow?"

We failed our challenge attempt last week, but that's ok. We got quite a bit of good feedback from the attempt, and have been hard at work making sure that everything works nicely. With any luck, our next and final attempt will go much better!

This week, I mostly made a bunch of small boring changes, but I also took out most of my todo list of 'big' items as well. The most interesting thing I did was laying the groundwork for multi-hero maps, something that we've been wanting for a while. You may be surprised to hear this, but the simple inclusion of one or two extra heroes actually increases the game's depth substantially.

When you have a single hero present, the game is fairly straightforward. Make sure that the chests have loot and each room has an enemy or two, and then you're golden. You can go hide in a backstage room and wait for the level to end, if you'd like. When you know that #2's on the way, however, you start to run into an interesting problem. Not only do you need to 'restock' in the wake of the previous hero (Without getting caught), you also need to make sure that the previous hero doesn't start touching the freshly placed items and enemies. On top of that, you know that there's a timer counting down until a second hero shows up, making sneaking around even tougher. My other big addition this week was finishing doors off, so now you also have to tail your hero to catch the door on their way out. Doors can also provide cover, in case you suddenly feel the need to become invisible.

This semester is coming to a close, but we still have about a week's worth of dev time left before the cut, so I have one last addition to make: Frustration. Normally, frustration is something that you should avoid in games, but ours is for heroes only.

Imagine, for a moment, that you are a valiant warrior entering a Completely Ordinary and Totally Legit Dungeon Seriously of Course it's Real Why Would You Even Ask, and you begin to explore. In your travels, you come across a door that's locked up tight. You keep searching, in hopes that a key will turn up somewhere. You search, and search, until you come to a startling conclusion: You've been everywhere except past the door, and there's definitely no key. "That can't be right!", you exclaim, and begin frantically running back and searching all of the old rooms, but there's nothing. Also, there's this weird guy that looks exactly like you and this other dude who keeps darting around corners and giggling. It's complicated.

At this point, I'd be getting pretty ticked off. The above blurb is an embellished description of how I want to see 'stuck' heroes act. When the hero cannot progress at all, they'll start to randomly wander while slowly picking up the pace. A frustration meter will begin filling up, and once it's full their happiness meter will begin to rapidly drain. Once that's over, they'll pack up and head back the way they came, right out of the dungeon.

What happens if you don't let them out? Do they start trashing the place? Who knows. I think that question is best left for another time.

11/9/15

Capstone Update 8: A real adventure

Note: If you somehow managed to get here in a mad search for information on writing EQS Tests in Unreal 4, there's a complete sample towards the bottom of the page.

My last post was a bit of a downer, but worry not! I have yet another dense AI post ready this time around. Today, I'm going to discuss how I'm making the Hero AI more intelligent and interesting to deal with.

The Problem

After a recent round of testing, our team identified a problem: The Hero in our game was predictable to the point of being boring. At the time, the Hero AI would follow a set path to the level exit, only leaving the path to kill enemies and grab loot. No matter where he ended up, and where the player led them, the Hero would always just make a beeline for the end of the level.
Players didn't like this, because it made the Hero feel very robotic. We wanted our Hero to be more interesting, so we decided to try and make the Hero explore levels properly. However, we had a number of smaller issues to work past first:
  1. There is no easy way, to my knowledge, to store and keep track of where an AI actor has been in Unreal. There were lots of little "half solutions" proposed, such as making the Hero spawn zones that affected navigation periodically. None of these ideas really seemed great, though.
  2. As much as we wanted the Hero to be more independent, we also still wanted some level of control over them. The game wouldn't be very fun if the player had no idea where the hero was going, after all!

The Solution

We made several changes to the game to make our idea work. First off, we've decided to move back to a more modular way of building levels. We originally planned to build our levels out of pre-made rooms and corridors, but started moving to building levels out of smaller tile objects. However, if we make the rooms ahead of time then it's easier for us to use them as targets for the Hero.

In addition, I re-purposed the path node objects in our game. These nodes were used to make the hero move to the exit without hugging walls and corners, but I've given them a new function using our new 'Point of Interest' component. This component has 2 main uses: To give the Hero a list of places to explore, and to keep track of where the Hero has been. Path nodes have a trigger volume that marks the point of interest as visited once the Hero enters it. The useful part of this is that even if the hero just passes by the node on the way to another, the hero still 'knows' that it has been there already.

With a setup like this, the level only needs nodes near 'things', such as intersections, rooms, and other important objects, rather than having nodes lying around everywhere. As an additional safeguard, the Hero has a case to path directly to the level exit if it runs out of valid nodes.
The basic level geometry and pathing nodes of our test level.

Handling Distractions

So now we have a method of making the Hero wander around our level without doubling back too much. With this alone, though, the Hero won't do anything but walk around. We want to keep the Hero's current method of dealing with interesting things (that is, walking to them and dealing with them in a context-sensitive manner), but we also want to avoid the main problem: If the Hero picks a new target to walk to, it'll overwrite and erase the old one. To get around this, I broke the blackboard entry controlling the Hero's movement in two: a short-term target for 'distractions' like above, and a long-term target based on the Hero's goal of exploration. As long as the Hero's short-term target is set, the Hero will deal with that first. Needless to say, this all took a while to set up nicely. Here's a screenshot of the Hero's new behaviour tree:
The scary thing is that this will be growing soon...

Coolness

At this point,  we have a much smarter Hero than we started with. The only problem is that now that is so much more independent, we have no goods way to influence its decisions.
That's where the new coolness system comes in. Every Point of Interest on the map has a custom 'coolness' value that our designer can set. This value influences the POI's final score in our EQS test, which probably sounds like a huge load of gobbledygook if you've never done AI in Unreal before. Simply put, it's a heuristic that affects which targets the Hero is likely to select first when exploring.
To actually make this work, we needed to write a custom EQS test to use our coolness values. However, it turns out that there's a small problem with that:

To my knowledge, no one has made any resources on how to actually do it.

Ultimately, I ended up referring to the Unreal Engine source code to make our custom test, and that worked out alright. Still, to save any future coders who might find this the hassle, here is the entirety of our coolness EQS test (This test targets Unreal Engine 4.9.2, so keep that in mind if you're using an older/newer version):

NodeCoolnessTest.h:
    1 // Fill out your copyright notice in the Description page of Project Settings.
    2 
    3 #pragma once
    4 
    5 #include "EnvironmentQuery/EnvQueryTest.h"
    6 #include "NodeCoolnessTest.generated.h"
    7 
    8 UCLASS()
    9 class DUNGEONRESTOCKER_API UNodeCoolnessTest : public UEnvQueryTest
   10 {
   11     // Don't forget your constructor! (I did.)
   12  GENERATED_BODY()
   13     UNodeCoolnessTest(const FObjectInitializer& ObjectInitializer);
   14 
   15  virtual void RunTest(FEnvQueryInstance& QueryInstance) const override;
   16 
   17     // A property like this one will appear in the EQS editor's side pane
   18  UPROPERTY(EditDefaultsOnly)
   19  float MinCoolnessMod = 0.5f;
   20 };
NodeCoolnessTest.cpp:
    1 // Fill out your copyright notice in the Description page of Project Settings.
    2 
    3 #include "DungeonRestocker.h"
    4 #include "NodeCoolnessTest.h"
    5 #include "PoinOfInterestBase.h"
    6 #include "EnvironmentQuery/Items/EnvQueryItemType_ActorBase.h"
    7 
    8 UNodeCoolnessTest::UNodeCoolnessTest(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
    9 {
   10     // This line is important, because it determines what your test actually
   11     // takes as input. Without it, your test will never run.
   12     ValidItemType = UEnvQueryItemType_ActorBase::StaticClass();
   13 }
   14 
   15 // This function is the actual test itself
   16 void UNodeCoolnessTest::RunTest(FEnvQueryInstance& QueryInstance) const
   17 {
   18     // min/max code borrowed from the ue4 source. These return the thresholds
   19     // set in the EQS editor
   20     FloatValueMin.BindData(QueryInstance.Owner.Get(), QueryInstance.QueryID);
   21  float MinThresholdValue = FloatValueMin.GetValue();
   22  FloatValueMax.BindData(QueryInstance.Owner.Get(), QueryInstance.QueryID);
   23  float MaxThresholdValue = FloatValueMax.GetValue();
   24 
   25     // This for loop is ytour friend. It iterates through all of the objects
   26     // returned by the Evironment Query
   27     for (FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It)
   28     {
   29 
   30         UPoinOfInterestBase* cmp;
   31         
   32         // This is how you retrieve an AActor, but you can do the same for
   33         // other types of objects.
   34         AActor* act = QueryInstance.GetItemAsActor(It.GetIndex());
   35         if(act) {
   36             cmp = act->FindComponentByClass<UPoinOfInterestBase>();
   37             if(cmp) {
   38                 // This is how you actually score your objects.
   39                 // The 3rd argument should be replaced with any float value
   40                 // you have for scoring.
   41     It.SetScore(TestPurpose, FilterType, FMath::RandRange(cmp->CoolnessFactor * MinCoolnessMod, cmp->CoolnessFactor), MinThresholdValue, MaxThresholdValue);
   42             }
   43         }
   44     }
   45 }

What's Next?

This is a great start, but there's still plenty to be done before Our Beloved Hero becomes smart enough to be a really fun and challenging opponent. My first goal, which I've begun, is making the Hero smart enough to solve basic puzzle-like challenges. I'm working on getting it to grab keys to open doors, which will probably evolve into switch puzzles and the like later.
My other main issue with the Hero's new AI is that it still can't be guided by the player. You can put down a breadcrumb trail of items and enemies, and the Hero will follow it, but then it'll just turn around and go back to what it was doing. You can't lead it into a certain branch of the dungeon, then double back while it's distracted to fill out the rest, which I think would add a lot of fun to the game and help combat the problem of not knowing where it's headed.

Either way, I have a lot of work ahead of me!

11/1/15

Capstone Update 7: A Few Grains of Salt in an Overwise Perfectly Decent Milkshake

I have not discussed it on this blog, but I have been responsible for the vast majority of this game's art and art direction. So far, I've produced all of the art documentation for both Sports Game and Dungeon Restocker, including the artist statements and art bible, the the latter of which contains all of the guidelines and details of the art style the game will be taking. Because our team had no artist, I've stepped up to fulfill all of the project's art needs.

It is for this very reason that I feel a little bummed out right now. In what feels like just overnight, I have been rather casually swatted out of my position as artist in favor of my designer. I don't blame anyone for this, nor do I think this was particularly intentional. However, I still can't help but feel a bit used, after defining the game's art style. It's a weird situation all around.

I should stress again that I'm not placing blame or trying to stir up any issues. I know full well why this happened, and it makes sense. Now that Mike has gone and finished the major design work for the moment, he sees an opportunity to keep being useful while also increasing the amount of work being done to implement his design. In that sense, it's a perfectly logical move. It's also not the first time this has happened. I made a similar switch last year as well. The reason I felt better then, though, is that the designer in question was a talented artist with a charming and distinct style, whereas my designer honestly doesn't seem much better or worse than I am.

What am I going to do about it?

Absolutely nothing.
I'm going to go back to programming, and work more on implementing the game's core systems. I have other projects that I can do art for, and I have no intention of creating any unnecessary drama over a move like this. Whoever does our art now is probably getting replaced if/when we go forward to next semester anyway, so I'd be out soon either way.

It's still a little bit sad, though.

10/27/15

Capstone Update 6: Challenge 1

It has been far too long since my last Capstone post, and I left things on a bit of a cliffhanger too! Thankfully, we passed Stage 1 last week. This next stage, known as the 'Deep Dive', is mostly about a mix of research and fleshing out the gameplay from Stage 1. I'm going to take this post to focus more on the latter, because I haven't shown off this demo yet.

The Restocker Demo

When I made my last post, the restocker demo was nothing more than an idea. Since then, we've made huge strides developing it into an actual game.

Our Beloved Hero

Making AI for our game has been quite the learning experience. Currently, I find that the one thing that UE4 really lacks is good tutorials. The current tutorials that exist are all right, but they lack a certain depth and level of detail that I'd like to see. I think the situation will improve with time, but for now we've been figuring out a lot through trial and error.

With that said, we do have a nice base to build on.
The hero has a basic but effective loop that it follows. Once every 1/2 second:
  1. The hero checks through all the objects that it cares about (The restocker, the enemies, and the items), and removes everything that it can't see.
  2. If the list still has objects in it, choose the closest object to target.
  3. Otherwise, choose the next node on the path to the level exit.
Between these searches, the hero walks towards its' current target. By making all of the hero's interactions collision-based, it results in an easy to make system where the hero interacts with the items the player places (you can even lead it around) without ever getting stuck or lost.

Right now we're aiming for another challenge tomorrow, although it's hard to say whether or not we'll be completely ready by then.

10/13/15

Capstone Update 5: The Great Culling

The deed is done! After weeks of discussions and back-and-forth, we have decided on our final prototype. This post is a bit late because there hasn't been much to write about apart from this decision.

The Options

We made 4 prototypes for stage 1:
  1. Dungeon Restocker, a game about going into old dungeons and restocking the chests/resetting the traps just ahead of the heroes.
  2. Rowdy Crowdy, A rhythm game where you have to balance conducting an orchestra with dealing with a rowdy crowd.
  3. Corn Maze, a puzzle game in a corn maze, with a focus on perspective puzzles.
  4. Sports Game, a party game where you play soccer but with shifting mechanics. (You can read more about this one here: 1 2)

The Decision

This was a very difficult decision for us to make, and we're quite a ways behind everyone else as a result. Rowdy Crowdy was the first to go, because no one had much interest in the game.
In a surprising turn of events, Sports Game was the next to follow! This actually makes a lot of sense if you think about it the way we did, however. We spent a while together figuring out what each team member wanted to get out of this class, and the general consensus was that we wanted something that could challenge us and (hopefully) make it through to next semester. Sports game is certainly too simple to accomplish the former. In addition, if you've been at Champlain for a while then you'll know that every year there's that one Capstone game that goes through. It's a quirky team sports game involving one or more balls. This happens just about every year. We figure that the teachers are sick and tired of the genre, and thus Sports Game would be at a serious disadvantage. On top of that, the design professors tend to be rather... touchy about random elements in games. These factors together make Sports game an unappealing choice for us to continue with.
The last two, Dungeon Restocker and Corn Maze, have been butting heads for well over a week now. It was only last night that we reached a final decision on what to do. To explain what exactly happened, we need to look at the pros and cons of each:

Dungeon Restocker

Pros
  • Plenty for everyone to do
  • Fun idea
  • Clear design direction
 Cons
  • Practically no prototype
  • Built on AI (In our programming disciplinary review, prof. Lawson was not particularly worried about this, but we'll see how this goes.)
  • Practically nonexistent tilemap support in all major engines

Corn Maze

Pros
  • Tested well
  • Interesting design
Cons
  • Almost nothing for the programmers to do
  • MASSIVE amounts of design work (With a 1 designer, 2 programmer team setup)
  • Somewhat murky design direction

 The Final Decision

During yet another long meeting of trying to choose between Dungeon Restocker and Corn Maze, we came to a startling conclusion: Making Dungeon Restocker into a 3D game would actually reduce our workload. This seemed rather unintuitive, but correct. Moving to 3D would make most of the major things we needed to implement for a working prototype absurdly easy to integrate, because we could use built-in engine features instead of writing our own. It also gives us an opportunity to make more interesting and complex levels, which is always a plus. The best part? We can build the dungeons out of modular parts and hook up our level creation to a tilemap editor like we were planning to anyway! In other words, we can have all of the pros and far fewer cons.

Suffice it to say, we're making Dungeon Restocker now. Even better, we have to make it in Unreal because Unity is missing certain features in the AI department that we sorely need. This makes me very happy, because frankly I'm not a huge fan of Unity's dev tools. Our new goal is to make a new prototype and attempt a Stage Challenge on Wednesday. We'll see how it works out, but I think we might just make it if we put enough effort in.

10/1/15

Capstone Update 4: Unleash the Sandworm!


Bet you didn't see that coming!
Our stage challenge was delayed for a week so that we could get more testing in, which gives me a good opportunity to keep improving Sports Game. The prototype now features 3 new strange rules, including the sandworm pictured above:
  • Tumbleweed:  The chairs are no longer held up by their legs, and flop about as they move
  • Endangered Bird Watch: Endangered birds fall to the ground and must be avoided. Anything that hits them causes them to explode in a puff of cartoon blood, and hitting them with a chair results in losing a point.
  • Unleash the Sandworm: A sandworm beneath the ground chases a random player, telegraphed by upturned earth. The worm then pops out of the ground for a moment, eating anything beneath it.
Suffice it to say that the game is a bit more hectic now. The sandworm also introduces player death, a new mechanic. When a player dies, they explode in a puff of cartoon blood (like every other dead thing in the game). Their team loses 1 point, and they respawn a few seconds later. We'll need to test this for balance purposes, but for now it seems fine.

On the subject of rules...

When our team showed off Sports Game at the last meeting, there was a bit of confusion about the game due to some poor wording on my part, so I think I should give a quick explanation here in addition to the one I already gave: Rules in Sports Game are not "Rules" in the traditional sense that people might expect from sports. Rather, rules are mechanics that the game randomly introduces during play. Some might take the form of rules (Such as the one where you have to avoid running over endangered birds), but this is not a requirement. Likewise, the game isn't meant to play like a real sport, it just bears a strong resemblance to them and is referred to as one. I wonder if most of the confusion is coming from people trying to make sense of the concept, when it really isn't supposed to make sense. If we decide to go forward with this, we'll have to think hard about what to do to avoid future confusion from players.

What's Next?

My main development goal before the next presentation is to get a total of at least 15 rules into the game. In addition, I want to draft a list of several hundred rules/potential rules. This kind of game will live or die by its replay value, so it needs a lot of content to be successful.  Even if we don't manage to implement the entire list into the game, it gives us a good blueprint to work with.

With any luck, we'll challenge next week and then I'll write a post about what happened!

9/26/15

Update: 1 month of college edition

If you've been reading this blog, you may have noticed that I haven't made very much posts apart for the capstone ones. To be honest, I haven't made too much headway on most of my projects recently. This is caused by several factors:
  1. Capstone - This one's obvious. Capstone, being the final piece of my college career, has to take priority over my other projects. There's always plenty of work to be done, so I don't have as much time for personal projects as I'd like. Thankfully, this generates plenty of posts
  2. Sickness - If you're a student right now, this might also make some sense. Going back to school tends to result in the entire student body catching a cold, so it's no wonder. I've been taking it unnaturally well, but it still makes me a bit slower on the work front
  3. Too Many Projects - I started this semester with 2 major projects: Halberd and DFEngine (Eventually AMAZE and Space Douchebag too). I'm currently sitting on.......9 projects. Brainstorming for capstone and a general creative mood has led to a bit of an explosion. This particular deluge of ideas seems to be over now, but I still have to split my work more now. None of these newcomers are ready just yet for a post, but they will be soon.
  4.  Work - In addition to all of this, I have a part-time job. That's going to be over(ish) pretty soon, but that currently eats close to 15 hours a week, when factoring in travel times.
Those 4 factors are the main reason that the posts have dried up a bit. With that said, let me give you some quick updates on some of the things that I'm working on.
  1. Halberd - I've fixed all of the bugs that I pointed out in my last post! My next goal is to figure out how to set up a decent GUI for the editor. I'm leaning towards using an established library such as Gtk, but I'm not entirely certain yet. That decision is the main delay in the project, and once I've made a decision I'll probably post about it.
  2. DFEngine - I'm occasionally working on this on and off, mostly trying to set up a better logging system. I'm also working on a post about that as I go.
  3. Tutorials - I'm finally back to my ncurses game tutorial, with one opf my new game projects. I've started writing the post for that, and hopefully you'll see it soon.
  4. Software - I'm currently cleaning up one of my personal projects, and once that's done I'll be releasing it on Github. I'm pretty excited to get another piece of normal software out for use, and hopefully that'll also be ready soon.

Last but not least, I'm teaming up once again with my good friend Peter Orzell. For the unacquainted, Peter is a bit of a mad scientist and the composer who's made most of the music in my games. (A Wheelie Good Time, Diamond Rush, Space Douchebag, and Doomsday Darren Goes Fishing)
Two years ago, we made a little 'gem' called Duke Spookem 3D for Game Architecture class. It was a big hit with the people we showed it to, and now we're back together working on it again! I'm currently working on getting the game to run on Linux machines, and then we'll start swapping out the assets and fixing up the engine. With any luck, you'll be seeing some more posts about that in time.

9/24/15

Capstone Update 3: Sports Game!

The first phase of our development is nearing its close, and now we've started all of our demos. We've got 3 more concepts that we've begun to prototype, and I'll be covering them all in general next week, but today I want to focus on my prototype: Sports Game.

Sports game is a very odd concept that I came up with during one of our brainstorming sessions. A question formed in my head, along the lines of "What would Calvinball look like as a video game?" (This, of course, refers to the made-up game that occasionally popped up in Calvin & Hobbes comics) From these roots, the idea formed for an actual game. The general concept of Sports Game is an absurd one: The game starts out like soccer, but every 30 seconds the rules change randomly. This usually means the addition of a new element to the game, such as half the field falling into a pool of bubbling lava, a prisoner being dropped into the field for public execution, time travel, or maybe just hundreds of regulation Sports Balls spewing into the arena. Also, everyone is riding around on office chairs, because at this point, why not make things a little more interesting? The office chairs actually came from a different game idea. We couldn't find a good way to make it into a proper game, but we really wanted to keep some of the concepts. Sports Game, being built around silly and arbitrary concepts, seemed like the perfect fit.
The 'normal' start of the game

In my vision for the game, Sports Game(or Sports for short) is a huge thing in society, much like sports are in the real world. Stadiums use newer and wackier devices to try and woo the crowds with their rules.

The prototype is going well at the moment. I have the most basic mechanics of rolling around and scoring goals working, and now I'm working on the multiplayer and rule-changing elements.
The Multiball rule duplicates all the balls on screen

As you've seen in the above screenshots, I've also made a basic chair model for the players to sit in. Here's a closer image of the model:
It's basic, but I think the simple aesthetic looks good for a game like this. I still want to make some improvements to it, but now isn't really the time for that. Maybe you'll see this again if we go through with this game!

9/13/15

Halberd Update 2 : Scrolling Around

Just as promised, here's a short update on my progress with Halberd. I've started to adopt a new strategy for work that spreads my work out more, so work on individual projects has slowed down a bit. On the other hand, I think it's more fun, and I've been making more progress on projects that had been sitting by the wayside for a while.

A couple of things have been done for this project since this summer. The biggest update has been to map loading and scrolling. Just like I originally explained, maps are loaded as the player walks between them. To ensure that the game world can grow to any size, actors in the world use 3 sets of coordinates. The first one refers to the map that the actor is in, the second is the tile that the actor is on within the map, and the last set is the position used for rendering. Using this setup, we can allow actors to move smoothly between tiles, and while also having enormous maps without any extra tricks.

This update is pretty short, so I'm also going to leave a couple of screenshots showing off the current status of the editor and game.
Here's a view of the test player standing at the intersection of several map segments. The unsightly seams will be going away shortly, but in the meantime they do a good job of showing how the maps connect nicely.

Now, here's a second view of the area, from the map editor. As you can see, multiple map segments work even in the editor now, as does zooming. However, the editor doesn't yet support map streaming like the game does. I also need to get the grid to draw on more map segments. It shouldn't be hard, but the multiple segment feature is still a work in progress for the editor.

Lastly, I just finally got the code for this project up on Github. If you're wondering how much duct tape is involved holding this engine together right now, you can finally find out! My next goal is to clean up some of the little bugs here and there, and polish the editor up a bit more. After that, I can get back to adding more gameplay features.

Capstone Update 2: The 1st Concept

Now that capstone is underway, our group needs to begin prototyping some of the many ideas that we've been throwing around. The first idea that we've decided to use plays off of a common trope in many games. Have you ever wondered, in a dungeon, why none of the traps are sprung? Have you considered where all of the gold and treasure chests dotting these caves actually comes from?

Enter the restocker.

The point of this game is to enter dungeons and restock them, by resetting traps, refilling chests, and strategically placing corpses with loot. At the end, your performance is graded based on various criteria, like the time it took you and the distribution of the treasure.

Mechanics: Scoring

I'm not going to talk too much about the gameplay itself, since the first prototype isn't even done yet. However, I want to address one question that I was asked while we were discussing the game. The issue that came up was how we could actually grade the player's treasure placement, and I came up with an interesting solution for us to try. Using a technique sometimes referred to as Dijkstra mapping, we can generate heatmaps of important elements in a level. From that, we can analyze how well the player placed treasure, and we can tell whether it's too spread out, to clumped up, or even. We can also theoretically make our own heatmaps of how we think treasure should be distributed, and compare them to the player's results.

Dijkstra Maps

I'm going to go out on a limb here, and assume that you likely don't know what a Dijkstra map is. If you have any experience with game AI, you probably know about Dijkstra's algorithm. Variants of this algorithm, such as A*, are used for pathfinding. Essentially, it works by starting at one point and expanding outwards until the destination is reached or the map is filled up.

With Dijkstra mapping, we perform a version of this from multiple starting points and with no destination. In addition, we can give each starting point a value and make it count down as it radiates outward. If we keep the highest values, then the result is a heatmap generated from the points used. From here, there are a variety of things we can do with the resulting data. One option is to check if lowest value is above a certain threshold, which ensures that no part of a map is too far from a point. Here are a few examples:
1 emitter, no walls
1 emitter, walls
3 emitters, walls

If you compare examples 2 and 3, you'll notice that the values are much higher (redder) as a whole in the latter. This is the general goal here. By spreading out multiple emitters (chests), the resulting values will be much higher than if we place just one in an area or bunch them up.