I've just finished setting up wordpress on my website and I've decided to move my XNA blog to my personal web space. XNA is a great framework, but something I find myself using less and less. So it makes sense to consolidate my games development experiences on one website. Along with this it gives me a chance to post about other things I'm working on such as the science fiction stories which I'm writing with my former colleague Lap Pun Cheung. I will be posting my morpher implementation (which as far as I'm aware is the fastest implementation in XNA) to my new blog. Something I'm considering doing with my involvement in XNA is posting samples rather than articles as it's much quicker to produce. During the next year I'll be learning the Qt framework, which I'm really looking forward to, so I expect I'll do a few posts on that.

I also thought I'd mention that XTC 2010 (an XNA tutorial competition) is drawing to a close and as far as I'm aware there's been few entries, so if you want a great chance of recieving a free license for the Hilva Graphics Engine check it out.

You can find my new blog here, feel free to bookmark or subscribe. I recommend Google Reader ;-)

I was in Scotland a couple of weeks ago and while sitting on the shore of an island overlooking the mainland, something occurred to me. I was looking at where the mainland met the sea, what should you expect to see? A lot of people, including it seems a few games developers, would say there should be a reflection of the terrain. In actual fact, what I saw was no reflection at all, but instead there was a fairly bright highlight instead. If this was a generated computer graphic, I'd have probably called it a mistake, reflecting the horizon behind the terrain which of course was occluded.

Reflections

I find it interesting that quite often reality is overlooked in favour of what we think it should look like. To a certain extent, perhaps this is necessary for the user’s experience. In a game, is it better to have an effect which is based on real life but looks completely wrong, or something which looks correct but isn’t true to life? Just a musing.

Ok, so back to the blog. I’m currently writing a series of articles based on morph target animation since there seems to be very little information about it in XNA and only one or two implementations on the internet. You can check out a video of the code I’ll post in the first article here. I’ll probably write about four articles on morphing.

I’ve got a number of articles planned (some of which are virtually complete), I hope to write and release the majority of the following:

  • Camera Paths Using Bezier Curves
  • Coding Standards
  • Decals
  • Extending the Triangle Picking Sample
  • C# Extension Functionality
  • A discussion on getting code done
  • Imposters
  • Morphers
  • Opaque Data
  • XNA Game Installers
  • Point Clouds
  • An Approach to Resolution Independence
  • Stencils
  • Advanced Texture Usage
  • Tweakables
  • Texture Morphing
  • Uniform Unit Sizes
  • UVs
  • Version Control
  • Vertex Texturing
  • Weather Systems
  • Wipes and Transitions

Hi all, been a bit quiet on the blog post front recently. I've got a number of articles planned and am midway through writing a couple of new ones. Any requests, just let me know and I'll see what I can do. I'm currently also working on a software renderrer using C++ and GDI+.

In the mean time, here's some links you may find useful to a wealth of presentations. Quite a few of these links probably overlap.

Gamefest

Gamefest UK

GDC 2009

GDC 2009 XNA Specific

GDC Free Content

MSDN Listed Presentations

Crytek

Bungie

Insomniac

Valve

Khronos

J.M.P. van Waveren (Id Software)

Naughty Dog

Epic Games

Dice

 

Ke-Sen Huang also has a homepage dedicated to links to further presentations

Gradient mapping is a feature you will know about if you're a Photoshop user. The basic principle is to take an image, convert it to greyscale, then use each pixel's brightness as a lookup value from a texture1d. This texture1d in photoshop is generated from a built in gradient editor. To implement this in XNA using a pixel shader is a very straight forward task. Just generate out a 1d gradient texture (from your graphics package of choice). Now in the shader, as we are working with normalised values we can pass in the greyscale value of a pixel (which will be between 0 and 1) into the sampler lookup function which considers a textures width to be 1.The gradient map is then sampled based on the brightness of the image, which results in the process you can see below. Using gradients can be very useful for a range of tasks, so if you wanted to extend this system you could make some sort of gradient editor.

Download the sample

“Dolly zoom” is a cinematography term for a method you'll instantly recognise. Originally pioneered by Irmin Roberts, a Paramount Pictures cameraman, the method was made famous by its memorable use by Alfred Hitchcock for the film Vertigo. The cinema device has made numerous appearances since and is usually used for giving a sense of vertigo, unease or depicting the emotional impact of a realisation on a character. The basic premise is to keep the subject of the frame at the same scale while changing the scale of the background and/or foreground. This effect can be extremely good at giving a sense of vertigo and unreality.

Dolly zooming can be achieved by changing the field of view while changing the distance from the subject to ensure the subject remains approximately the same desired scale. When using an actual camera, this would be achieved by using a zoom lens (zoom lenses change the focal length and thus field of view) and at the same time physically moving backwards of forwards as appropriate.

Because of the non-linear relationship between the field of view and camera distance required to achieve this effect, it takes a good degree of experience and skill to do manually. In computer graphics, however we can use an equation to help us out. A common equation to achieve this effect is:


Now looking at the equation above, there are three variables. The field of view, which we can control and is therefore an input. The distance, which is calculated by the equation and is therefore the output. And finally, width which is a value relating to the target of our dolly zoom, this we will need to calculate ourselves. Fortunately this is straightforward as all we need do is multiply the target distance by the arctan of 90 degrees.

Assuming your camera view matrix is created using the standard Matrix.CreateLookAt() method, all you need adjust here is the camera eye position parameter. And assuming that the camera projection matrix is created using Matrix.CreatePerspectiveFieldOfView(), you can simply supply the field of view of the camera in radians.

Now, probably what you're most interested in, the sample.

Please note, this is the first time I have attempted to implement the effect so if the implementation can be improved I'd be delighted to hear how.

References

http://en.wikipedia.org/wiki/Dolly_zoom
http://www.gamedev.net/community/forums/topic.asp?topic_id=528056
http://www.mediacollege.com/video/shots/dolly-zoom.html

