4 Hugues Ross - Blog: Capstone
Hugues Ross
Showing posts with label Capstone. Show all posts
Showing posts with label Capstone. Show all posts

5/7/16

Capstone Update 19: Project Statistics

It's been a few weeks since my last capstone post, and quite a lot has happened! Last week we finished The Last Light and presented it at the senior show, and it got a pretty great reaction all around. Even better, the game got several Let's Plays after we put it up on itch.io, and the overall reaction seems to be pretty good.

By the way, you can download the game here:

(Sadly, it's Windows only right now. I might see if I can put a Linux build together at some point though)

Now that the dust has settled, I thought it might be a good time to go over some statistics from the project. I got a few requests from fellow team members, and also wanted to do some things myself, so here we go:
(Please keep in mind that these numbers are estimates pulled from hastily-constructed git queries. They should be close to the right number, but may not be perfect)

Total Number of Merge Conflicts

When dealing with teams that have more than a couple of members, it's only natural that at some point, merge conflicts are going to happen. This problem becomes even more common when your project consists mostly of binary files that can't be merged normally. We certainly had our fair share with 122 merge conflicts resolved.

Floor_400x400

For some reason, a random unused asset from the UE4 starter content folder, Floor_400x400.uasset, kept getting marked as changed. My team was curious how many times it got 'updated' in git. Apparently, 60 times. That's about once every other day!

Substance Plugin Kill Counter

Unreal really loves the Substance plugin. If your machine has it installed, Unreal has a habit of quietly slipping it into your project when you're not looking. Then, everyone else on your team gets a little popup saying something along the lines of
"This project requires the Substance plugin. Do you want to download it now?"
Naturally, this message is a tad irritating, so we tended to go into the project file and purge the plugin. We did this 34 times, in fact. That number actually seems remarkably low, but I think it's because we didn't always remove the plugin immediately if we were busy, so sometimes it would stick around for a while.

Total Number of Binary Updates

Have you ever an artist to go compile some code? It's not pretty. Although Unreal makes compiles pretty easy, we programmers made a point to include the compiled binaries in git so that our fellow team members could spend less time compiling and more time developing. This happened 96 times.


That's it, but hang on to your seats, boys and girls! It's time for.....

Uncle Huey's Repo Analysis Awards

The "Biggest Git" Award for Total Commits

 Let's start with a simple one: Who made the most commits overall? It was a close race, but the winner is:
Chris Johnson, with 292 commits
Second place is Vincent Loignon, with 288 commits. 
Simple, right? On to the next category!



The "Man of Mystery" Award for Commits under an Alias

Not everyone keeps to a single name, especially when jumping from computer to computer. This award is for the person who made the most commits under a non-name:
Jesse McKinley, with 122 commits listed as 'Dekeche'
Second place is Hugues Ross (me), with 121 commits listed as 'DF458'
Looks like it's another close one. Next!



The "Fashionably Late" Award for Latest First Commit

You know what they say: The early bird is a total loser.  This award goes to the person who was the last to start making commits to the repo. Who won? Why, it was:
Paul Scardera, who first committed on April 13th
Second place is Kyle Patterson, who began on April 8th
I think it's important to mention that these awards are meant to be fun, and that this isn't any sort of condemnation. Paul and Kyle are both producers, so they only joined in with direct development at the end to help with 11th-hour grunt work. They've been super helpful throughout the project, just not with commits.
And speaking of strange awards...



The "Writing is for Losers" Award for Most Commits Without Changing a Single Line of Text

Git keeps track of how many lines of text were added, removed, or changed in text files. This award goes to the developer who made the most commits while maintaining a perfect 0 in all of those categories. Let's hear it for:
Paul Scardera, with 7 commits and 0 lines
Second place is Scott Beecher, with 6 commits and 0 lines
Again, be nice, not everyone's work is represented by commits, yada yada.
Now, time for the final award:



The "Who's That Pokemon" Award for Most Enigmatic Team Member

Among the huddled masses of our Slack channel, there are rumors of a secret developer, spoken of only in hushed tones, working from the shadows. Who are they? Where did they come from? No-one knows for sure. Of course, I'm talking about:
Unknown, with 18 commits
Yeah, so someone probably just forgot to enter their name into git before committing. Still, it's good to have fun with these things, that's what the awards are for!
Actually, I just double-checked and apparently it was me all along (with one commit from vince). Whoops!



Project Development Visualization

All this text is pretty boring. Thankfully, I have a solution to that problem. In addition to all of these stats, I also have a visualization of the project's development, starting from February (Fullscreen viewing is recommended):


This video was made with a super-cool tool called gource. Go check it out!

4/17/16

Capstone Update 18: Doors, my greatest weakness!

Recently, I had the misfortune of dealing with a number of issues in Unreal, and all because of doors. One of the last features that the designers wanted me to add to the monster was the ability to slip under doors and gates. "How hard could this possibly be?" I wondered to myself.

As it turns out, it was much harder than it should've been.

First try: The sensible approach

My first attempt was using Unreal's NavLink system. Nav Link Proxies allow you to have your AI take routes that aren't part of a level's navmesh, and have the ability to set up "Smart Links" which can have additional scripting added to them. The idea was to use this system to make the monster play an animation and warp to the other link, but there were some issues with this approach. The primary issue is that you can't remove all of the normal links and use only smart links. My research seems to suggest that this is a long-standing bug in UE4, so there's not much I can do about it. (As an aside, it's times like these that make me regret not trying to convince the team to make our own branch of the 4.9 codebase) If the monster chooses the 'dumb' link, which seemed to happen randomly, it would run into the door/gate and become permanently stuck. Clearly, a new approach was needed.

