Neither of the articles in this mini-series so far have been particularly revolutionary, though I do think I’ve implemented them in an elegant, almost effortless way. Most pro developers out there will have used tools much like them on most of their games; but I think they represent the kind of “obvious” tip that hobbyist developers never get told about, so hopefully they will have been of interest to at least a few people out there. The next tip, though, is something so blindingly obvious that every non-trivial development effort will have something like it. Or so I thought, until I (briefly) worked at a studio where there wasn’t much like it at all, and what little there was took fifteen lines of code where one ought to have been enough. In particular, it reduced 3D development to guesswork, and it showed in the quality of the game. So if you haven’t got stuff like this in your toolkit already – do it now! (Or, wait for a couple of days until I publish my Kensei.Dev code, then you can use that).
Pictures are worth a thousand words so here you go (you’ll want to follow the link to see it in detail):
This is a screenshot from the map editor mode of Shihan, a game which will, sadly, never see the light of day; XNA may be brilliant, but it eventually became clear that one person still can’t do the work of forty, and it would need forty people to make Shihan what I wanted it to be. That’s OK – lesson learned before too much time had been lost, and Pandemonium is a much more realistic target.
There’s quite a lot going on in the screenshot. In addition to the ground textures (from here), the skybox (from here) and the tree (procedurally generated by the wonderful XNA library here) you can see a whole bunch of other stuff:
- In the top left is text that is printed as though it were on a page. This is useful for messages to the developer and stuff that remains in view over several frames. In this example, it prints the current camera position and the frame rate (essential information at all times). This uses Kensei.Dev.Text.Print.
- In various locations across the screen is text, printed at a position in 3D space. This is invaluable for showing precise vector co-ordinates, as seen in this screenshot, and other data that needs to be readable but positioned in space. It uses an overload of Kensei.Dev.Text.Print.
- In the centre of the screen, in red, green and blue are lines indicating the 3D axes, using Kensei.Shape.Dev.Axis. Note XNA’s leftright-handed coordinate system!
- The green lines form the edges of a box around the currently editable ground tile. You can also see the red and yellow lines, which indicate the shapes formed by the control points and polygon edges of the ground respectively. Boxes and lines are invaluable for showing regions of the game world without blocking the view and are drawn with Kensei.Dev.Shape.Box, Kensei.Dev.Shape.Line and a number of others.
- The solid white 3D arrow in the centre of the view indicates the light direction. Solid shapes, including boxes, cylinders, spheres, frustums, etc. are also useful for showing regions and can even stand in as “programmer art” for game objects, as you’ll see in the next screenshot. Above, you can see Kensei.Dev.Shape.Arrow; below, the player is represented by a Kensei.Dev.Shapes.Capsule.
- Below also shows a couple of hollow spheres (Kensei.Dev.Shape.Sphere) indicating the minimum and maximum ranges of a currently playing test sound. Note how text positioned at the same location as the sound gives us valuable information about it.
- Also available are frustums, cylinders, cones, crosses, and triangles, each in wireframe or solid, and in whatever colour is required.
It’s practically unheard of for me to be running the game during development and not have some of this stuff turned on (controlled using Kensei.Dev.Options, obviously). It’s fundamental to the game programming art (especially in 3D but it’s useful in 2D too), and trying to work on that game without it was a nightmare, it’s as simple as that.
By now you will not be remotely surprised to learn that the code for all this is pretty simple to implement. Here, for example, is the entirety of the rendering code for our stand-in player character:
Vector3 bottom = m_position;
bottom.Y += HumanRadius;
Vector3 top = m_position;
top.Y += HumanHeight – HumanRadius;
Kensei.Dev.Shape.Capsule( bottom, top, HumanRadius, playerColour, true );
Or as another example, the sound source includes code to help show where sounds are coming from as follows:
if ( Kensei.Dev.Options.GetOption( “Audio.ShowSoundPositions” ) )
foreach ( CueInstance cue in m_attachedCues )
Kensei.Dev.DevText.Print( m_xactEmitter.Position, cue.ToString(), Color.LightBlue );
if ( Kensei.Dev.Options.GetOption( “Audio.ShowSoundDistances” ) )
foreach ( CueInstance cue in m_attachedCues )
Kensei.Dev.Shape.Sphere( m_xactEmitter.Position, cue.MaxDistance, Color.LightGreen, false );
Kensei.Dev.Shape.Sphere( m_xactEmitter.Position, cue.MinDistance, Color.Lime, false );
It really doesn’t get much easier than that.
Behind the scenes it’s pretty straightforward too: the Kensei.Dev.Shape (and Kensei.Dev.Text) static classes track what they are asked to draw during the frame, then render it all in one batch during the Draw method. Working out how to draw some of the more complex shapes was a bit of a pain, but not horrendously so and anyway if you use Kensei.Dev when I release it, that will all be done for you.
I hope you understand what I mean by Efficient Development by now. It’s not just having options in your game; it’s the ability to add options with one line of code, and control them during debugging with one mouse click. It’s not just having a command line interface; it’s the ability to add a new command to it with less than five minutes work and have it available forever after. It’s not just being able to draw shapes – it’s the ability to do so in one line of code and turn them off and on at will, so you can visually understand why your 3D code is misbehaving or put off creating complicated 3D models until later. Efficient Development is putting in a small amount of work up front to enable big gains later. It’s also knowing when to stop – almost all of the stuff I’ve written could be polished further (and you are encouraged to do exactly that if you decide to use it), but being a one-man team it’s enough for me at the moment. Efficient Development is about finding the balance between creating time-saving tools, and spending so much time making time-saving tools that you never quite get around to finishing the game.
Speaking of which: in the next and final part of this mini-series I’ll make the Kensei.Dev code available for download, and cover a few final miscellaneous tips; then we’ll move onto something more exciting.
“Step by step walk the thousand mile road.” – Miyamato Musashi