In the development of many computer games, it is often important and necessary to store positions and meta data relating to 3d models and scenes. For example, you may have a model of a car and wish to place a number of meta-points on the model. Such as a point on the exhaust for a smoke emitter, points on the front for the headlights to project from, an object attachment point for that roof mounted turret, local damage helpers and positions inside the car for players to sit and interact with the steering wheel, to name but a few implementations. Rockstar North for example use this system in GTA: San Andreas by setting up dummies in 3d models. An example can be viewed here of a car from the game.

A method to address such a need is in placing pre-identified (essentially meta) bones throughout the model. There are many names for creatable objects in graphics packages which will export to bones, 3ds max has dummies, Maya has locators and most other software packages call them nulls (such as Lightwave, Softimage, Houdini, Blender and Cinema4d), systems like Unreal Engine call them pawns. These bones are connected to no geometry, which means its very easy to access them from your bone tree but they won't visibly be displayed (unless you want them to be) and so are ideal for representing invisible helper points.

Some key uses of meta bones are:

  • Object attachment points, e.g. customisable weapon hard-points on a spaceship, or an articulated trailer on the back of a truck.
  • Particle emitter locations
  • Spawn points
  • Lights
  • Waypoints
  • CTF Locations
  • Weapon Pickups
  • King of the hill zones
  • Anchor points

How to make them

These objects are very easy to create in most packages, for example in 3ds max simply go to the create tab, then the helper tab and click the “Dummy” button and create the object in one of your viewports. You can accomplish the same in Maya by creating a locator, in Lightwave by creating a dummy and most other graphics packages use the term “null”.

Now that you've created one of these object, you now need to encode information about its purpose and relevance, which can be parsed by your game. In this article I describe storing the data and identification by encoding it into the bone name, however in the “Taking it further” section I cover some options for extending the capabilities of this meta-data. Each object should have a name which can identify every piece of information it needs to communicate to the game, such as the type of meta-object it is and some related data. Also note that bone names must be unique, so you may need to include some sort of unique identification number. As an example, you could approach encoding a smoke emitter like so: <type>-<subType>-<uniqueId>-<size> such as “emitter-smoke-01-50”. Bear in mind that there will be a comparatively small limit on the length of the name.

Also remember that it can get confusing having a lot of these objects in a scene, so confusing object a that does x with object b that does y is a problem. You may consider picking different colours for different types of objects.

How to load them and display them

Once exported, your nulls (or equivalent) should now be stored as model bones. You can retrieve a list of the model's bones by accessing the collection of ModelBones, for example: myModel.Bones. You will then have a list of bones which store the name and world matrix, which is great as you can retrieve the relevant meta-tags stored in the name and decompose the world matrix into its translation and scale vector3s and a quaternion for rotation (you can convert this to your conventional Euler angles (i.e. yaw, pitch, roll) by using skytigercube's method in this article at Creators Club.) For example:

Vector3 scale, translation, eulerRotation;
Quaternion rotation;
bone.Decompose(out scale, out rotation, out translation);
eulerRotation = QuaternionToYawPitchRoll(rotation);

You may wish to parse the bones in the model when you load the model in and build up the data structures which will rely on the stored meta-data. A quick example, which just runs through bones each Draw call and displays a sphere at all bones that begin with “myNamedTag” follows:

foreach(ModelBone bone in model.Bones)
    {
        if(bone.Name.StartsWith(“myNamedTag”)
        {
            spherePrimitive.Draw(bone, view, projection, Color.White);
    }
}

Here any bones that begin with “myNamedTag” such as “myNamedTag01”, “myNamedTag02” and “myNamedTag-Front” will have a sphere drawn using their bone world matrix. Note that this is using the sphere primitive class from the Primitives3D Creators Club sample and relies upon an already sphere primitive.

Taking It Further

Encoding meta-data into the name of bones works fine for fairly simple implementations, however if an object has a lot of information attached to it this becomes less than ideal to encode everything into the contents of a small text box. You may consider encoding all this data into each object's user defined properties (in 3ds max, other software will have equivalents.)

In terms of displaying and loading user-defined-properties you can check out the creators club NormalMappingEffect sample (and I'm told the premium robot sample), while http://xnaengine.com/ and http://www.catalinzima.com/?page_id=66 appear to do something with 3ds max user-defined properties. There is also some discussion at: http://forums.xna.com/forums/t/13265.aspx?PageIndex=2

You could also make a custom tool to achieve more customised functionality or extend your graphics package's functionality by taking into account its support for plugins and scripting (if it has the support) and coding in what you need.

And Finally

I hope this article has been informative. Criticism and comments are appreciated. If people want me to put together a quick sample I'll be happy to do so, just comment.

References

http://www.gamedev.net/community/forums/topic.asp?topic_id=279475
http://gamecareerguide.com/features/20010324/melax_03.htm
http://www.3dcognition.com/theoryGameDev.php
http://update.multiverse.net/wiki/index.php/Platform_Tutorial_Importing_Static_Models


Amit from Dev102 has some great lists of Visual Studio shortcuts that I've come across. They're in the form of three articles, I've combined the three lists into one list of 26 shortcuts which you can view on this page. Though I've been using some of these shortcuts for a fair while, I've already put into practice the ones I didn't know about and have found them very useful. I feel I should reiterate that these lists are not my original work.

Three Articles At Dev102

 

A Combined List

  1. CTRL + ".": This is actually a shortcut for a shortcut. it is the same as CTRL + SHIFT + F10 which opens the smart tag window and allows you to add Using statementsAdd Using Statement

    Or implement interfaces Implement Interface

    and much more.

  2. ALT + CTRL + "e":  This one will open the Exceptions window, which allows you to tell Visual Studio to halt at specific exceptions, halt on all exceptions or selecet some exceptions to ignore.

    Exception Popup Windows 

  3. CTRL + "k" + "f" and CRTL + "k" + "d": these two will format the code in the window to be nicely indented. using "d" will format all the document while using "f" will format only selected text. The formatting is for all types of documents, HTML, Xaml, XML, C#… This one is my favorite.

  4. SHIFT + Del: This one will cut the entire row from the document and past it to the clipboard. No need to select the row, just put the marker there and click SHIFT + Del and it is gone.

  5. CTRL + "k" + "c" and CTRL + "k" + "u": These two are for commenting selected text (the "c" options) and uncommenting selected text (the "u" option).

  6. ALT + ENTER: this little shortcut will open up the Properties windowProperties Window

  7. CTRL + "k" + "s": This one opens up the code snippets dialogue within the code

    Open Snippets Dialogue

    If you want to create code snippets you should read my post about snippy the code snippets editor.

  8. F12: I think you all know this but still F12 is the shortcut for the "Go to definition" command which will take you to the definition of the object your marker is currently on.

  9. F9: Another one i think you all know, clicking on F9 will add a breakpoint to the code line your marker is currently at. Clicking F9 again will remove this breakpoint from that line.

  10. CTRL + ALT + "q": This one will open the Quick watch window while you debugOpen Quick Watch Window

  1. CTRL + "K" + "M": This one is Genius.
    Incase you need to add a method to an
    already existing class you just write the method
    as if it exists :

       1: int i = 5;
    2: bool flag = NewMethod(i);


    Click on the shortcut and you will get the

    following method stub:

       1: private bool NewMethod(int i)
    2: {
    3: throw new NotImplementedException();
    4: }

    Great isn’t it?

  2. CTRL + ".": This one expands the one before it, say you need to add a functionality to a different class. again all you have to do is use the method as if it exists:

       1: int i = 5;
    2: bool flag = DifferentClass.NewMethod(i);

    Put the cursor on the new method, click the shortcut and you will see this:

    Create Method Stub 
    Hit Enter and you will get a new method stub with the return value and the parameter, in the other class.

       1: public class c
    2: {
    3: internal bool NewMethod(int i)
    4: {
    5: throw new NotImplementedException();
    6: }
    7: }

    Definitely my favorite.

  3. CTRL + "-" and CTRL + SHIFT + "-":  These two are similar to the Forward and Backwards buttons of the WebBrowsers and will take you to all the places your curser was, Very useful for those times you click F12 to go to definitions and then have no clue where you were before :). (Thanks Vijay Santhanam).

  4. ALT + ENTER: We talked about it in the last post, but it seems that this shortcut will open the properties window on anything that moves, even Files in your Windows Explorer. (Thanks to Bryan Migliorisi from http://www.Migliorisi.com).

  5. SHIFT + ALT + ENTER: This one will switch you Visual Studio to Full Screen mode, which is very useful in those boring presentation when you have to show your code through a projector on a screen. Another click will get you back to normal mode. (Thanks to Pablo Marambio).Visual Studio Full Screen

  6. CTRL + "M" + "M": This one will collapse the region your cursor is at whether its a method, namespace or whatever for collapsing code blocks, regions and methods. The first will collapse only the block/method or region your cursor is at while the second will collapse the entire region you are at. (Thanks to knave).

  7. CTRL + ALT + "P": This will open up the attach to process window, very useful for debugging. (Thanks Greg Beech from http://gregbeech.com).Attach to Process

  8. CTRL + "R" + "R": This one is used to quickly rename a method/ variable or whatever. (Thanks again to Greg Beech).Rename Method

  9. F8 and SHIFT + F8: These two are great! they are similar to the shortcut number 3 but they will take you forward and backwards in your search results just search for something and then start hitting F8 and you will see. (Thanks to David Hu).

  10. CTRL + SHIFT + "B": This one will invoke build solution. ( Thanks to Matt Brunell).

  11. CTRL + "B" + "T": This one will allow you to quickly add or remove a bookmark from a line of code.

  1. CTRL + SHIFT + 8/7: In case you haven’t knew there is a “Go to Definitions Stack” and every time you click F12 it stores where you went inside that stack. Hitting CTRL +  SHIFT + 8 goes “Back” in the stack and CTRL +  SHIFT + 7 goes forward.

  2. F8: I hope all of you are using the CTRL + “-“ to go back to the location you were (after hitting F12 for example). F8 is the opposite to that action it will take you forward. It is the same as CTRL + SHIFT + “-“.

  3. SHIFT + F12: Having the marker on top of anything and clicking SHIFT + F12 will search the entire solution for that object and open up the find symbol window:
    SHIFT   F12

  4. CTRL + ALT + Down Arrow: This is my favorite. You all know the  CTRL + TAB feature of Visual studio:
    CTRL   TAB
    We have all used it to switch between open files, the problem is that there is no order in the files, although sometime it looks alphabetical it isn’t Clicking CTRL + ALT + Down Arrow is like clicking the little arrow on the upper right corner of the text editor so the result is this:
     CTRL   ALT   Down Arrow
    And the best this is that it is ordered the same as the tabs on top of the text editor.

  5. CTRL + K + X: This is also a useful one, Hitting CTRL + K + X will open up the insert snippet window and allow you to select the snippets you want to use:
    CTRL   K   X

Creation and use of placeholders, whether levels, 3d models, sprites or sounds, has a number of advantages when developing computer games. In this article I discuss some aspects of the use of placeholders in games.

Decouple programming and art schedules

Placeholders are an excellent way to support code development without waiting on asset completion. Using placeholder graphics decouples programming and art schedules, allowing them to progress independently of each other. By using quick and effective placeholders, the coders can get to work on what's important without being held back waiting on final assets to be finished. The coders can then put in revised assets when they become available – just make sure you don’t leave any placeholders behind. An industry professional once told me how they “borrowed” some models from a very similar game to the one they were making at the time and accidentally shipped the demo with the hijacked assets!

Speed of build turnaround – Proof of concept

High poly models or detailed assets can take a long time to create and when you're trying to prove the feasibility of a project you're often more interested in the technical side. When trying to decide if what you might attempt is technically feasible in your environment and time constraints, you may find that when building a proof of concept you just want some quick assets to put in so that you can continue to focus on building up the code. In terms of pre-production, placeholder art can be very important just to get a working build. I was recently at the Microsoft X48 competition, where we coded a game in 7 and a half hours. When developing, our artist mercilessly took Google images and made graphics by tweaking them in Photoshop. Our focus here was not to make a pretty game, but to get a working build as fast as possible.


Figure 1. Dodge The Big Foot - Google Images tweaked mercilessly

Identify the tolerances

Placeholders also are a great way to carry out tolerance testing when trying to work out how high poly you can make scenes for example. It would waste a lot of time for the artists to not know how detailed to make their 3d models and what limitations there are on the type of material properties they can use. By using placeholders that simulate the sort of poly counts and shaders that you want to support you can figure out the tolerances of your game engine, what you need to optimise and what the artists need to be limited to.

Issues with placeholders

While placeholders mean that you can get the basic look and feel of your target environment without the full development time, they can also work to your detriment. It can be demotivating to see your project littered with ugly placeholders. Most games go the extra mile in creating the fun factor by rewarding visuals and involving graphical finesse. Likewise placeholders can create issues for the team, the designers may not know how the physics of a vehicle may work when the vehicle has not yet gone beyond being implemented as a placeholder, which of course must be understood for a more balanced and smoother level.

Some examples in the context of level design

When Half Life 2 was being developed, the developers took a new approach. Separating art from design in the level creation, the designers would flesh out the gameplay before the team of artists made the levels look pretty. The initial stage in level production was to create an “orange map”, where the entire level's textures were orange. The result of this meant that the team could test and perfect gameplay, script in any necessary elements and let the programmers work on what would become finalised levels without waiting for the art pipeline to be completed (or indeed necessitate the start of art development.) The result was a much more rapid and smoother development process, as designers involved in play-testing, tweaking and working out where those big, beasty enemies should jump out can do their work equally well in either a Sunny-D environment or a fancy multitextured and materialed environment.


Figure 2. An "Orange Map" from Half Life 2

In the context of level design for example, I discussed this with a friend who is a level designer using UE3. He stated that he believes using placeholders cuts development time in half. “With level design (my choice examples, as it is my area of knowledge) placeholders are easier to throw around. Gameplay isn't fun? Put a block there to cut the view distance as opposed to putting a table there and finding out later that it is ineffective. If designers are too busy worrying about "But a table doesn't make sense" then the actual fun will never be developed.”

So who makes it?

Depending on your development environment (and in the case of studios), you may have either the programmer developing the placeholders or the 3D artist. I know a few triple A studios where they won't even let their programmers have 3ds max installed in case they start making placeholder graphics, leaving this task to be done by the 3d artists. However, depending on your environment this may not be feasible or desirable. Depending on the organisation, it may be the 3d artists or the programmer who creates the placeholder, this is more of a managerial decision and each has its pros and cons.

I hope this article has been an interesting read, as usual comments and criticism are appreciated. If you can suggest any improvements I can make, I'll be happy to change the article.

References and Further Reading

Keighley, G. (2004). The Final Hours of Half-Life 2. Available: http://uk.gamespot.com/features/6112889/index.html. Last accessed 28 March 2010.

Recently I've been doing tools development, something I've done a lot of in the past when reverse engineering Dune 2000 (an old RTS.) I've learnt some interesting lessons in tools development, which I thought I'd share with you.

Understand your user

Firstly, the most important part of tools development is seeing how the end user will use it and making it as easy as possible for them. When developing a series of tools for our artists, I'd frequently speak to them, going through the work process and how they feel it should flow. Make sure the tools you develop are suited to the intended target.

Keep things straightforward

Everything should be kept straightforward, easy and quick (and obvious). Too many programs have massively complicated user interfaces which can be completely baffling. It's worth spending time working on the design of the program and the structure whether that's on paper or on a graphics package. The last tool I wrote I mocked up quickly in Photoshop what it would look like and drew the class structures on paper, before touching a line of code. This helps you think about how to make the program well structured and come across potential problems before they become an issue.

Make everything fluid

It's important to make everything fluid, support dragging and dropping of files rather than forcing a rather more cumbersome process of being locked in to the windows open file dialog box. If your user is applying a texture to a shader for example, let them drag it straight in from Windows Explorer, it makes things quick and easy. Auto focus helps keep the flow going with tool usage, having to keep reselecting the same option because the program forgets gets frustrating quickly. In a similar fashion if you have a list of items in a menu, let them be dragged up and down rather than requiring a button to be pressed each time you want to move the item up one.

Keep clicking to a minimum

Following on from this idea, a good rule of thumb is to keep functionality down to as few clicks as possible, this way your end users will be able to work more productively. Shortcuts are also good at speeding things up, but should never be the exclusive way to carry out an action. Most modelling packages for example have many ways to achieve the same task. Less clicks is a fundamental improvement and goal for tools, people spend half their lives clicking through menu after menu. The objective of a good tool is to cut this down to a minimum.

Clean UI

Keep the user interface clean and clear of clutter. Icons can be very helpful, but what they represent need to be easily recognisable at a glance. Adopting common icon designs is definitely a great idea, using a floppy disk icon for saving and an open folder for opening a file for example. Everyone knows what they mean, resulting in a quicker learning curve.

Redesign and reiterate when necessary

When development of the tool becomes held back by poor or a changed design, it's time to have a think, work out the optimal structure and recode the tool. Frequently I've wasted more time trying to make code work which is broken from poor design, than it would have taken me to change the structure and reimplement the code. I find an iterative approach to this development very helpful, the first design is rarely optimal and you'll learn from each iteration.

Target your tool

I also believe in the Unix ethos of developing small targeted use applications as opposed to über programs which attempt to be a jack of all trades but result in being a master of none. My experience of the asset production pipeline is that dedicated tools which each accomplish a job is a much more favourable approach, for example creating a mesh in Lightwave, shipping it off to Zbrush to be sculpted, then taking it into Topogun to create a lower poly version, baking the high poly to normal maps, tweaking in Lightwave again, generating maps with XNormal, then exporting to FBX via 3ds max (Lightwave's FBX exported is supposedly pants).

Screenshot of TopoGun
Figure 1. Topogun, a targeted tool

Flexible interfaces

This is more an issue of personal taste and indeed there are a lot of different systems out there for the way different parts of an application are presented. Recently I've gotten into using floating windows, if I want to bring up the properties of a mesh for example, I find it far more useful having that as a separate window. Windows can then be resized and moved about, your preview window can be maximized on a second monitor for example. Then the layout can be saved and preserved, allowing a lot of flexibility for the end user.

Allow extension

Make tools that are easily extendible, with readable and editable configuration files. Custom user configuration helps makes people life's easier, having the capability to change their preferences to something they find more suitable. We don't all like the same layouts or colours, so supporting user changes will make people's time less painful.

Existing formats make life easier

Usage of existing and established file formats can be very useful. I like to use XML where appropriate (although I change the extension) as it makes serialization and deserialization very easy, tends to generate readable files and allows quick editing in a program like Notepad++ (or just Notepad). As a standardised system, it also means someone else can pick up your files and understand how they're structured – which is certainly more involved with a custom or binary format. An alternative to XML is JSON, which provides a lightweight alternative that my friend swears by. It can also give a lot more flexibility when adhering to an established standard when storing other data, such as images and models.

While using established standards for storing any kind of data can be extremely helpful and effective, it does carry with it a potential inherent problem. By adhering to standards, you are limiting what you can do to what the standard supports. In the case of XML this may not be such an issue as its a very versatile markup language, however locking yourself in to an image or 3d model format can be extremely limiting. To get past this, you could extend or encapsulate the format or simply see if there is an alternative which is better suited.

Summary

To sum up, planning and design with an iterative approach allows for speedy development of tools. Keeping things extendible and configurable means the user can keep things the way they prefer, while constantly looking to streamline the flow of usage speeds up tool use and improves productivity.

I think I've repeated myself quite a few times here, but hopefully it's been an interesting read. I recommend you check out some articles on Gamasutra written by people much more experienced than me and who know what they're going on about ;-).

Shawn Hargreaves on Tool Postmortem: Climax Brighton's Supertools
Noor Khawaja on
Making Your Game Tools Fast And Efficient
Dan Goodman on
Game Tools Tune-Up: Optimize Your Pipeline Through Usability

I find discussion of tools development interesting, so please feel free to comment.

Hi all,

I came across a link to IntelliShade the other day, an extension to Visual Studio which seems to be rather hard to find now that the official website has gone down along with ziggyware. IntelliShade offers syntax highlighting and some basic intellisense to editing HLSL (.fx) files. Rather than having to rely on a plain text editor, IntelliShade will highlight data types, semantics and other tokens that it recognises and has a rudimentary list of suggestions as well, it also makes use of outlining functionality, allowing you to take advantage of the ability to hide functions and structs at the click of a button, which helps editing large effect files greatly.

I've mirrored this download onto my personal webspace now, you can download the installer here

You can find alternate mirrors here and here

You might also be interested in checking out NShader, which supports HLSL, GLSL and CG, although it's HLSL support lacks more than syntax highlighting at this time.

As far as I'm aware neither IntelliShade nor NShader work with Express versions of Visual Studio. If you're on express then you should be able to create a usertype.dat file containing HLSL keywords which will give you more basic syntax highlighting. For some example keyword lists, check out this topic.

XNA 4.0 was officially announced today at GDC 2010, earlier this week support was announced by Windows Phone 7 Series phones for XNA developed products and to support this new platform XNA 4.0 has been announced. So besides support for Microsoft's new mobile OS, what does XNA 4 change?

Firstly, there is now support for Visual Studio 2010. Next there have been audio improvements with support for dynamic audio output and microphone input. Further to this there have been a number of graphics changes and optimisations, with the addition of new effect classes (like BasicEffect) to support skinned animations, environment mapping, dual textures and alpha testing. 

More details at Michael Klucher's blog and Sgt. Conker's blog

Static classes are extremely useful in software development and here I will cover how they can be used for keeping track of important game resources.

Firstly, for those of you unfamilliar with static classes, what is a static class?

Static classes are a type of class that can not be instantiated and can only contain static members. A static class will only store one instance of fields and methods. The Math and MathHelper classes are examples of static classes, you do not (and indeed cannot) instantiate these classes, but make use of their static methods and static properties which return the value in a static field. 

So how is this useful?

Static classes are extremely useful for helper classes, my engine is full of static classes for localisation, utilities such as math extension helper classes, crypto random generators and physics. However this is generally mainly for the static functions contained within them (which in fact aren't restricted just to static classes), now in regard to game resources, we typically store one object of the graphics device, spritebatch, contentmanager, game etc... but it can be very useful gaining access to the graphics device easily by storing it in a public static class. This enables you to simply use Resources.GraphicsDevice rather than having to pass down the graphics device from parameter to parameter.

An example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace MyNamespace
{
    public static class Resources
    {
        public static GraphicsDevice GraphicsDevice;
        public static SpriteBatch SpriteBatch;
        public static ContentManager Content;       
        public static GameTime GameTime;
        public static Game Game;

        public static void Cleanup()
        {
            GraphicsDevice = null;

            if (SpriteBatch != null)
                SpriteBatch.Dispose();
            SpriteBatch = null;

            if (Content != null)
                Content.Dispose();
            Content = null;

            GameTime = null;
            Game = null;           
        }
    }
}
 

Since it's not always convenient to be using random avatars or a signed in gamers avatar (especially as the signed in gamer's avatar isn't allowed a life of its own), you may want to create an avatar in the editor and use that in the game as a NPC friend, enemy or boss. Additionally, you may want to keep randomising avatars till you find one you like, and keep that to use. This tutorial will show you exactly how to accomplish this.

The AvatarDescription Class

The AvatarDescription class stores a byte array containing 1021 entries. This array stores all the unique characteristics of an avatar, such as skin colour, weight, clothes, facial features, hair etc. The last 19 bytes of this array, appears to be a checksum, preventing you from creating your own avatars (unless of course you know how the checksum is generated.) The guys on the XNA forums are looking into determining what in the array does what. If there's an element you need, I recommend using the avatar editor on the NXE dashboard, then seeing what's changed, as per the advice of AtraX. 

The Parser Script [Located Here]

This script simply runs through the supplied text, parsing it using a regular expression and outputting the second column in one of four formats. As a byte array, for hardcoding, then as newline delimited, comma separated values or XML for easy storage external to the binary, so that you can store many preset avatars and load them in from a file(s).

Step One: Run the avatar code from Tutorial One or indeed any avatar code which makes use of the AvatarDescription class. 

Step Two: As soon as this code is running on your screen, hit the break all button, or use the Ctrl-Shift-Break shortcut.


Step Three: Bring up the locals window, the locals window shows you all the local variables at play which you can inspect and examine the values of. Here we are very much interested in what is stored in the avatarDescription.description. If the locals window is not already up hit Ctrl-Alt-V,L.

Step Four: Now under game->avatarDescription->description (or equivalent), highlight all entries in the description from [0] down to [1020], right click and hit copy.


Step Five: Next, load up the parser script on my site, paste into the box, and using the byte array format, and hit submit:

Step Six: This will now parse the data, and put it in a format that can be used easily in our code. Highlight and copy the results, including the { and } at each end.

Step Seven: Now back in the Visual Studio hit the stop button or press Shift-F5. Now find and replace the avatarDescription initialisation code, instead of generating a random avatar (or using a signed in gamer's avatar) we now want to use the avatar data we've obtained from the IDE, using the following line (pasting in the clipboard):

 

avatarDescription = new AvatarDescription(new byte[] YOURBYTEARRAYHERE );

e.g. 

 

avatarDescription = new AvatarDescription(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, ...... 58, 45, 243, 60 } );

Step Eight: The avatarDescription now is a preset avatar rather than an avatar generated on each execution of the game.

In summary, we've grabbed the desription out of the IDE, processed it and put it back into the code to ensure a permanent avatar appearance.

Complete source (Game1.cs)

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace AvatarStepOne
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;

AvatarDescription avatarDescription;
AvatarRenderer avatarRenderer;
AvatarAnimation avatarCelebrateAnimation;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
Components.Add(new GamerServicesComponent(this));
}

protected override void LoadContent()
{
avatarDescription = new AvatarDescription(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 16, 0, 0, 3, 26, 0, 3, 193, 200, 241, 9, 161, 156, 178, 224, 0, 8, 0, 0, 3, 37, 0, 3, 193, 200, 241, 9, 161, 156, 178, 224, 0, 32, 0, 0, 3, 59, 0, 3, 193, 200, 241, 9, 161, 156, 178, 224, 0, 0, 128, 0, 2, 250, 0, 3, 193, 200, 241, 9, 161, 156, 178, 224, 63, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 2, 142, 0, 3, 193, 200, 241, 9, 161, 156, 178, 224, 63, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 2, 110, 0, 3, 193, 200, 241, 9, 161, 156, 178, 224, 63, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 215, 185, 113, 255, 55, 33, 22, 255, 235, 125, 128, 255, 114, 127, 53, 255, 55, 33, 22, 255, 197, 73, 109, 255, 55, 33, 22, 255, 101, 68, 40, 255, 101, 68, 40, 0, 0, 0, 2, 0, 0, 0, 1, 193, 200, 241, 9, 161, 156, 178, 224, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3, 193, 200, 241, 9, 161, 156, 178, 224, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 31, 0, 3, 193, 200, 241, 9, 161, 156, 178, 224, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 96, 0, 1, 193, 200, 241, 9, 161, 156, 178, 224, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 144, 0, 1, 193, 200, 241, 9, 161, 156, 178, 224, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 60, 0, 1, 193, 200, 241, 9, 161, 156, 178, 224, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 60, 0, 1, 193, 200, 241, 9, 161, 156, 178, 224, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 144, 0, 1, 193, 200, 241, 9, 161, 156, 178, 224, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 96, 0, 1, 193, 200, 241, 9, 161, 156, 178, 224, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 31, 0, 3, 193, 200, 241, 9, 161, 156, 178, 224, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 145, 254, 13, 246, 78, 178, 157, 244, 219, 52, 73, 35, 119, 60, 219, 58, 45, 243, 60 });
avatarRenderer = new AvatarRenderer(avatarDescription);
avatarCelebrateAnimation = new AvatarAnimation(AvatarAnimationPreset.Celebrate);
}

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

if (avatarRenderer.IsLoaded)
{
avatarCelebrateAnimation.Update(gameTime.ElapsedGameTime, true);
}

base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);

avatarRenderer.View = Matrix.CreateLookAt(new Vector3(0, 1, -3), new Vector3(0, 1, 0), new Vector3(0, 1, 0));
avatarRenderer.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, .01f, 40.0f);
avatarRenderer.Draw(avatarCelebrateAnimation.BoneTransforms, avatarCelebrateAnimation.Expression);

base.Draw(gameTime);
}
}
}