Second try: The unpleasant approach

After that, my next idea was to add a higher tier of pathfinding for the monster. By generating a set of links, I could create a small pathfinding graph that represented the level. With a basic A* implementation, I could make the monster select movement targets while attempting to reach a certain position or object. This was an incredibly large undertaking, but the result would likely work well. As such, I made all of the necessary preparations for pulling an all-nighter. However, this is not the solution in our build.
I constructed all of the necessary objects, but when I went to actually get them generating links I noticed something odd. specifically, none of them were linking up. I'd written a small function that used a quick pathfinding check to see if one link was reachable from another, but they always failed top make a connection. As it turns out, the returning value was always 'error'. Note that Unreal didn't provide any specifics, nor did I find any way of seeing what precisely this error was. After yet more research, I found out that this is yet another long-standing bug in Unreal. Epic really needs to crack down on some of these. Frustrated, but not yet asleep, I thought up another way.

Third try: The 'Why the hell not' approach

With all of the obvious and reasonable solutions out of the way, it was clearly time for a disgusting hack. After searching some more, I found a way to make Unreal ignore a given solid object when building the navmesh. However, as demonstrated by the first approach, this kills an AI's movement when they walk move an unexpected solid. To prevent this, I put a box trigger around every door and gate. Then, I made a special collision layer for the monster that would make doors/gates ignore all collisions with it. When the monster entered the trigger, it would change and be able to pass through! As an added bonus, the monster would even pass through the floor and fall out of the level, despite the fact that the floor is supposed to collide with it! To prevent that little issue, I had to temporarily disable gravity, while also changing collision layers and animations. Lastly, I needed to adjust the monster's speed. The monster is supposed to be slowed down by these obstacles, after all.

So, that's how I came up with a dumb solution for a dumb problem. I really hate that I had to do this, since it's a much less elegant and flexible solution, but I don't really see any available alternatives. As long as it holds together, I suppose it'll have to do.

4/7/16

Capstone Update 17: Looking Good!

As the beta milestone (the effective 'due date' for the monster) approaches, I've started filling in the remaining gaps that are left over from earlier in development.

One of those gaps is art. I gave the monster a graphical upgrade several weeks ago, but I've gotten plenty of feedback since then. I've also added more abilities to the monster since then, which require more animations.

The two biggest complaints about the monster were that it wasn't very scary, and that it was still hard to tell when the player was taking damage. The designers haven't had a chance to play with the monster's stats yet, but I still found it odd that my damage feedback wasn't doing enough. One thing that we'd been wanting to do for a while is make it more apparent that the monster was nearby, so I added a noise effect that grows as you get closer to it. In addition, I made the damage effect on the player smoother and slightly reduced the monster's damage. This seems to have greatly improved player reactions to getting hurt.

One of our designers added a nice cinematic introducing the monster, where it leaps down to attack you but is driven away by a flickering ceiling light. We think it's really nice, and much scarier than normal interactions with the monster. Part of this is because the player can fight back, but we've also identified a few other things that could use improvement. First off, the monster is almost always seen from a high angle. In other words, it looks harmless because the player towers over it. Just making the monster taller than the player has added to the monster's scare factor by a decent bit. I also pumped up the alpha and particle count to try and make the monster look a little bit more solid than before.


