Tuesday, December 29, 2009

Abstracting XACT 3D Audio

Today I worked out the most of the major kinks of getting positional audio working in Space Combat Sim. Well, I guess it's yesterday now since it's 12:45 AM and I finished sound at about 6:00 PM, but I digress.

My main experience in audio middleware has been working with FMOD and FMOD Ex. Both versions of FMOD are extremely powerful yet very easy to use. If I were doing this project using C++ I would not hesitate to use them. But I'm not using C++. Instead I'm using XACT, Microsoft's Cross-platform Audio Creation Tool.

Overall XACT is somewhat less powerful (no module support, no enviornmental effects, less portable etc.) but it's still reasonably simple to work with and supports the features I'm interested in. Specifically I want to support panning and fading of sound based on the position of the object producing it and I want to support doppler shifting based on how fast the object is moving.

Despite XACT being simple it proved to not quite be simple enough to use directly with my game objects. Ideally what I'd want to do is be able to associate a sound with an object then start, stop and alter it without having to worry about stuff like which specific sounds should play and so on. Sounds kinda like FMOD Ex's method of dealing with channels and voices independently eh?

The system I have now is a step in that direction but isn't there yet. For now I'm sticking with it since it works and, for the most part, sounds in Space Combat Sim are really simple so I don't need anything more advanced. My audio class stores an array of some arbitrary number of so-called tracked sounds. Each of these contains a Cue which may or may not be playing, a magic number, and some additional state data.

When I wish to play a sound that will loop, (and therfore need to be stopped manually,) or that I just want to keep track of because it's long, I specify a flag in my PlaySound function that it should be added to the tracked sounds. PlaySound will then choose a slot in the tracked sound array and replace its cue with whatever I wish to play. The PlaySound function then returns a handle, made by mashing the sound's array index and magic number together. When I decide to stop or alter the sound I simply pass the handle to access it. The index and magic number are extracted and, if the magic number matches the one in the tracked sound, the operation is performed on the Cue object.

How does this help? Well, by using a handle with a magic number I can eliminate the possibility of accidently messing with a Cue instance that has been squelched due to a more important/louder sound starting. Howzat? The magic number. My audio class is implemented as a GameComponent and is updated every game tick. If it notices a tracked sound whos Cue has stopped for whatever reason it will increment the magic number and null the Cue reference. If an operation were to be attempted on the, now null, Cue nothing would happen since the magic number has been changed. The only requirement here is to keep the number of magic numbers high enough that numbers aren't recycled until after they're no longer in use, otherwise very hard to diagnose bugs could appear.

Of course now that I've had things working for a while I've learned better ways of doing this which I might try out later. Particularly removing the need to track handles and send position/velocity updates manually from the object playing the sound. But, for now, this is the way things work in the project.

Monday, December 28, 2009

Another Late Entry

So here's yet another late entry. Once again, sorry for not keeping to my "at least once a week" schedule. This time I don't really have an excuse since school is finally over for Christmas and New Year.

What's happened? Well, lessee...
  • Collision detection is finished
  • Damage model is finished
  • Demonstrated the project to the rest of the 3rd year class
  • Wrote up some extra documentation for the faculty's benefit
I ended up ditching one of the collision test elimination methods I mentioned previously. Testing the objects in game, hierarchically (i.e. test a group to eliminate all related objects) added complexity that cost more than the benefit of eliminating a few collisions early on. Additionally a commonish edge case makes the algorithm design slightly hairier than my initial plan which was to use a breadth-first search. The AABB of each group of objects on a given level in the hierarchy would be tested, any non-overlapping branches would be eliminated from further testing. Collisions would then be fired for overlaps between objects at the lowest level of the hierarchy. Astute readers might see a potential problem here.

Collidable objects can be attached to other collidable objects objects across different levels in the entity hierarchy. Because of this collisions can occur at different levels of the hierarchy. In fact collisions can even occur across multiple levels in the entity hierarchy. For example, a fighter's gun can touch another fighters hull and the attached wing. This has to be taken into account. The additional complexity, during my testing, amounted to more CPU work than simply testing all object AABBs within a spatial hash bucket without grouping them.

A plausible compromise would be to use the grouping only as a first-pass (i.e. whole group) method of eliminating collisions. This would probably give the best bang for the buck since group parents are easy to find (removing the pain of implementing breadth-first with the current entity storage system, a giant array) and, in the case of capital ships, a LOT of collision tests can be eliminated at once. For now though, this solution doesn't exist. I'll probably add it when I have the time.