Carrying on from the first article, I thought I'd just extend it to include support for a signed in gamer's credentials. While the only new avatar element here is the capability to draw a user's avatar instead of a generated one (which I'd already given the code for in the introduction), it also shows off getting the gamerpicture, tag, gamerscore etc, and some basic use of event handlers.

Step One: Set up storage for a sprite batch for drawing 2D elements, a sprite font so that we can draw text to the screen, a boolean value to tell us whether the player is signed in, copies of the signed in player's Gamer and GamerProfile objects, a texture for a pretty background to render along with a texture to store the player's gamer picutre. In the declarations add:

        SpriteBatch spriteBatch;
SpriteFont arial;
bool gamerSignedIn = false;
GamerProfile profile;
Gamer gamer;
Texture2D gamerPicture;
Texture2D background;

Step Two: Set the screen resolution to 720p, this means that we can rely on co-ordinates always being at the sample place. In the game constructor add:

            graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;

Step Three: Add two event handlers to handle the user signing in and out. It is useful to note that for the first few frames of the game the player may not be signed in, so calling their profile without checking that they're signed in will result in an exception. Also we want to take care of the player signing out during our game also. Again in the game constructor add:

            SignedInGamer.SignedIn += new EventHandler<SignedInEventArgs>(SignedInGamer_SignedIn);
