Monday, May 10, 2010
Space Combat Sim Postmortem
I'm basing my postmortem on those typically found on Gamasutra. If you haven't read one do so, they're quite eye-opening.
What Went Right
1. Tight, focused scope
Game projects can be massively complex. Particularly when they're 3d action-oriented online ones :). Most of my early projects started out relatively simply but grew into complex behemoths due to "wouldn't it be cool if" syndrome. For example a simple game where you killed enemies before they could leave the screen evolved into a vertical shmup with procedurally generated levels.
For Space Combat Sim the scope was set in stone from the beginning. The project would be a multiplayer game combining elements of X-Wing, Quake 3 and Counterstrike. Tools were only to be developed for the game if they were absolutely necessary (ignoring content pipeline extensions only two tools were made, one for creating hit boxes and one for creating effects.)
With the scope in hand I was able to set out a series of broad goals which defined how the game was to be built from the ground up. These broad goals were converted into a 24 page document describing all of the required features of the game (required for the course.) That was then turned into the detailed list of tasks that needed to be done to produce the game. Making the game was then simply a matter of finishing all of the tasks on the list. Since all time was spent exclusively on those broad goals the amount of wasted effort was minimized.
2. Continuous integration
Continuous integration means always having a working version of a project while it's being built. There may be missing features, and if it's a game it may look and play like crap, but it at least exists. One thing that always happens with software projects is scheduling issues. Feature creep, scope creep, unanticipated challenges or whatever, eventually something will cause a project to go off course. Having a working version means that even if the deadling is looming at least something is there for everyone to see.
In the case of Space Combat Sim, a lot could go wrong. I was challenging myself technically since I hadn't produced a 3D game before, nor had I produced a multiplayer game before. Except for a few occasions I succeeded in this goal. This was very helpful in keeping me from being too ambitious in coding features and forced me to break down overly lofty goals into more doable tasks.
3. Scrum-like scheduling
Space Combat Sim used a barebones version of Scrum, albeit with each cycle of development being much longer than specified. By dividing the project into sprints and assigning a set of real deliverables to be completed in each I was able to keep on task. The faculty's imposed limit of about 8 hours per deliverable also helped keep tasks from meandering and getting out of control.
What Went Wrong
1. Not enough time spent getting tools
The first four or five months of development time were spent building up the back-end code needed to support the first network session. A huge amount of that could have been saved if I spent that first month just looking at rendering engines and playing with them. No more shader development, effect tool development, etc. etc. in all about two months of work there. Sure, I'd still have to spend time on managing game objects and networking but that was kinda the point of the game. Instead I gave up after about two weeks of looking at tools, honestly, because it was boring.
2. Working solo
Especially in combination with making my own tools working solo made the game take a painfully long time to get done. It would have been quite nice if I could have focused more on object management, networking and gameplay while someone else took care of UI, loading, and other backend stuff. With only myself I generally had to focus on every task of game development which tended to result in polish getting short shrift.
The game's code is poorly documented in places, hacks abound and not all of the visuals that I wanted are in the game.
3. Continuous integration
Continuous integration has proven to be a double-edged sword. On one hand, having a working copy of Space Combat Sim all the time was motivating and helped reduce the impact of schedule slippage. On the other hand it made me midjudge whether a particular piece of the game's architecture was actually done or not. The area where this resulted in the most wasted time was in the game's startup sequence. The issue was that, while the game did indeed have space for its menus and loading sequence it wasn't really set up with its final usage in mind.
Having something that works, and having something that works correctly are different things. Continuous integration overall has been very useful, but at the same time it can cause one to do something that is expedient and fast rather than the correct solution suitable for the remainder of the project.
Conclusion
Overall I'd consider Space Combat Sim a modest success. I met my basic goal, which was to produce a multi-player combat game in space. My more lofty goals of having mission-oriented combat, style etc. weren't met due to time pressures though. The experience has definately been worth while and I learned a lot about actual project development through it.
Wednesday, May 5, 2010
Bad Demo, Good Demo
Bad Demo
The first presentation was to faculty and some industry representatives (fortunately their thing seemed to be anything but games.) It was originally going to be in a classroom setting but moved to the lounge in the student life center due to the number of people attending. The lounge, which happened to have one, maybe two, network ports. Both which were in use by other equipment... sigh. Without being able to play with someone all I could do was crash into scenery. Not much of a demo.
I was able to re-show the project in a lab, with a proper network, but the damage was done. My kingdom for Fraps... and the time (and people) to use it effectively. The fact I didn't have a fallback in case of network failure was a pretty major oversight on my part. Still that last minute venue change was really frustrating.
The most frustrating issue though was the fact the most vocal representative was most interested in how a project was supposed to make money. The fact he seemed more impressed about a group wearing suits than their actual project (which was quite slick) was particularly rankling. Why in the fuck are superficial details such as what the presenter is wearing even considered relevant? Caring more about clothing than the product demonstrated is not something to be proud of!
The impression he left me is that I could have run a pre-rendered video (not a recording of the game) and made up some bullshit about online gaming being worth billions and not been called on the fact I didn't even present a product. That would have saved a couple months of effort... At least the other members of the panel were willing to ask some technical questions during all the presentations.
Good Demo
The second demonstration was at the technology program showcase for the college. This was a 3 hour affair where a large number of people in the various technology programs at the school got to show off their projects. This time a lot more time was given to setup, last time there was a token effort in setting up a router which didn't work at all when used for wired networking. The project was set up on two PCs and running with proper Live accounts. There was some pain as some old bugs managed to magically un-fix themselves, and I didn't actually have the passwords for the Live accounts that were set up for the demo, but that got worked out early on.
The big lifesaver was having Heather (from Slime Cat Blog) and her sister to demo playing the game while I could talk about what it was and how it worked. They would fly around, shoot at each other, be silly, laugh and generally have fun. This attracted a lot of attention from the various people attending the showcase. It also nicely showed what the project was without me having to go into crazy amounts of detail describing how it worked. I'm glad they were there because a lot of the people coming to see the project weren't gamers.
By the way, if you're wondering how those photo****d textures turned out; here's a rendering of the three fighter types.
Not great but still decent for about 2-3 hours per ship I think.
Wednesday, April 21, 2010
More Spit and Polish
- The game join menu doesn't crash when no games are available
- The game join menu will poll for new games if none are available
- Beam weapons now do damage when swept through other ships
- All incomplete scenarios are have been disabled
- Fighters have photo****ed textures instead of default test patterns
- Minor damge model bugs fixed
- Thrusters flicker slowly enough to be noticable
- Sound effects fade correctly
Regarding the photo****: One thing I really wanted to do in this game was give the fighters a nice metallic look. Metal is shiny! But, if I add shininess to the game it gets choppy. Ugh. But I might have a solution. Rust! Patina! etc.
I want to avoid making the game a rusty-brown shitefest so I'm hoping to go for more of a tarnished silver/brass/bronze/copper look. If, later, I manage to get some decent shininess at decent speed I'll bring back the metal look I wanted originally.
Saturday, April 17, 2010
Spit and Polish
I've been making a lot of small tweaks to the game of late. My primary objective is to be ready for the project presentation which is coming alarmingly soon. After that I need to have an open demo at the school's Tech@Work event. The most noticable changes to the game are the addition of a semi-working server selection screen, and a lobby screen. These aren't all that interesting to talk about but they produced a spectacular number of bugs during development.
The other feature in the game is the menu background. Very minor when compared with stuff I talked about earlier but it has an amazing effect on how complete the game feels. All I did was randomly spawn objects (that look exactly the same as the ships but without all of the movement code) and have them move toward and past the camera.
Much better than plain old CornflowerBlue eh?
Saturday, March 20, 2010
Slightly late. Slightly different.
Today I added point lights to the game. These are nice for lights which come from a location and affect a specific, limited area. Great for more dramatic explosions, shooting and so on. Here's a pic
Lighting in Space Combat Sim is done using some fairly simple math. One topic covered in high-school geometry was the dot product. The dot product is a scalar product of two vectors. One property of a dot product is that, when it's produced from two unit vectors, its value is equal to the cosine of the angle between the vectors.
Why is that useful? Try shining a flashlight on a marble, or ball bearing, or basketball (anything round will do.) Notice that the brightest parts are those that face the light. As the surface of the ball faces away from the light it darkens. If you remember that old high-school math cosine is one for an angle of zero and zero for an angle of ninety degrees.
Cool. But this still doesn't say how light or dark a surface is... We need one more piece of data. The surface normal. This is a unit vector points straight off of the surface being lit. Let's express the direction of some infinitely far away light source with another vector. Remember what I said in the previous paragraph? The dot product of the two vectors is one if the surface is facing the light perfectly and zero if it isn't facing the light at all. Cool, eh?
This is the shader code for a directional light. It's a nice stand-in for some sunlight. Notice there's a little bit of extra work here so that it can render eight lights at a time.
float4 outputColor = float4(0, 0, 0, 0);
for(int i = 0; i < GlobalLightCount; i++)
{
float LightFactor = dot( GlobalLights[i].Vector, input.WorldNormal );
float4 color = GlobalLights[i].Color * LightFactor;
outputColor += color;
}
outputColor.a = 1;
return saturate( outputColor ) * tex2D( DiffuseSampler, input.TextureCoord );
Now to extend this to point lights.
Point lights are a little different in that they have a definate location and a limited range. Both of these are fairly easy to deal with. Instead of specifying the direction of the light explicitly we calculate it by finding a unit vector that points from the light source to the object being lit. Cake.
The range limitation can also be made quite simple if we don't care about being 100% realistic.
Get distance between the light and the object being lit.
Divide that distance by the radius of the light.
Clamp the value to a range between zero and one
Subtract the value from one
This gives an additional value that we use to adjust the light's intensity based on distance. Here's the resulting HLSL shader code
float3 lightVector = GlobalLights[7].Vector - input.WorldPosition;
float lightDist = length( GlobalLights[7].Vector - input.WorldPosition );
float3 directionToLight = lightVector / lightDist;
// falloff light intensity linearly between alpha*radius and radius
float baseIntensity = 1 - saturate( lightDist / GlobalLights[0].Radius );
float diffuseIntensity = saturate( dot( directionToLight, input.WorldNormal ) );
outputColor += GlobalLights[7].Color * baseIntensity * diffuseIntensity;
outputColor.a = 1;
return saturate( outputColor ) * tex2D( DiffuseSampler, input.TextureCoord );
Thursday, March 18, 2010
First killin's
Here's an abridged list of SVN commits I've made since my last blog to give you an idea of the number of fixes and tweaks being done. They're in order from newest (yesterday night) to oldest.
- Got the game closing down nicely now.
- Mostly working game exit sequence... still doesn't unload DynamicTextures yet.
- Precess rotation axes when in strafe mode.
- Kill beams when its parent dies.
- Fix wrong thrusters becoming visible.
- Clean up ALL references to a leaving player (fix crash on join after a player quits)
- Proper fix for weapon toggle not working on remotes
- Minor improvement to weapon switching from remote
- Fix scaling in billboard shader
- Add state items for targeting, and thrust
- Recursively update scene nodes as well as entities. (FIXED THE GLITCH)
- Another attempt to fix off-by-one graphical glitch. Didn't work.
- Ensure that entities on host will still receive remote input properly.
- Don't collect input if using a remote controller
- Implement bandwidth usage tracking and some measures to reduce usage
- First stab at fixing crash on >2 players at once in game.
- Fix wrong name in kill news item
- Fix bug where more than one join attempt would cause a crash
- Assign gamertag to player slot when initializing on remote.
- Remember to dequeue pending notifications after sending them.
- Finish up host side of sending player notifications
- Implement remote side and part of host side of player notification packet.
- Don't actively produce score updates unless hosting the game.
- Fix kill detection bug.
- First stab at fixing weird off-by-one-frame glitch.
- Fix stack overflow in resolving entity creations.
- First stab at queuing creations that arrive out of order.
- Fix up absurd level of brightness.
- Fix impossible to see through HUD
- First shot at multipass lighting. Tested with single light
- CoalesceDeadEntities called in response to entity destruction packet
- Add weapon states to data to be sent.
- Make sure criteria for StateItems being sent are updated.
- Adjust send criteria to keep bandwidth more sane and keep lag down
Screenshots coming tomorrow. I might also talk about how to create a simple radar display.
Wednesday, March 10, 2010
Space Combat Multiplayer
But it was worth it. After much pain multiplayer is now working. I got to show it off to the prof' this Monday. It's still buggy as hell but man, it's satisfying to be able to finally fly around and shoot other people. Even if getting a kill means crashing the program immidiately afterward.
As promised I'm going to talk about how I've implemented multiplayer so far.
The game uses a basic client/server architecture. Whoever starts the game acts as the server and has final say on stuff like where players are and who scored what kills. All other players are clients and passively receive data from the server. The only data sent to the server by the clients are an initial "I'm ready to receive data" signal and player input. The data sent to the players dictates stuff like what direction they're facing and how fast they're going.
There is a bit of hairyness here however. The client needs to know stuff like what graphics to use to display the game. If you remember my earlier entry on multiplayer, XNA allows a game session to have properties, in the form of integers, associated with it. By associating a particular play scenario with a number the client can find out what to load immidiately by checking the properties of the session he's joining.
The whole sequence of joining an active game goes like this
- The client player chooses a server to join
- The server notices the new client and creates an object to track what is to be sent to him
- The client grabs the scenario number from the server's session properties
- The client then runs the normal load sequence
- After loading concludes the client tells the server it's ready to receive data
- In response, the server sends the client basic information on all players (their score, team, assigned spawn points and so on)
- At this point the client can begin playing. Normally they're waiting to spawn.
Wait... there's no state data sent yet. In fact, if nothing else were sent the player would see nothing except for some background scenery. The magic occurs in the object the server creates to track the data sent to the client.
Each client tracking object has a list of game entities which matter to the clients. The tracking object allows the server to know stuff like whether the client has been informed that the entity exists (or has ceased to exist) and if any state updates are pending. The server sends entity creation data first, updates second and entity destruction data last. The server can also check for certain combinations (e.g. neither creation nor destruction have been sent but both are pending) to save on bandwidth. In the case of the previous example the server would give up on sending either to the client since creation and destruction effectively cancel eachother out.
State updates are a little more complicated than creation and destruction of entities. These are managed by a class called StateItemCollection. StateItems are objects which describe stuff like an entity's position, movement, damage and so on. When some significant change occurs, say the player suddenly accelerates, the associated StateItem flags that interested players should be notified of the change. The client tracking object queries each entity's StateItemCollection for this flag. If any StateItem's flag is set then the server queues up an update for the client. Once the server has queued the update for all relavent players it clears the flag.
There are a couple advantages to using this flagging method. One is that I can allow the server to choose which players receive the state updates. This allows for the server to throttle itself if it's sending too much data, or to skip sending state data that isn't relavent to a particular player. Other advantages lie in the ability to compensate for lag and in merging updates by having later updates replace earlier updates if neither have been sent.
I'll leave you with this screenshot of one (poorly lit) player shooting grey bullets. Notice I have some (glitched) lighting working now :)
Sunday, January 31, 2010
Don't Worry, I'm Still Here
I'm busy as hell working at the final (though it will probably change still at this stage) game startup sequence. I've got things working nicely now and will have a more detailed update soon. The load sequence is somewhat interesting and I think worthy of a couple paragraphs on this humble blog... later.
I'm also busy with revamping, and hopefully near-finalizing, the network protocol for the game. I'm giving particular attention to the sequence of events and data transfers that occurs when a player first joins the game.
If you remember in a previous entry I mentioned how this was the most time-consuming part of an earlier sprint. Given some further (and much briefer thought) I've created a much improved process and am throwing away pretty much all of my old network code in favour of a new solution which should support all of the events that may occur in the final game. All of this I'll write about, in more detail, tomorrow.
Off topic for a second...
I was visiting my parents earlier today for some delicious chicken and potatoes. I also got to see a bit of my brother's new score in gaming. He's picked up a copy of X3: Terran Conflict. This was a game that I've been moderately interested in acquiring myself. Unfortunately I only got to see a bit of a tutorial mission which was mildly, but irritatingly, broken. My brother was piloting an unarmed freight ship but the instructor, inexplicably, was telling him to blow up debris containers despite being unarmed. Needless to say he had to abort the tutorial at this point... going without any remaining information that could have been provided.
I hung around for a few more minutes. What I saw implied a large, freeform game universe. I'm strongly reminded of EVE Online, Freelancer and/or (what I've heard of) Privateer. Sadly, I didn't get to see much more since my brother seemed more interested in reading about bread factories than exploring the world.
However, based on what I've seen I'll definately look to pick up a copy for myself some time. The best part is I don't have to worry about Starforce, SecurROM (sp?) or any other bullshit DRM. I can either get it through Steam or pick up a DRM-free box somewhere. Even if the game turns out to be less cool than I'm thinking it will I'll still be more than happy to support a developer who's willing to not include pseudo-malware in their products.
Tuesday, December 29, 2009
Abstracting XACT 3D Audio
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
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
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 also try to find some time to get another Content Pipeline series entry written up.
Saturday, December 5, 2009
Apologies for the delays
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?
- Create teams
- Assign players to teams
- Create spawn points
- Spawn players at spawn points
- Timing for when players should spawn
- Collision detection
- Rules for damaging fighters
- Weapon targeting
- Kill scoring
- 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.
Monday, November 9, 2009
What to do... what to do... what not to do
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)
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???
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:
- The host starts up a game session and starts playing.
- Some other player joins the game session
- 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.
- In the mean time the joining player is watching the game without participating.
- 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.
- 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.
- 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.
Sunday, October 25, 2009
And Now for Something Completely Different
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?
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.
Wednesday, October 14, 2009
The Second Nastyish Problem
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.
Thursday, October 8, 2009
The Cockpit
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.
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
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...
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.