Speaking of time, the previous sprint (number three for those who care) finished seriously behind schedule with an estimated 50ish hours of work leftover. For comparison purposes, the faculty expects a bit less than that amount of work to be done per person per sprint.

I am now confronting the pile of unfinished work and attempting to catch up to where I originally wanted to be at the halfway point for the project. This particular sprint, currently set up to occupy my between-semester vacation time, I decided to focus on eye and ear candy in addition to the neglected work from sprint 3.
  • Positional audio
  • Particle effects (running on the GPU no less, though I got the original code/concept from Microsoft's sample code at the XNA Community site)
  • Lighting, at least some basic global lights and hopefully an initial shadowing model
  • Fixing an amusing, but mysterious, off-by-one-frame bug in the view (or world) matrix of some objects
I'll talk about my plans, and completed development, for positional audio and particle effects in the next couple days this week. Perhaps I'll have something screenshot worthy soon...

I'll also try to find some time to get another Content Pipeline series entry written up.

Saturday, December 5, 2009

Apologies for the delays

As you can see I just released Part 2 of my series on custom content in XNA Game Studio. I think you can also see that I haven't maintained my promised weekly schedule of blog updates.

It's now nearing the end of the semester and things have gotten quite hectic. The only major issue is that my deadlines are tending to arrive in bunches with assignments coming due all at once so I have to work like mad on non-project stuff then, work like mad on the project until the next wave of assignments hits.

So, what am I up to now? Glad you asked! I'm working on turning my game into something that actually resembles a game. This means adding the ability to target, shoot and kill other players as well as a small host of other features. How many?
  1. Create teams
  2. Assign players to teams
  3. Create spawn points
  4. Spawn players at spawn points
  5. Timing for when players should spawn
  6. Collision detection
  7. Rules for damaging fighters
  8. Weapon targeting
  9. Kill scoring
  10. Improved network code

I've finished 1-5 already. They're not thatinteresting to talk about at this point since they don't have much effect at this phase of the project. Most of the real work in getting team assignments, spawning etc. working well will happen in the next couple development phases. What I'm doing now though is feature number 6. And it's a bear of a feature.

Collision detection, in my case, is really about detecting when two objects overlap. A lot of effort is required to figure out whether or not two objects, of any shape or size, are touching or overlapping. So most of my efforts have gone into, first, minimizing the number of objects to be tested, and second, simplifying the math required to find overlaps.

I'm currently using two general tricks to eliminate objects for testing. First, objects are generally defined as groups. For example a fighter isn't just a fighter. It's a hull, wings, thrusters and guns. Capital ships are many pieces of hull and many many guns etc. This allows me to eliminate a large amount of tests very quickly by asking "are these objects close enough to have a chance of overlapping?"

Second is what's known as spatial hashing. This is a way of finding the answer to "are these objects close enough to have a chance of overlapping?" quickly. The basic idea is to take a point in space and assign it to a bucket based on its location. Each bucket represents an area of some size, let's say 50x50x50 units. So if you divide an object's position by 50, you now have the number you need to assign the object to a bucket. All objects that occupy the same bucket get tested for collisions.

Now that we have the objects to test we could just test every object against every other object. e.g. if a bucket has ten objects the result is every object being tested ten times or 100 tests. However what we're really doing is testing pairs of objects. We don't need to test if object A is hitting object B if we already checked object B against object A. We also don't need to test an object against itself. So what do we test?

1. Test the first object against the next nine
2. Test the second object against the next eight
We don't test aginst the first, it's already been tested in step 1
3. Test the third object against the next seven
The previous two steps tested this against the first and second objects
4. Etc.

This means we only need 9 + 8 + ... + 2 + 1, or 45 tests... which do what?

Yes, we're finally at the point of actually doing collision detection. There are two general choices here. First is doing perfect collision detection for the object. This involves a lot of tests for even relatively simple objects, so I'm not doing it. The second choice is to test simplified volumes for overlap. This is what I'm doing.

In my case I'm using two kinds of boxes. First is the axis-aligned box (AABB.) The AABB is useful since I can rapidly eliminate non-collisions by simple value comparisons. The AABB for an object contains the bounding box all objects that are attached as well as the object itself. This helps in eliminating many collisions at once.

This second box is shaped so that it covers the object volume as accurately as possible. This one is used for making the final decision of whether or not two objects are colliding. The math for doing, known as the separating axis theorem, this is somewhat more complex than that for the AABB but not by much. In fact the simple test for the AABB is a special case of the same theorem.

This picture shows all of the boxes involved in a collision test (it also shows a tool I created last week for the purpose of setting these boxes up XD) The AABB is orange and the actual collision volume is yellow.

Sorry about the vagueness of the fighter, it's a test model and I haven't set up lighting for the game yet.

Tuesday, November 24, 2009

Non-Trivial Custom ContentProcessor - Part 2

If you're reading this for the first time you might want to check out the Introduction and Part 1 first.

The next step taken by the XNA Content Pipeline is to process the data produced by the content importer. This is done by the aptly named ContentProcessor classes. These classes are responsible for pretty much anything that happens between the content being loaded (via ContentImporter or ContentReader which I'll discuss an a later article) and the content being used.

ContentProcessors are used to massage data into a format usable by an XNA project and/or to load additional content. For example a model processor will load textures and shaders that the model is rendered with. So processors usually run when importing content into a game project or when loading imported content as part of game execution.

As I mentioned in Part 1, my custom content importer simply converted the raw XML input into a nice tree that can be worked with by the processor (using the .NET System.Xml family of classes.) Now this XML has to be turned into something meaningful to the game. This obviously leaves a lot of work to the content processor.

As I mentioned before this is the structure of the XML:
  • Group (document element)
  • One or more entity elements. Each element defines how it's related to the others. In-game this is used to build an n-tree of entity objects with one entity as the root.
  • One or more property elements for every entity. The meaning/use of these properties is dependent on the type of entity.

What we'll do in the processor is iterate through all "entity" elements in the document, read in the data we care about, and add each to a content data class called EntityGroupTypeContent. The code to do this is relatively straigtforward and uninteresting. I'm sure it can be improved but at the time I wrote it my main intention was for it to work.

outputGroup = new EntityGroupTypeContent();
XmlElement top = input.DocumentElement;
foreach (XmlElement entity in top.GetElementsByTagName("entity"))
{
// Read in entity attributes (convert from string as needed)
string name = entity.GetAttribute("name");
string parentName = entity.GetAttribute("parent");
string entityType = entity.GetAttribute("type");
string renderObjectName = entity.GetAttribute("render-object");
string[] rawPosition = entity.GetAttribute("position").Split(',');
Vector3 position = new Vector3(Convert.ToSingle(rawPosition[0]),
Convert.ToSingle(rawPosition[1]),
Convert.ToSingle(rawPosition[2]));

string[] rawOrientation = entity.GetAttribute("orientation").Split(',');
Quaternion orientation = new Quaternion(Convert.ToSingle(rawOrientation[0]),
Convert.ToSingle(rawOrientation[1]),
Convert.ToSingle(rawOrientation[2]),
Convert.ToSingle(rawOrientation[3]));

// Read entity properties
Dictionary properties = new Dictionary();
foreach (XmlElement property in entity.GetElementsByTagName("property"))
{
string propertyName = property.GetAttribute("name");
EntityGroupPropertyContent propertyData = new EntityGroupPropertyContent(property);
properties.Add(propertyName, propertyData);
}

// Add the entity
outputGroup.AddChildEntity(name, parentName, entityType, renderObjectName, position, orientation, properties);
}

Notice the lack of exception handlers on Convert.ToSingle. If something goes wrong here the exception percolates up to the content builder. When this happens the exception is recorded as a build error in Visual Studio. Also notice the EntityGroupPropertyContent instantiation. It's pretty important but talking about it brings up a lot of discussion irrelevant to this entry. I'll talk more about EntityGroupPropertyContent in Parts 3 and 4.

Next we have to validate the data that was loaded. The game expects the following conditions to be true:

  • The group has a root entity. Its parent entity is undefined
  • There is only one root entity.
  • Entities within the group are only related to eachother, not other groups
  • Entity properties are valid (notice valid here isn't defined yet, stay tuned :)

Since we didn't verify these conditions in the importer they have to be checked now. This way any errors in the content will be caught by the compiler and show up as build errors. Trying to catch these errors later would result in them crashing the game.

I'll get into validation with Part 3.

Sunday, November 15, 2009

BOOM!

Nobody can resist explosions.

Non-Trivial Custom ContentProcessor - Part 1

This is part one on my series on writing a non-trivial custom content processor for XNA Game Studio 3.1. If you want you can read the introduction of this series for useful background information on why I went about writing a content processor.

Besides the tutorial and samples I mentioned in the introduction MSDN also has a very nice tutorial on how to create a complete content processor.

A complete content pipeline extension project consists of the following parts:
  • A content importer
  • A content processor(s)
  • A content data class(es)
  • A content writer
  • A content reader

Each piece is a distinct step in the process of importing and loading content in your project.

The content importer is a very simple object. All it has to do is open the basic content (image, model, game data etc.) and parse it enough that it's usable by the content processor. Since I originally chose to use XML my importer only needs to open the file as an XML document. If you're using XML you might want to test the document against a DTD to save in sanity checking code in the processor.

Here's the importer:

using System;
using System.Xml;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;

// Entity group type specs/annotations are in XML format
using TImport = System.Xml.XmlDocument;

namespace EntityGroupProcessor
{
///
/// Basic entity group type importer. Entity group types are always in XML. All this does
/// is load the file.
///

[ContentImporter(".ent", DisplayName = "Entity Group Importer", DefaultProcessor = "EntityGroupTypeProcessor")]
public class EntityGroupTypeImporter : ContentImporter
{
public override TImport Import(string filename, ContentImporterContext context)
{
XmlDocument document = new XmlDocument();
document.Load(filename);

return document;
}
}
}

Notice the line
[ContentImporter(".ent", DisplayName = "Entity Group Importer", DefaultProcessor = "EntityGroupTypeProcessor")]
The first part ".ent" specifies the extension of the file that this importer processes. This allows Visual Studio to automatically use this importer when content with the extension of ".ent" is added to the project. The second part specifies the name of the importer as it appears in Visual Studio. The third, and most important part, names the class used to process the output (in this case an XmlDocument instance) in the next step.

The bulk of the code, at least in my case, ends up in the content processor and the content data classes. Stay tuned for Part 2 where I get into the basics of the ContentProcessor and content data classes.

Neat effect

I've been trolling around for information on how I could make a better looking beam weapon. One idea I had was to render them as volumes instead of flat lines. In my research I stumbled across Graphics Runner who has some neat tutorials posted on rendering volumetric effects on his blog. Check 'em out.

I'm likely to not use 3D textures like in these blogs so that I can save on resources. Instead I hope to derive the thickness of a particular section of a beam from the alpha value of that section of beam.

Stay tuned for followups, and Part 1 of my custom content processor series.

Saturday, November 14, 2009

Non-Trivial Custom ContentProcessor - Intro

The network component is finally done for this sprint. Yay! And I have a project that compiles for the X-Box 360. Yayy!!

This past week has been interesting so far since I found that my initial solution for batching objects for drawing was impractical when it came to the critical stage of actually doing the batching. So I had to tear it out and start over. The new solution is quite clean and has an added advantage of reducing the amount of data stored for render objects. Only one set of render data is stored no matter how many objects that use it exist. But this change started a cascade of extra changes which has led me to begin developing a custom content processor for XNA.

I'm working on generalizing the code needed to spawn in-game objects. My original method of loading in-game object data was to load a model and create one in-game object for each mesh that makes the model. The properties of the in-game objects were encoded in the names of the meshes. Initially this worked surprisingly well. The biggest advantage is that I didn't have to spend time on tool development and could focus on getting the game working.

There are, however, four problems.
  • No two objects defined in a model can have the same properties (due to mesh names having to be unique)
  • There's no easy way of creating a deep tree of attached objects (e.g. a capital ship with turrets)
  • Using names severely limits the number of properties that can be defines
  • Not all objects need to be models (e.g. beams and bullets)

My solution is to split off loading of graphics and defining in-game objects. Graphics are loaded and tossed into a pool for later use. Each graphical item has a unique name which can be used to reference it. Once the graphics are loaded the game then has to load information on how to create in-game objects using the graphics.

This is where the ContentProcessor comes in. My current plan is to create a custom XML document which defines a tree of in-game objects and their properties. Each file lists a set of in-game objects to be created. Each object is a single block in the XML file defining the following.

  • What appearance the object has (references a loaded bit of graphics)
  • What the object's type is
  • What the object's reference name is
  • What the object's parent's reference name is
  • A set of properties specific to the object's type

In order to keep the code for the game clean this XML data is to be loaded using a custom ContentProcessor. There are at least some resources out there on the internet including this (tutorial 21, PDF Alert!) and this which provide some nice sample code. I like the first since it distills the process down to its simplest form. Useful for learning, but it doesn't cover all the nuances I need for what I'm doing.

Stay tuned as I post more details on the content processor.

Monday, November 9, 2009

What to do... what to do... what not to do

Earlier in this blog I mentioned that Space Combat Sim is being developed using at least the trappings of the Scrum methodology. I say the trappings because certain aspects of the method don't apply because A, I don't have a team to hold meetings with and B, the Scrum methodology seems to assume a 40 hour week of five 8 hour days. This is great for regular software! I love having 8 hour days. They certainly beat 10 and 12 hour days (grumble grumble.)

But I digress... one part of Scrum that we do use is the product backlog. It's essentially a glorified to-do list. A huge set of items to be created for the project with estimates for how long they'll take. Work from the list is batched together in units called sprints. The expectation that over the length of the sprint all of the selected tasks are to be done. In the real world I believe sprints are one or two weeks long, in school they're about a month. Anyway, if the to-do list for the sprint isn't empty when the time is up then there's a problem. Fortunately, due to the way Scrum works this problem is noticed as the sprint ends which is usually well before the project is to be delivered. This is the good news.

The bad news is that, in my case, I have around 40 hours of work left to accomplish in one week. We're expected to put in about 12 hours a week individually. As I hinted before, that's a problem. At this point in the project I can defer some of the work to later sprints if need be. But first, prioritization.

The critical items (not started):

  • X-Box 360 support
  • Beam weapon rendering
  • Beam weapon test
  • Capital ship gun turrets (guns which can independently shoot targets)
  • Targeting cursor/crosshairs

The incomplete items:
  • The targeting computer
  • Weapon status display is working but ugly
  • Smoke/flames/tracers (barely started)
  • Sorting/grouping of graphics by how they're to be drawn
  • The network code (still untested)
So now that I have what I want to do I need to decide what I need to do. My primary goal for this phase is to get the fundamentals of multiplayer working and to get the game on the X-Box. I also want there to be enough supporting code done that I can get shooting and killing other players working in the next sprint.

This leaves:
  • The network code
  • X-Box 360 support

This cuts the amount of work left from ~40 hours to 10.5 hours or so. Much better.

Sunday, November 8, 2009

I can haz multiplayer test???

Over the last week I've been working on getting the network code implemented for Space Combat Sim. This is one of the most critical parts for the game since without it there's no way for the game to support multiplayer over Live.

This has turned out to be painful in one place which I didn't expect, the game's rules system. When I first created the game I've been working with a basic startup sequence which creates a bunch of fighters and assigns a local controller (i.e. your X-Box 360 gamepad) to one of them leaving the rest uncontrolled. I originally wanted to create a fairly simple stub and hook joining players to other objects arbitrarily. This didn't work.

The problem is that when a player joins they initially know nothing of the game's state. This includes which fighter they're supposed to control. If I just assigned one arbitrarily on both sides the results would be inconsistent. Each player would think that the other is attached to a different object. Worse, two players could be trying to control the same object. This meant I had to implement code which runs on the game's host only to assign a player to a specific in-game object. In addition it had to support the player being killed and assigned a new object of (possibly) a different type than before.

What occurs now is this:
  1. The host starts up a game session and starts playing.
  2. Some other player joins the game session
  3. The host notices the joining player and asks the rules system that a new player is in the game. This is where team balancing etc. would occur.
  4. In the mean time the joining player is watching the game without participating.
  5. The host notices that there's a player without a ship (i.e. the joining player.) The host finds an appropriate place to create the player and adds them to the game. In addition the host lets all players know that one of the players has just been assigned a new ship. This is where re-spawn rules would go.
  6. The joining player notices that they've been assigned a ship. Since it doesn't exist on their machine yet they create it and attach their local controller to it. The player is now in the game.
  7. If there were other players they'd also notice a player has been assigned a ship. Since it also doesn't exist for them they'd create it as well.

I've omitted some housekeeping but this is, at least for now, how players joining and being assigned ships is handled. What's left is testing. Since I only have one PC on hand I'll need to do that at school.

Monday, November 2, 2009

Oink

Normally in these entries I drone on about some random technical crap that is not terribly interesting but last week I didn't actually do any technical crap... so I don't have anything to talk about.

Instead, last week, I was down with a nice little case of the swine flu. Not fun... but not the worst disease I've had by any strech however. The only thing that really sucked was the night I didn't get to sleep (and fitfully at that) until about 2:00AM because of an irritating, persistant cough. That and the fact I had not one, but two exams right in the middle of the week I was sick. Oh yeah, that fever was fun too...

To anyone reading... try to not get the swine flu, it's not the worst flu, but it still sucks.

I'll be posting about my adventures in getting communication between players working later this week.

Sunday, October 25, 2009

And Now for Something Completely Different

For the last week or so I've been working on getting weapons firing. This included a lot of architectural crap which I mentioned previously. Weapons are working quite nicely now, though bullets will keep flying off to infinity forever currently. The other issue are some obnoxious visual defects whose cause is a mystery currently.

Weapons have some basic rules which govern whether or not they're allowed to fire. First, the gun must have ammunition. Second, the gun must be ready to fire. Every weapon has to rest briefly between shots. In real life this is because it takes time for a new bullet to be loaded into the chamber and for the firing pin to be cocked. Finally, the gun must be cool enough to fire. I decided to take a page from the Mechwarrior games here. Every weapon produces some amount of heat. When this reaches a maximum the player must wait for the weapon to cool off again. Effectively the player's firerate is dramatically cut when the weapon overheats. Between heat, and limited ammo, the player should be encouraged to fire in controlled bursts for maximum damage.

Today I decided to switch gears. Since this phase is supposed to produce the first multiplayer implementation I started coding in Live support.

XNA provides network related code in two major chunks. First, GamerServices, which is where most of the Live service code lives. Second is Net, which handles all the grunt work of communication between players.

The first thing I figured I should tackle is allowing the player to sign in to the Live service. This is done through a program/widget built in to the X-Box 360 called the Guide. As it turns out this required about three lines of code. Two for some setup and the third, which does the real work.
Guide.ShowSignIn(1, false);
Seriously! That's all that's needed to fire up the Live signin screen. The 1 states that only one player can be signed in for this game. The second indicates whether only online Live profiles can be used.

Next task is to get hosting and matchmaking up and running. Thusfar it looks pretty simple. The hard part looks to be the actual work of communication between players.

Friday, October 23, 2009

This week was umm.... productive?

So anybody reading this might recall me saying I might have more information on how the project is going by this week. The good news is that I did get some stuff, namely, guns actually firing bullets, working. The bad news is that's all I got done this week and that was waay back on Sunday/Monday.

This week has been rather nasty due to other coursework supersceding the main project. Worst was the database course. The project is fairly striaghtforward. Everyone is/was to work in groups of 3-4 people and produce three or four programs that interact with a database tracking the hours of some hypothetical consultants. Very straigtforward... also very boring. The main twists were the intentionally vague specifications and the fact that part of the data, namely the client information (people buying consulting services, not the technobabble meaning of client), had to be on a MySQL database while everything else had to be on SQL Server. That meant a modest amount of extra work. Three/four client applications plus two databases. A nice little chunk of work to disrupt the momentum I had built up for the main project.

While I was definately productive on the database project (finishing my parts, the server and two of the clients, with about three days of work) I got barely anything done on the main project.

The work I did do was to fix/improve object composition. That is I can now make an object in-game out of many smaller objects. For example, a fighter can be made of a hull, two wings and two guns. This is all working well now. The underlying code isn't all that interesting to talk about so I'll refrain from doing so.

As I said before I also got firing bullets working. This really only required the addition of an extra phase in updating the game's state, known as the spawning phase. Any objects that are to be created are placed in a queue. At the end of the update they're created and added to the game. What I want to do now is add a few more rules governing when they're fired. I also need to add the capacity to remove expired objects from the game. Otherwise it will get quickly bogged down by thousands of bullets screaming off into the infinity of deep space.

Thursday, October 15, 2009

Another Nasty Bites the Dust

As I mentioned in previous blog entries. This development cycle has been far more involved than the first. Mostly due to the fact that it involves a great deal of interdependent parts which all have to be developed at roughtly the same time. In this case I'm getting controls shared across multiple objects, object relationships and physics all working at once to support movement by simulating thrust.

I've figured out most of the math for the physics but it took several hours of effort to learn the basic math enough to even start. It was a few hours ago that I realized I'm starting to seriously diverge from what I want to be working on. What I'm trying to do is make the game look believable. I didn't originally intend to make the game accurate. *forehead slap* Out goes the physics, back to the drawing board.

My new method of simulating thrust is essentially a cheat. I'll just have thrusters appear to turn on and off in relation to the controls. Instead of simulating the behavior I'm simulating the appearance of the thrusters. This is far easier to build saving probably a day or more of work implementing it plus who know how long in getting it to be fun.

Wednesday, October 14, 2009

The Second Nastyish Problem

I now have the critical part of the batching portion working. Objects are decomposed to their smallest constituant parts which can then be rendered in groups. The actual grouping is still to be done but that's relatively straigtforward. I want to be able to measure how slow/fast I'm making my game's graphics before diving in to some hardcore algorithm hacking.

The next nasty problem for me to deal with is the issue of getting the game's controls working across multiple objects. For example, the player's fighter can be composed of a hull, a few guns and several thrusters. Input would need to be affect only relevant objects without causing weird side-effects in the others.

This problem is half solved currently. A single controller object, which is responsible for receiving and processing input from somewhere into actions. Any entity can attach itself to the controller and alter its state based on input from the controller.

A thruster, for example, can decide whether it should turn on based on whether the controller is saying "turn left" or not. This nicely addresses the issue of getting weapons firing in groups, thrusters firing appropriately and so on.

The second half of the problem isn't so easily resolved however. I also have to get state data from the enties that are attached to the controller back to the controller so that they can be sent to the network. My other option is to send complete object state data directly from each entity to/from the network, however that defeats the original purpose of the controller.

An additional problem I didn't quite want to solve this early, but have to, is getting the in-game physics working. This is due to my choice of controlling fighters via believable application of thrust and counter-thrust.

Plenty to mull over. I probably won't have a solution until the end of this week at earliest.

Tuesday, October 13, 2009

First Nastyish Problem Part 2

A nice bit of bone-headedness on my part. I spent around 40 minutes scratching my head trying to find how to get the VertexBuffer from ModelMeshPart so I could render it... only to find that it's in the ModelMesh that owns it. D'oh.

It really helps to look in the right place.

Monday, October 12, 2009

First Nastyish Problems

Now that the first phase of getting the basics up and running is done I'm starting to confront the nastier issues of getting this project to resemble a game that might, some day, be fun to play. Not to mention fleshing out the game's internals so they function as I originally intended them to.

The focus of the effort for the next couple days is on getting the graphics system batching objects to be rendered correctly.

The concept behind batching is to group together all similar objects to the video card in one big chunk. The hard part is that my graphics system is meant to contain very different types of objects (e.g. both 2D particles and 3D models) in a particular scene.

Technical crap below
My solution is to build two interfaces. The first, known as IRender, represents a complete drawable thing, for example a laser cannon on a fighter. This exposes objects which have the second interface, IRenderPart. These represent a piece of the whole object which has its own special appearance. For example an IRenderPart could be a glowing tip on the laser cannon and a second could be the actual body of the cannon.

The IRenderPart is the critical piece for batching. The IRenderPart exposes instructions on how it is to be drawn. The rendering enging groups all IRenderParts with similar instructions and draws them all at once. This, in theory, saves time used in sending different sets of instructions to the game console's video hardware since each set of instructions only needs to be sent once.

The big advantage of using interfaces is that they allow the graphics engine to see only the information it cares about to group the objects without having to worry about what, exactly, those objects are. This addresses the nasty issue of handling the variety of visible objects in the game that need to be drawn.
End of technical crap

Now it's down to implementing the changes. I'm approximately 25% done. In addition I need to implement a performance measuring harnass in the game so that I can perform adjustments to the game's code and know exactly what effects they have on the game's speed.

Thursday, October 8, 2009

The Cockpit

Today I'm going to talk about the cockpit in the game as it is right now. When you're playing you see everything as if you're the pilot sitting in the cockpit of a starfighter. What I hope to do is display all information relating to the state of a player's fighter as part of the fighter's cockpit. This dictated that the cockpit be one of the first things to be coded since it will be critically important to the player's in-game experience. The fundamentals (code-wise) are there now but they're not much to look at currently since I don't have much of any artwork done.
Cockpit test

I was motivated to do the cockpit this way by a pet peeve I have with space combat games like, for example, Freespace. The in-flight displays are just sprites, they're not part of the fighter! While this is primarily an aesthetic complaint it's something I feel is a major detriment to the immersion factor of games that often purport themselves as simulators.

There are a number of challenges with building the game's displays this way. Foremost is layout. The displays need to be placed such that they make sense and all of the information on them can be read easily. Also I need to decide how many displays there are, and what each should contain. Finally, I need to decide if there are to be any controls which change a display's appearance, for example switching between text and visual diagnostics. And, just for extra spice, the layout must fit completely within the "title safe" area which is the area visible on all TVs. If the displays don't fit then they'll be cut off for some players on the X-Box. Oops.

Currently I'm drawing inspiration from the F-16 fighter for a general layout of the cockpit. The F-16 features a HUD and three large displays for various tactical data.
F-16 Cockpit
In the game the cockpit will be somewhat similar. The HUD will display navagational and targeting data. The left screen will display sensory data and weapon status (e.g. ammo.) The right screen will display diagnostic data (i.e. what is, and what is not damaged.) The central screen will display tactical data. Additional information, such as score, is still displayed as text and graphics on the screen outside of game space.

Friday, October 2, 2009

Perhaps we have a muse

The first few builds of the project have been finished. Nothing too interesting to look at but you can fly around in space and the cockpit (but none of the information it should display) renders. After some initial testing with the demos I've downloaded I've decided that the Nuclex framework fits my needs better than Titanium XNA. It's a much more minimal product in that it's more of a toolbox than a game engine but the quality of those tools is excellent. Props to you Cygon!

For the past few days my girlfriend and I have started watching Batman: The Animated Series. One of several excellent cartoon series released by Warner Brothers in the mid ninties. I'm still impressed with how they managed to create such a surprisingly mature cartoon that was still accessable to children.

"But, what does this have to do with the game?" you might ask... One feature with Batman that stood out for me when I first watched it, and stands out even more now, are the amazing Art Deco images that pervade the entire series. I love the dichotomy of the style. With the right execution it can look both elegant and inviting in one moment then evil and terrifying the next. It looks both futuristic and anachronistic at the same time. Art Deco is an incredibly rich artistic style which I'd love to explore within the game. The future of the past if you will.




Just imagine something like this locomotive as a huge space-faring battleship... yeaaahhh :)

Sunday, September 27, 2009

About the Project...

I've always developed games as a hobby since I was a kid. I started with text-based games in QBASIC when I was about 7. Since then I've made shooters, puzzle games, tools and other stuff for my own amusement and the amusement of my friends in school. When I found out we had to do a large software project over eight months in our last year of school I immediately wanted to do a game.

The project, currently untitled, is a space combat simulator game in the same vein as the Freespace series and X-Wing series of games. The game is planned to be set up something like Quake 3 with one player hosting a game session and other players joining. Game types would be free for all (deathmatch, keep-away etc.) and team-vs-team (capital ship assault, etc.)

At this point I've finished enough of the initial planning and school-related junk that I can actually start development. I'm using XNA Game Studio 3.1 foras a development framework for the project. This provides a nice multi-platform base to work from and a good collection of documentation and sample code to boot. I'm mulling over using an existing graphics engine or rolling my own at the moment.

There seems to be a decent selection of graphics engines aimed at the XNA environment out there however most of the ones I've looked at are specifically aimed at rendering terrains which isn't particularly helpful. I've narrowed my list down to TXNA and Nuclex. My choice now comes down to how easily I can exploit the engine for my vile purposes and, if I can't whether it'd be easier to tear the engine apart or code what I need as I need it.

I'll be making my decision later this week.

About Me...

Hi, I'm a college student currently in the final year of my program at Conestoga College. One of the tasks we have to complete in order to graduate the program is to complete a software systems project over the next two semesters. For my project I chose to develop a multi-player action game on the XNA platform.

This blog will be about the various challenges that I encounter during the development of my game project. This includes coding issues, sceenshots, school-related crap and anything else I feel like blogging about. I intend to make a post on this blog at least once a week.


Besides this blog I'm also an occasional poster on the XNA community under the name "Dan Dan Dan Dan"