SignedInGamer.SignedOut += new System.EventHandler<SignedOutEventArgs>(SignedInGamer_SignedOut);

Step Four: Since we are using the signed in player's avatar rather than a random one, we can remove the lines initiallising the avatarDescription and subsequent avatarRenderer with a random avatar. In the LoadContent function remove:

            avatarDescription = AvatarDescription.CreateRandom(); //Generate a random avatar, by randomising the description byte array with acceptable values           
avatarRenderer = new AvatarRenderer(avatarDescription); //Create a renderer for the avatar we have just randomly created

Step Five: Create the sprite batch and load the background texture and default font spritefont. In the LoadContent function add:

            spriteBatch = new SpriteBatch(GraphicsDevice);
background = Content.Load<Texture2D>("background");
arial = Content.Load<SpriteFont>("Arial");

Step Six: In the update function modify the if statement to update only if the gamer is signed in in addition to the renderer being loaded. Modify the if statement to be:

            if (gamerSignedIn && avatarRenderer.IsLoaded)

Step Seven: In the draw function, after the call to clear the graphics device, but before the view matrix set, we will be wanting to draw the background, so add:

            spriteBatch.Begin();
spriteBatch.Draw(background, new Vector2(0), Color.White);
spriteBatch.End();

Step Eight: Now we want to ensure the avatar is only renderred when the player is signed in. So enclose the view matrix set, projection matrix set and draw call in curly brackets which are preceeded with the following line:

            if (gamerSignedIn)