The last thing to add, which I addressed last weekend, is animation. There were  two main situations where the monster needed animations: Blinking, and slipping under doors. Blinking especially needed an animation, because the player needed a warning that the monster was about to appear. I spent a long time considering how to make the blink look. The blink is probably the most 'outlandish' thing that the monster is capable of, so I wasn't really sure how to make it work visually. Most of the monster's abilities are closely tied to the fact that it's more of a cloud than a solid object, but teleportation doesn't really fit as obviously.  Ultimately, I decided to interpret the blink as the monster slipping into a crack and popping out elsewhere, which I've represented with the monster's particles compressing and flying into the ground, while a second animation has them pop out and expand at its destination. It may not be perfect, but I think it fits nicely nevertheless.

The slipping animation was much easier. I scaled down the monster's particles, then made them stationary and emitted them using a flat disk. The result is a mostly-flat shadow creeping around. I'm pretty happy with the result, and also a little sad because I think a bigger, more elaborate version of it might've made for a creepier design overall. My original idea was for the shadow to be a vague squid-like silhouette that scurried around the floor and walls, and I still kinda regret not giving it a shot.

3/31/16

Capstone Update 16: Blink and you'll miss it

It has been quite a while since my last post. I've gotten a lot of work done since then, so I've decided to split my post into two parts. In this first part, I'll discuss the changes to the monster's AI, and in the second part I'll talk about graphics some more.

I've made several major changes to the monster's AI to make it more dangerous and unpredictable. The first change is the ability to 'blink'. When the monster is trapped or otherwise unable to reach the player, it can now teleport to designer-specified points called 'blink nodes', favoring nodes that are close to the player, but not to close to be unfair. This gives the monster more options, and makes it more challenging to trap.

Another major change that I've made is making the monster more resistant to the flashlight. The player's flashlight no longer marks them as 'safe' when in the dark, and the monster will now attack them. If the player sees the monster and reacts quickly, it can still be warded off with the flashlight. However, if it gets close enough then the flashlight becomes ineffective and the player will be forced to fumble with a flare to escape. This rewards careful play, and prevents the player from being 100% safe for most of the game.

Lastly, I've made the monster change speed based on its state. This not only makes it seem more dangerous, it also makes it very difficult to chase and kill, as we found some testers liked to do. Combine that with regenerating health similar to what the player has, and the monster is suddenly much more dangerous than it used to be.

Now, the monster is much more dangerous. On the visual side though, it's still a bit of a cute fluff cloud. In my next post, I'll discuss the steps that are being taken to fix that.

3/6/16

Capstone Update 15: Monster Beauty Pageant

During the past couple of weeks, I've been working on the monster as always. The AI work has been slowing down since I've had to look up how to alter some of the pathing. In the meantime, I've also started working on the particle effects that make up the monster. I think I've made some pretty good progress so far.

Shaping the Monster

When I asked the artists on the team for some guidance on how the monster should look,  they brought up images of schools of fish, and various swarms of animals. Following that idea, I added an additional emitter that created tiny particles to erratically orbit the monster's origin point. The original cloud of smoke now had what looked like a swarm of insects buzzing around it.

Next, I decided to try and fix a simple problem: Because the monster is entirely black, it's nearly impossible to see against a dark backdrop. I needed to find a way to make the monster visible while still being creepy. One of the original concepts that spawned this game was the common fear of the dark. That concept led me to try and make the monster create glowing 'eyes' within its mass, both to add to the creepiness factor and to make it more visible to the player.
Even in a bright preview window, it still looks a tad unsettling

Changing Form

I got some useful feedback in class. My teacher showed me some videos of snakes, barracudas, and other 'long' predatory animals to help make the monster seem more dynamic and alive. I've taken her feedback into consideration, and made a few interesting changes.

The monster in its natural habitat

My first change was to "give the monster legs", as I like to call it. As you can see in the screenshot above, the monster's main mass actually falls now, and sits on the ground. The result is that the monster seems to actually drag its body across the floor, rather than simply float like a cloud. It also serves to almost make it feel more like a creature, by giving it what looks like a discernible head.

When fleeing a light, the monster puffs itself up

After that, I started working on making its state more visually obvious. I started off by making the monster's size depend on a variable that I could alter. When the monster charges the player, it becomes thin and agile. When it runs away, it puffs up to look more intimidating. This change alone makes it feel more interesting and alive.

The monster going in for the kill. Believe me--it's creepier when it moves.

