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;
}
}
}
Posted
Sat, Jul 11 2009 4:44 PM
by
Barnaby Smith