Step Nine: It would be nicer to have the avatar at the side of the screen, so modify the view matrix set to:

                avatarRenderer.View = Matrix.CreateLookAt(new Vector3(1, 1, -3), new Vector3(1, 1, 0), new Vector3(0, 1, 0)); //Set the view matrix supplying a sensible eye position, target and up direction

Step Ten: Now we need to draw the signed in gamer's picture and credentials. We make use of the Gamer object for the gamertag, the Texture2D set in the sign in event handler for the gamer picture and the GamerProfile object for the rest of the credentials. Again using the sprite batch, after the avatar draw call but before the if statement closing curly bracket add:

                spriteBatch.Begin();
spriteBatch.Draw(gamerPicture, new Rectangle(115, 81, 100, 100), Color.White);
spriteBatch.DrawString(arial, gamer.Gamertag, new Vector2(240, 80), Color.Black);
spriteBatch.DrawString(arial, profile.Motto, new Vector2(240, 120), new Color(10, 10, 10));
spriteBatch.DrawString(arial, "Zone: " + profile.GamerZone, new Vector2(100, 230), Color.Black);
spriteBatch.DrawString(arial, "Region: " + profile.Region, new Vector2(100, 260), Color.Black);
spriteBatch.DrawString(arial, "Rep: " + profile.Reputation, new Vector2(100, 290), Color.Black);
spriteBatch.DrawString(arial, "Titles played: " + profile.TitlesPlayed, new Vector2(100, 320), Color.Black);
spriteBatch.DrawString(arial, "Achievements: " + profile.TotalAchievements, new Vector2(100, 350), Color.Black);
spriteBatch.DrawString(arial, "Score: " + profile.GamerScore, new Vector2(100, 380), Color.Black);
spriteBatch.End();