With the size changing in place, I began working on giving it some more interesting movement as well. When attacking, the monster now undulates along two sin waves. Each axis (horizontal and vertical) has a slightly offset multiplier and length. The result is desynchronized movements that make it look both dangerous and a little bizarre.

As a little teaser, here's some updated damage feedback.

2/22/16

Capstone Update 14: The blog post where I actually discuss monster AI

This past week, our team took The Last Light to an expo in Montreal. By all accounts, it went well, but the work leading up to it was intense. I'll probably be taking things a bit easy, given that I spent 17+ hours working on the project last week.

One of the big things that I worked on last week was the monster AI. We now have a rough sketch of the AI implemented, and in the first level. I'm going to go through a quick rundown of the behaviors here, and what I plan to add in the future.

The Monster is based on a basic finite state machine, currently containing 4 states:

Wandering

 This is the default state for the monster. Currently, it chooses a random location within a small radius that isn't illuminated and that it can see, then goes there and repeats. This was implemented before I received the full designer spec for the monster, so it differs somewhat from their design for the moment.

Their system has the monster moving randomly between predetermined points, with a bias towards the player's position. This is partially implemented, but the waypoint EQS generator is still WIP.

Seeking

Previously, the player would die if they stayed in the darkness too long. Now, we have a more concrete and visible threat in the monster. When the player strays into the darkness without a light, the monster is alerted and enters a seeking state.

In this state, the monster finds a direct path to the player and chases them. If the player is caught, they begin to rapidly lose health, shown by a post-processing effect. Their health will regenerate after a few seconds of safety, however.

Currently, this is a pretty dumb state. Because the monster uses UE4's default pathfinding, it finds the most direct route. However, this route usually passing through includes light, which harms it. I haven't decided how to handle this yet, but I'm considering both navigation modifiers and custom navigation. Only time will tell.

Fleeing

 When the monster is lit and begins to take damage, it retreats. This is done using a simple pair of EQS tests on top of the same generator used for wandering. The tests A. ensure that the monster won't be moving into light and B. Heavily favor locations that are more distant from the player. The result is a behavior that feels 'right' when the player shines a light on the monster.

Dead

The monster takes damage from light, so if it spends too much time lit up it will enter a dead state. Once 'dead', it disappears for a few seconds, before reforming and continuing with what it was doing.

One major thing that needs to be done still is making it move in this state. It seems counter-intuitive, but by making it move as if it were fleeing, I can ensure that the monster won't reform directly on the player or inside a light.

My Goals

I've explained all the monster work that remains, but I also have some other goals for this coming week, mostly focused on graphical improvements.

First off, I need to improve the damage effect. Right now, it's not quite "in your face" enough, which probably makes it difficult for new players to realize that they're dying. Some additional blur, contrast, and color tweaks should hopefully make the player more aware of what's happening.

After that, I need to work some more on the interaction shader. Currently, it works well, but the designers have requested more control over it, such as color and width options. I'd like to get that done soon so that they have more time to play with it.

I don't expect to solve the pathfinding issue just yet, but we'll see.

2/12/16

Capstone Update 13: Making a Monster

The time has come for me to return, take up my mantle as an AI programmer, and write a bait-and-switch post about Unix shell scripting. I did work on our buddy the shadow monster this week, but it's not in the game yet and I'll be making much more progress on it this weekend. In the meantime, I'm going to make a post about a specific problem, and how I solved it with a just a tiny bit of scripting.

If you've used Unreal Engine 4, you probably know about the Substance plugin. This plugin is useful for making materials, but also has some issues. First off, it absolutely does not run on Linux. Given that my primary dev machine exclusively runs Linux, this is a problem. If I try loading a project that contains the plugin without installing it, Unreal simply crashes. The second issue is that it spreads. For some reason, installing Substance in one project seems to make it quietly install itself into other projects. So, if a single member installs Substance, the rest of the team will have to install the plugin on every new computer that they load the project onto.
Clearly, we have a problem.

However, I'm not here to complain about a problem, but instead to describe how I solved it. As a linux user, I think I can safely say that I'm more comfortable with shell scripting than your average developer. I'm also quite comfortable with git's command-line interface as well. Lastly, I know that Unreal stores plugins in the its text-based .uproject file. Going with my knowledge and experience, I decided to try and create a script that could auto-remove Substance whenever it appeared, so that no-one would ever need to deal with it on this project again.

Search and Destroy

