July 26 — Where I’m At

Well, here we are so far. A lot of work has been completed since the last progress report.

  • Voice recording and mastering is all done. That’s right. Every single line has been edited and made to sound like it’s coming over radio, so it’s all campaign-ready. I really enjoyed working with the individuals who were nice enough to offer their voice acting talents. (Finding enough actors was something I was initially concerned about, but many people were very willing to spend a half hour or so working with me to bring my characters to life. I’m very grateful for that.) There were a lot of bloopers filled with jokes and curse words. It made the editing process (which took hours upon hours) very entertaining.
  • The first 3 campaign missions have been built. These are shorter missions intended to gradually introduce features and familiarize the player with the controls, and are thus fairly simple. The remaining missions will be longer, but will probably be built quicker as I develop momentum (and gain familiarity with my own game engine…funny how that works). I have to say, it is incredibly exciting to see the action and hear my characters come to life in the way I imagined.
  • Various game play improvements. The targeting system has been improved, the computer players are smarter, bugs are being squashed…the list goes on.

Currently, my priority is getting the campaign finished. Building the missions not only advances the game towards completion, but also reveals bugs in the engine and helps identify game play issues.

Here is a screenshot from the third mission, Incursion, where a simple assault goes awry and the player’s forces are ambushed by the Coalition.

The player provides support during a mission to destroy a series of enemy network satellites.

The player provides support during a mission to destroy a series of enemy satellites.

Until next time.


Tech Report — Efficient Laser Bolt Collision Checks

I’m going to depart from my usual style of blog post and exercise my right to describe some technical stuff. This week’s topic is going to be about collision detection. It’s a massive topic, but for the purposes of today’s post, I’m going to focus on a very specific portion of Gateway’s collision detection system: how it handles laser bolts colliding with other objects.

Collision detection is potentially very costly, and the amount of collision checks between objects doesn’t scale linearly. The real trick is to discard potential collisions with as many objects as quickly as possible. In my attempts to reduce how often these checks had to take place in Gateway, I focused my efforts upon the most prevalent collision-enabled objects in the game world: the laser bolts.

In my game, lasers move very fast. We can’t rely on simple distance checks to determine if a bolt hits a fighter; the ordnance may very well simply ‘jump’ over the fighter and miss it entirely.

Simple distance checks will not suffice because the bolt moves so fast that it may skip over a potential victim

Simple distance checks will not suffice because the bolt moves so fast that it may skip over a potential victim, missing it

So, instead, we cast a ray between the old and new positions of the laser bolt.

As the laser bolt moves forward, our collision system performs a ray cast between its old position and its new one to see if it hit anything in between

As the laser bolt moves forward, our collision system performs a ray cast between its old position and its new one to see if it hit anything in between

This works fine, but we’re unnecessarily testing the ray cast against objects that fall behind the bolt. So, we discard any objects from the ray cast test that aren’t in its path. This can be done with a fast vector dot-product calculation and discards half of the objects we have to test against, on average.

Ray casting is expensive, so we should only test the objects that fall in front of the laser bolt's path

Ray casting is expensive, so we should only test the objects that fall in front of the laser bolt’s path

But, we can still do better than this.

Now, we’re performing these collision checks every frame. Even though we’re discarding a good chunk of the objects in our scene fairly quickly, that can still be costly in terms of pure iteration. These checks for discarding objects also consume resources.

Let’s think about this: laser bolts move really fast. Over the life of a single bolt (about one second or two), no ship is likely to change it’s position much. In other words, the set of potential colliders for any single laser bolt is fairly static throughout its entire life. So, why not just pre-compute a list of potential colliders at the beginning of the bolt’s life? This is likely to be a very short (or empty) list, and we can re-use it for every frame of the bolt’s life until it dies. In other words, we’re only computing the list of possible collision candidates once.

This page has some great code for a fast check to see if a point lies within a cylinder in 3D space. By specifying a radius wide enough to account for the fact that certain ships may cross the path of the laser bolt, we can use this to build a list of potential colliders that will remain valid until the laser dies. This list might only ever contain just a handful of ships out of hundreds, and will save our collision engine from tons of unnecessary iteration.

When a laser bolt is first spawned, compute a small list of candidates which we may collide against, and re-use it continually throughout the laser's life

When a laser bolt is first spawned, compute a small list of candidates which we may collide against, and re-use it continually throughout the laser’s life

In the image above, we can see that only two ships are within this cylinder. For that particular laser bolt, those are the only objects we have to check for collisions against. Pretty neat.

Of course, we’ve made a number of assumptions. We assume that the laser bolt is fairly short-lived and travels very fast. Slower or long-lived ordnance would necessitate the use of a wider cylinder, if we could still use this technique at all. Additionally, weapons that don’t move in a straight line (such as heat-seeking missiles) would present a problem. But for standard laser bolts, this works just fine.


Finish or Fail