Step Eleven: Now we need to add the event handling functions which are set up and referenced in the game constructor. The sign in event handler copies the gamer object, profile object and gamer picture. The avatar description is set to that of the gamer's avatar, and a new renderer is created from this description. The gamer signed in flag is also set to true. The signout event handler however just sets this flag to false. After the draw function add:

        void SignedInGamer_SignedIn(object sender, SignedInEventArgs e)
{
gamer = e.Gamer;
profile = e.Gamer.GetProfile();
gamerPicture = profile.GamerPicture;

avatarDescription = e.Gamer.Avatar;
avatarRenderer = new AvatarRenderer(avatarDescription); //Create a renderer for the avatar we have just randomly created

gamerSignedIn = true;
}
void SignedInGamer_SignedOut(object sender, SignedOutEventArgs e)
{
gamerSignedIn = false;
}

Step Twelve: Add a new sprite font named "Arial", in the spritefont xml description set the fontname tag to "Arial" and the font size to 24. Also download the background file from here and include it in the Content folder of the solution. (Make sure it's included in the project)

Step Thirteen: Deploy and run on your Xbox 360


So what have we achieved here? We've added some basic event handlers to handle signing in and out or profiles, and we've taken this signed in player's avatar and other details and rendered them to the screen. It is worth noting however that there are a couple of areas where this will fall down. Notably that if the motto or gamertag is long then it'll go off the yellow block. Additionally if multiple gamers are signing in and out then, the last player to sign in will have their avatar rendered, while if any signed in player signs out then the system assumes no players are signed in. However in the interests of keeping this tutorial simple, I've not gone over these elements.

Complete source (Game1.cs)

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace AvatarStepOne
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;

AvatarDescription avatarDescription;
AvatarRenderer avatarRenderer;
AvatarAnimation avatarCelebrateAnimation;

SpriteBatch spriteBatch;
SpriteFont arial;
bool gamerSignedIn = false;
GamerProfile profile;
Gamer gamer;
Texture2D gamerPicture;
Texture2D background;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
Components.Add(new GamerServicesComponent(this));
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
SignedInGamer.SignedIn += new EventHandler<SignedInEventArgs>(SignedInGamer_SignedIn);
SignedInGamer.SignedOut += new System.EventHandler<SignedOutEventArgs>(SignedInGamer_SignedOut);
}