The first thing that I had to tackle was finding and removing Substance. After all, if I couldn't do that then there would be no point to this exercise. Here's an example of a .uproject file with Substance installed:
{
    "FileVersion": 3,
    "EngineAssociation": "4.9",
    "Category": "",
    "Description": "",
    "Modules": [
        {
            "Name": "MindTreeGames",
            "Type": "Runtime",
            "LoadingPhase": "Default",
            "AdditionalDependencies": [
                "Engine",
                "CoreUObject"
            ]
        }
    ],
    "Plugins": [
        {
            "Name": "Substance",
            "Enabled": true,
            "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/offers/2f6439c2f9584f49809d9b13b16c2ba4"
        }
    ]
}
Keeping in mind that the plugins section only appears if there are plugins installed, and that The Last Light doesn't make use of any plugins. In other words, we're free to simply wipe the Plugins section out entirely. Of course, we still need to find Substance, but we can easily fix that with a simple grep.
# Grep provides us with a line number at the start of the line, so we use cut
# to isolate it
substance_line=`grep -n "Substance" $project_file | cut -f1 -d:`

# Then, all we need to do is check if the resulting variable is empty or not
if [ -z $sub_line ]; then
    echo "No Substance here, but remain vigilant!"
else
    # The +/- parts here are hardcoded, based on the fact that our .uproject
    # file is relatively stable.
    start_l=$((sub_line - 3))
    end_l=$((sub_line + 3))

    # Delete the calculated lines, and get the resulting file
    result=`sed "$start_l,$end_l d" $project_file`

    # Now, just write out the result to the file. I take this extra step so that
    # I can provide a preview before making the change.
    echo -e "$result" > $project_file
fi
With this basic script, we can now find and remove the Substance plugin from a project with a single call!

Hooking it Up

I had a good start with my script, but I wanted a proper automated solution. Luckily, git provides us with the necessary tools to make this happen. By placing scripts in the .git/hooks directory, we can add scripts that are called on certain git-related events. If we add our script as a post-merge hook, then we can make our script run every time we pull changes from a remote.

In addition to adding a hook, we may want to commit our changes, and push them to save other team members the work of removing it themselves. As it turns out, we can simply call git commit and git push from a post-merge hook, and they work completely fine.
# Grep provides us with a line number at the start of the line, so we use cut
# to isolate it
substance_line=`grep -n "Substance" $project_file | cut -f1 -d:`

# Then, all we need to do is check if the resulting variable is empty or not
if [ -z $sub_line ]; then
    echo "No Substance here, but remain vigilant!"
else
    # The +/- parts here are hardcoded, based on the fact that our .uproject
    # file is relatively stable.
    start_l=$((sub_line - 3))
    end_l=$((sub_line + 3))

    # Delete the calculated lines, and get the resulting file
    result=`sed "$start_l,$end_l d" $project_file`

    # Now, just write out the result to the file. I take this extra step so that
    # I can provide a preview before making the change.
    echo -e "$result" > $project_file

    # Commit and push our changes immediately
    git commit -a -m "[bot] Removed Substance Plugin"
    git push origin master
fi
With these changes, all we have to do when we pull in the Substance Plugin is type in a password, and our script handles the rest.

2/5/16

Capstone Update 12: Lighting Up

This week, I made the first pass of a very important feature in The Last Light: Light Detection.

One of the central themes in The Last Light is the fear of darkness. Darkness is not only supposed to be scary, but dangerous as well. In darkness, the monster becomes more aggressive and staying outside of the light for long enough will result in an immediate game over.

Of course, to make all of this happen we need to know if the player is standing in darkness or not, and that's where light detection comes into play. Last semester, the team faked this by surrounding segments of the game world with giant "light volumes" that could be turned on and off. While this does solve the problem, it's a pain for the designers. Not only do they need to put these things in place, they then need to hook them all up to the power system along with the lights in each room. They also add more cruft to sift through when searching a level for a particular asset or area. For this reason, I was tasked with finding a solution that relied on the actual lights in the scene.

Ultimately, I came across a solution in the UE4 forums. (Here, for the interested) I'm still not sure about it, but it seems to work well. The general method is this:
  1. Iterate every light in the scene
    1. If a light is off, it doesn't affect the player, or there's no "line of sight" to the player, ignore it.
    2. Otherwise, determine how strongly it's lighting the player up and add the result to a counter
  2. If the counter is above a certain threshold, the player is safe. Otherwise, the player is considered to be "in darkness".