I have a list of unfinished projects as long as my arm. It’s taken me a while to develop the discipline necessary to see my goals through to the end. So, this week’s post will be all about the various causes of project failure that used to plague me, years ago.

Of course, this list is not exhaustive, nor are these categories mutually exclusive. Readers are more than welcome to contribute their own insights.

  • Feature creep. This one hardly needs explanation, and has been the bane of my existence more than once. Too many times have I been unable to resist the pull of flashy features that only served to broaden the scope of my project to such a degree that I could not possibly finish it.
  • Massive changes to the system. A particular game called Wing comes to mind. (This was, in fact, yet another precursor to Gateway.) I had a nearly-finished game engine, support for exciting environments and missions, and a story ready to go. My younger brain thought that it would be a wise idea to upgrade the core graphics engine I had written to something more modern. Instead, all that ever became of Wing was a whole lot of shader bugs and rendering issues. While I could have easily reverted to previous, working versions, I had become so disenchanted with the problems I was having that I ultimately dropped the project. (Fortunately, a lot of the AI and flight mechanics code now reside in Gateway, which has saved me a lot of duplicated effort. So, it wasn’t a waste.)
  • Lack of design. This was an important lesson to learn. Many of my failed game projects began with visions of flashy graphics, advanced particle or rendering effects, or even a single unique gameplay mechanic. Having not given any thought into these projects other than, “this feature is going to be really cool”, they were, of course, doomed to disappear, not having a drop of substance. Since then, I’ve learned that quick, graphical demos are a great way to showcase flashy effects, and that you should have a solid plan in mind before touching a single line of code.
  • Lack of commitment. Being a game dev hobbyist means you’re free to work on whatever you want. I’m constantly being harassed by new and exciting ideas, even as I work on Gateway. Even a well-planned-out game isn’t guaranteed to be completed if you can’t pick your projects wisely. The trick is to choose something that you know you can complete. Initially, this should be something simple, and as you gain experience, you can take on the big ones.
  • Too much commitment. Or, in other words, learn how to take breaks. Your game isn’t going anywhere. Contrary to popular belief, your passion for your project will not dissolve if you set it aside for a week. In fact, you’re likely to return to it refreshed and excited as ever. Constantly pressuring yourself to work on it without disengaging for a while is a sure way to get sick of your project real fast, in favour of some other shiny jewel.

Originally, my failed project, Wing, was about a group of young anarchists trying to buck the system and disrupt a benign, powerful empire simply for fun, when things get out of hand and they find themselves being actively hunted for their increasingly risky crimes. For your viewing pleasure, here are two screenshots. The resemblance to Gateway is fairly apparent if you look closely.

Three established friends test the player's ability to face intense combat odds.

Three established friends test the player’s ability to face intense combat odds.

The player dives low to avoid being caught on radar.

The player dives low to avoid being caught on radar.


Feb. 16 — Where I’m At

If it seems like it’s been a while since my last post…it’s probably because it has. Mostly, this has been because I’ve been busy actually working on Gateway instead of writing about it. There’s been tons of progress, but it can all be summed up in a single phrase:

The first mission is now complete.

Okay, it’s only the training mission, but that’s hardly important, since getting to this point required pretty much everything to be complete enough to support a mission with dialogue, basic enemies, props, etc. Scripting out the mission has uncovered a lot of bugs and “features” that have appeared since I last tested various aspects of gameplay. Thus, the list of things I’ve completed has mostly consisted of: “fixed a bug here, corrected a segfault there, etc.”

A few non-technical items have been addressed, as well. Several models and textures have been improved, for a better look and feel. While I recognize that I’m not an artist, I’m always open to improving something if I think that I can.

Right now, I’m at a very important stage in Gateway’s development: developing the story. I’ve always had a rough outline in my head at any given time, but the real work now involves scripting out every mission and piece of dialogue, in order to figure out how many voice actors are required. Several family and friends who I think would fit some parts well have already volunteered their time, which is going to be immensely helpful. I also have a few play testers lined up. (Not to mention that a couple of folks have already tested the tutorial mission and have given some very useful advice.) Thanks, everyone!

I’m incredibly excited about what’s going to come next. Seeing my game finally come to life in this way is rewarding and, at the same time, very nerve-wracking. What if some vital features are missing that could make the game more fun? What if it’s just no fun at all? I suppose these are normal fears. Whenever they happen to pop up, I usually just think something like, “Shut up. It’s either a half-complete game with loads of features, or something more minimal that’s actually finished. You can’t do it all.” Sound advice, if I do say so myself.

The other issue to consider is that of play-testers. If my game sucks in any way, I’ll just have to trust them to be honest. Then it falls on me to find a way to improve things. The only thing I can do now is just carry on forward.

Before we part ways, here is a screenshot from the tutorial mission. It shows some space stations, colossal gates, cruisers, fighters, and a little dialogue from the (later ill-fated) Col. Matthews.

The player is greeted by Col. Matthews as they enter the training sector.