protected override void LoadContent()
{
avatarCelebrateAnimation = new AvatarAnimation(AvatarAnimationPreset.Celebrate);
spriteBatch = new SpriteBatch(GraphicsDevice);
background = Content.Load<Texture2D>("background");
arial = Content.Load<SpriteFont>("Arial");
}

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

if (gamerSignedIn && avatarRenderer.IsLoaded)
{
avatarCelebrateAnimation.Update(gameTime.ElapsedGameTime, true);
}

base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();
spriteBatch.Draw(background, new Vector2(0), Color.White);
spriteBatch.End();

if (gamerSignedIn)
{
avatarRenderer.View = Matrix.CreateLookAt(new Vector3(1, 1, -3), new Vector3(1, 1, 0), new Vector3(0, 1, 0)); //Set the view matrix supplying a sensible eye position, target and up direction
avatarRenderer.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, .01f, 40.0f);
avatarRenderer.Draw(avatarCelebrateAnimation.BoneTransforms, avatarCelebrateAnimation.Expression);

spriteBatch.Begin();
spriteBatch.Draw(gamerPicture, new Rectangle(115, 81, 100, 100), Color.White);
spriteBatch.DrawString(arial, gamer.Gamertag, new Vector2(240, 80), Color.Black);
spriteBatch.DrawString(arial, profile.Motto, new Vector2(240, 120), new Color(10, 10, 10));
spriteBatch.DrawString(arial, "Zone: " + profile.GamerZone, new Vector2(100, 230), Color.Black);
spriteBatch.DrawString(arial, "Region: " + profile.Region, new Vector2(100, 260), Color.Black);
spriteBatch.DrawString(arial, "Rep: " + profile.Reputation, new Vector2(100, 290), Color.Black);
spriteBatch.DrawString(arial, "Titles played: " + profile.TitlesPlayed, new Vector2(100, 320), Color.Black);
spriteBatch.DrawString(arial, "Achievements: " + profile.TotalAchievements, new Vector2(100, 350), Color.Black);
spriteBatch.DrawString(arial, "Score: " + profile.GamerScore, new Vector2(100, 380), Color.Black);
spriteBatch.End();
}

base.Draw(gameTime);
}
void SignedInGamer_SignedIn(object sender, SignedInEventArgs e)
{
gamer = e.Gamer;
profile = e.Gamer.GetProfile();
gamerPicture = profile.GamerPicture;

avatarDescription = e.Gamer.Avatar;
avatarRenderer = new AvatarRenderer(avatarDescription); //Create a renderer for the avatar we have just randomly created

gamerSignedIn = true;
}
void SignedInGamer_SignedOut(object sender, SignedOutEventArgs e)
{
gamerSignedIn = false;
}
}
}

Following my introduction to the series of articles I'm writing on the use of avatars in XNA games, (which I'd advise you to read before this article) it would only make sense to start with the basics of implementing avatars in an XNA 3.1 game. The following shows an implementation of how to get avatars into XNA:

Step 1: Start a new XNA 3.1 project, and select the Xbox 360 3.1 template.


Step 2: In the variable declarations add:

AvatarDescription avatarDescription; //Stores the data relating to an avatar's appearance in a byte array, and allows generation of a random avatar
AvatarRenderer avatarRenderer; //Allows an easy method to render avatars
AvatarAnimation avatarCelebrateAnimation; //Stores the animation keyframe bone matrices so that the bones of the avatar can be modified

Step 3: In the Game1 class constructor add:

Components.Add(new GamerServicesComponent(this)); //Avatars require the GamerServices component so we need to attach it

Step 4: In the LoadContent function add:

avatarDescription = AvatarDescription.CreateRandom(); //Generate a random avatar, by randomising the description byte array with acceptable values 
avatarRenderer = new AvatarRenderer(avatarDescription); //Create a renderer for the avatar we have just randomly created
avatarCelebrateAnimation = new AvatarAnimation(AvatarAnimationPreset.Celebrate); // Load the celebrate animation 

Step 5: In the Update function add:

if (avatarRenderer.IsLoaded) //If the avatar has been loaded, update the animation
{
avatarCelebrateAnimation.Update(gameTime.ElapsedGameTime, true);
}

Step 6: In the Draw function add:

avatarRenderer.View = Matrix.CreateLookAt(new Vector3(0, 1, -3), new Vector3(0, 1, 0), new Vector3(0, 1, 0)); //Set the view matrix supplying a sensible eye position, target and up direction
avatarRenderer.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, .01f, 40.0f); //Again a sensible projection matrix
avatarRenderer.Draw(avatarCelebrateAnimation.BoneTransforms, avatarCelebrateAnimation.Expression); //Now draw the avatar, passing to it the animations bones and expression texture

Step 7: Deploy and run on your Xbox 360

So how does all that work? Basically what happens is we store data relating to the appearance of the avatar, the avatar's animation and a system to render it. Every update call we move through the animation a little, and then in every draw call we render out the avatar according to its appearance description and current animation bone world matrices.

Complete source (Game1.cs)

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace AvatarStepOne
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;

AvatarDescription avatarDescription;
AvatarRenderer avatarRenderer;
AvatarAnimation avatarCelebrateAnimation;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
Components.Add(new GamerServicesComponent(this));
}

protected override void LoadContent()
{
avatarDescription = AvatarDescription.CreateRandom();
avatarRenderer = new AvatarRenderer(avatarDescription);
avatarCelebrateAnimation = new AvatarAnimation(AvatarAnimationPreset.Celebrate);
}

protected override void Update(GameTime gameTime)
{
// Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

if (avatarRenderer.IsLoaded)
{
avatarCelebrateAnimation.Update(gameTime.ElapsedGameTime, true);
}

base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);

avatarRenderer.View = Matrix.CreateLookAt(new Vector3(0, 1, -3), new Vector3(0, 1, 0), new Vector3(0, 1, 0));
avatarRenderer.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, .01f, 40.0f);
avatarRenderer.Draw(avatarCelebrateAnimation.BoneTransforms, avatarCelebrateAnimation.Expression);

base.Draw(gameTime);
}
}
}
More Posts Next page »