My main worry about this method is about performance. Every tick, I need to check every light that's loaded in the level. No matter how fast this is, this still comes with overhead. Furthermore, the shadow monsters will also need to know their light level. It's entirely possible that these checks will negatively affect performance in a big way once multiple actors are involved.

My current hope is that this won't be an issue. If it does, then I'll probably see if I can either cache some information or cheat on distant AIs. For the moment, however, I have a more pressing issue to resolve with this system. When I first made the implementation last week, I was mostly aiming to create a quick proof of concept. As a result, detection is currently very glitchy.

This mostly comes down to the way I'm determining light levels. For the sake of getting the feature to a kind-of working state, I simply divided the brightness of affecting lights by the distance. This doesn't really reflect the way that unreal's lights actually fall off, and as a result you can survive in some very dark areas while sometimes dying well within a light. Clearly, I need a new algorithm for properly determining falloff. Fixing this is going to be my first goal for the weekend, and my first guess for this fix is getting the light's radius value involved. I don't know for sure that this will be enough, but if it's not I can take a look at the UE4 code to see how they determine light falloff.

After that, I'll hopefully start tackling the shadow monsters! Yes, that's right. I'm back for another round of AI programming. Stay tuned.

1/29/16

Capstone Update 11: Bugs in the wiring

Like last week's post, this Capstone post is going to be a bit short. Because of my schedule, I haven't been able to do much Capstone work outside of weekends. In addition, I didn't really have much to do until last Wednesday. As a result, I don't really have much to share beyond some truly riveting refactoring work. Because of the dearth of work, I'm going to be talking about a bug I found last week while testing a shader.

We have many interactive objects in our game, and some of them, like certain power switches, should only be used once. After using them, the highlight that marks them as usable disappears and they become unusable. Sounds good, right?

As it turns out, all of this only takes effect when you move your mouse off of them. As long as you keep your cursor in place, you can flip switches all day long. Of course, no one planned for this. Animations break, and (surprisingly!) you can simply switch lights on and off as fast as you like.

Sadly, as fun as this little bug is to play with, it's actually quite serious. Not only are lights important for staying alive, some doors are only open when the power's on. This means that by turning on the first switch, turning it back off, and looking away, the player can effectively soft-lock the game within about a minute of starting.

Since I found the bug, I decided to take it on and dig a little. It looks like the player is the culprit. The player keeps track of nearby interactive objects, adding them to and removing them from a list as you move and look around. When an object is no longer interactive, it can't be added. However, it doesn't get removed when the object's state changes.

There are a couple of ways that I could fix this issue: Removing things from the list, and making the interact key check the object when used. Originally, I was planning to do the former. However, I recently thought of another bug. If an object isn't interactive, and then it changes, the highlight won't appear and the player will be unable to use it. The latter change should fix this issue as well, but I'll have to give it a shot first.

1/22/16

Capstone Update 10: A new team, and a new game

With a new semester, it's time for a new weekly Capstone post.

Dungeon Restocker failed to go forward last semester, so I've joined a new team. Since the new production cycle has only just begun, I'm going to take this post to discuss the game and my role for the coming semester.

The Game

First off, let me introduce you to the game, The Last Light, with a short video:

As you can see, this is not the same goofy lighthearted fun that I was working on last semester. In addition to the trailer, the team made a brief description of the game for a Greenlight page:
"The Last Light is a first-person puzzle / survival-horror game where you play as Sophie Thompson, a highschool student on her way to pick up her younger brother Lucas, when an unknown entity causes a widespread power outage. Sophie embarks on a journey through the underground where she learns that there is some invisible entity lurking in the darkness and that the only way to remain safe is to, at all times, stay in the light."
I think that covers the game pretty well. I find the project especially exciting because this is my first time working on a game in this genre. I'm not usually a huge fan of horror games, but I find the premise interesting so I don't mind developing one. Now, let's talk about my role in all of this.

My Job

Like the other senior production games, this one came from last semester. All of the newcomers, like myself, have taken what was once a tiny 4-person team and tripled the headcount. As a result, many of us have been given some specific responsibilities.
In my case, I'm the team's dedicated Graphics Programmer. That means that I'll be handling a lot of the work on visual effects and materials, alongside the artists. While I enjoy graphics programming, I've never gone too deep into the subject. My work on DFEngine is the farthest I've really taken things, so I'm excited to have a real opportunity to develop and practice my skills.

For now, I'm going to leave it at that. Hopefully I'll have more to talk about next week as I start getting my hands dirty!

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

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.