The player is greeted by Col. Matthews as they enter the training sector.


Jan. 12 — Where I’m At

Not a whole lot has happened since my last progress report. This has mostly been due to the fact that up until that last post, I had been working on Gateway a fair bit, and was in need of a break. Nevertheless, a few things have gotten finished, and a lot of optimizations and graphics improvements have been made.

I had a bit of an unfortunate discovery several weeks ago, and found that a lot of my in-game models and textures didn’t look as nice as I had originally thought. The next couple of weeks after that were spent re-texturing some spaceships, writing a few new shaders, and implementing a better level-of-detail (LOD) system. The game looks much better — it was well worth the extra effort, despite my overwhelming lack of artistic talent.

An FPN cruiser opens fire as it slowly emerges from a Colossal Gate.

An FPN cruiser opens fire as it slowly emerges from a Colossal Gate.

Here’s a breakdown of some of the more noteworthy things that have been accomplished:

  • Several models were re-textured and some shaders were reworked, for a shinier, sleeker look to the spaceships
  • New LOD system combined with several major optimizations speeds up the gameplay noticeably
  • Mission Success menu screen has been implemented

I’ve also begun purchasing royalty-free music so I can slowly integrate it into the missions and see how they fit. What I’d really like to start once I finish reworking the last of the spaceship models is to start building the missions themselves. A lot of missions ideas are ready to take the hazardous trip from my head to the computer, but there is one major obstacle in my way that I haven’t figured out yet: voice actors.

Each of the 10 missions requires a short briefing, done by different characters at different times, as well as some initial dialogue between your wing mates at the onset of each mission. I expect I’ll need about 5-6 different voices: 2 or 3 for the briefings, and 3 for the pre-mission banter and chatter. Once I’m finished tweaking the last remaining spaceship models, I’ll begin scripting out my missions in detail to determine exactly what I need.


Powering Through Problems

Game dev isn’t easy. No one can deny that it’s incredibly rewarding, but there are also moments where sheer frustration will make you want to throw your PC down a flight of stairs, or out a window because the stair violence doesn’t convey how you really feel. Taking breaks is not a bad idea, but the game will never be finished if you continually set it aside or refuse to pick up your project again out of frustration from a temporary lack of progress.

The real issue is that problems like these can be very demotivating. It’s hard to see past a problem until you’ve fixed it. In my experience, the majority of game dev problems can be placed in one of the following categories.

  1. Technical problems: “I don’t know how to implement X.”

    This is the most common category of problems that a beginner will face. It’s also the most challenging, both from a technical perspective (because you’ll often have to learn something new that is non-trivial), and from a personal perspective (because it’s frustrating to see a lack of progress on something so important to you). These kinds of problems always have a solution — there’s always a way to implement something, and knowledge can always be acquired. This is a fundamental truth, and don’t let anyone tell you otherwise. If you lack the knowledge, get it. Take that extra linear algebra class or buy that GPU programming book. If you possess this level of commitment to your projects, nothing can stop you from finishing them.

    The other alternative is to find resources online. Need a collision system that supports concave geometry, but don’t know how to make one? Someone else probably does, and it’s most likely online for others to use. (I’m a firm believer that you should do everything yourself at least once, so try to aim to understand code that you download, if possible.)

  2. Design problems: “I don’t know what approach to take/feature to develop.”

    I’ve had entire projects come to a halt because of my inability to make design decisions, or because they got out of hand. There are two strategies I’ve generally embraced when I can’t make up my mind:

    Stay away until I’ve made up my mind. This is a pretty good approach. I certainly don’t want to end up in a situation where I continually change my mind and keep re-implementing things as a result. If I’m not sure about something, I just let it sit for a while. The better choice will eventually become clear.

    Just run with one of them. If it’s not a very important decision, I’ll often just choose arbitrarily. The key here, though, is to make sure you stick with your decision so you don’t end up wasting time flip-flopping in the middle of your coding session. Make a decision, even if it pains you. And that’s final.

    I should point out that you could spend forever designing a game or making decisions about features. The point of “just running with one of them” is to avoid wasting time philosophizing about what might actually be a really trivial thing. When deciding which of these two approaches to use, try asking yourself: “Would my players really care?” If you think they would, then maybe sit on it for a while.

  3. Debugging problems: “I don’t know why my game does/doesn’t do X.”

    “Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”

    Brian Kernighan

    This is another bad one. Debugging is often a very painful experience, but the single best piece of advice I ever received regarding debugging was this: “Know your data”.

    If something doesn’t work properly, don’t just stare at your code and think about it. If thinking was enough, you wouldn’t have run into the problem in the first place. Print out some useful information. Get your debugger going and watch those variables. You’re only going to get so far without these tools, and by using them, you’ll find that you’ll solve your problems a whole lot quicker.

So clearly, there is no shortage of issues one can face. But, successful individuals power through these problems because they’re committed to seeing their vision come to life, and they know how to meet a challenge head-on. I encourage you to do the same.