#region File Description //----------------------------------------------------------------------------- // AvatarAnimationBlendingSample.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System; using System.Collections.ObjectModel; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; #endregion namespace AvatarAnimationBlendingSample { /// /// This sample demonstrates how to blend multiple avatar animations /// public class AvatarAnimationBlendingGame : Microsoft.Xna.Framework.Game { #region Fields GraphicsDeviceManager graphics; SpriteBatch spriteBatch; SpriteFont font; // Description, renderer, and animation for // loading and drawing an animated avatar AvatarDescription avatarDescription; AvatarRenderer avatarRenderer; AvatarBlendedAnimation blendedAnimation; AvatarAnimation[] avatarAnimations; AvatarAnimation noBlendingAnimation; // Should we use blending? bool useAnimationBlending = true; // matrices used to draw the avatar Matrix world; Matrix view; Matrix projection; // the current input states. These are updated in the HandleInput function, // and used primarily in the UpdateCamera function. GamePadState currentGamePadState; GamePadState lastGamePadState; // the following constants control the speed at which the camera moves // how fast does the camera move up, down, left, and right? const float CameraRotateSpeed = .1f; // how fast does the camera zoom in and out? const float CameraZoomSpeed = .01f; // the camera can't be further away than this distance const float CameraMaxDistance = 10.0f; // and it can't be closer than this const float CameraMinDistance = 2.0f; // the following constants control the camera's default position const float CameraDefaultArc = 30.0f; const float CameraDefaultRotation = 0; const float CameraDefaultDistance = 3.0f; // Camera control values float cameraArc = CameraDefaultArc; float cameraRotation = CameraDefaultRotation; float cameraDistance = CameraDefaultDistance; #endregion #region Initialization /// /// Constructor. /// public AvatarAnimationBlendingGame() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.PreferredBackBufferWidth = 1280; graphics.PreferredBackBufferHeight = 720; graphics.PreferMultiSampling = true; // Avatars require GamerServices Components.Add(new GamerServicesComponent(this)); } /// /// Load your graphics content. /// protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); font = Content.Load("Font"); // Create random avatar description and load the renderer and animation avatarDescription = AvatarDescription.CreateRandom(); avatarRenderer = new AvatarRenderer(avatarDescription); // Load 4 of the preset animations avatarAnimations = new AvatarAnimation[4]; avatarAnimations[0] = new AvatarAnimation(AvatarAnimationPreset.Stand0); avatarAnimations[1] = new AvatarAnimation(AvatarAnimationPreset.Celebrate); avatarAnimations[2] = new AvatarAnimation(AvatarAnimationPreset.Clap); avatarAnimations[3] = new AvatarAnimation(AvatarAnimationPreset.Wave); // Create new blended animation blendedAnimation = new AvatarBlendedAnimation(avatarAnimations[0]); noBlendingAnimation = avatarAnimations[0]; // Initialize the rendering matrices world = Matrix.CreateRotationY(MathHelper.Pi); projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, .01f, 200.0f); } #endregion #region Update and Draw /// /// Allows the game to run logic. /// protected override void Update(GameTime gameTime) { HandleInput(); UpdateCamera(gameTime); // Set avatar rendering matrices avatarRenderer.World = world; avatarRenderer.View = view; avatarRenderer.Projection = projection; // Update the current animation and world space bones if (avatarRenderer.State == AvatarRendererState.Ready) { if (useAnimationBlending) { blendedAnimation.Update(gameTime.ElapsedGameTime, true); } else { noBlendingAnimation.Update(gameTime.ElapsedGameTime, true); } } base.Update(gameTime); } /// /// This is called when the game should draw itself. /// protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); string message = "Blending: " + (useAnimationBlending ? "On" : "Off") + "\n(Left Shoulder Button)"; // Draw the text spriteBatch.Begin(); spriteBatch.DrawString(font, message, new Vector2(161, 161), Color.Black); spriteBatch.DrawString(font, message, new Vector2(160, 160), Color.White); spriteBatch.End(); // Draw the avatar if (useAnimationBlending) avatarRenderer.Draw(blendedAnimation); else avatarRenderer.Draw(noBlendingAnimation); base.Draw(gameTime); } #endregion #region Input and Camera /// /// Handles input for quitting the game. /// void HandleInput() { lastGamePadState = currentGamePadState; currentGamePadState = GamePad.GetState(PlayerIndex.One); // Check for exit. if (currentGamePadState.Buttons.Back == ButtonState.Pressed) { Exit(); } // Check to see if we need to change blending bool if (currentGamePadState.Buttons.LeftShoulder == ButtonState.Pressed && lastGamePadState.Buttons.LeftShoulder != ButtonState.Pressed) { useAnimationBlending = !useAnimationBlending; } // Check to see if we should load another random avatar if (currentGamePadState.Buttons.RightShoulder == ButtonState.Pressed && lastGamePadState.Buttons.RightShoulder != ButtonState.Pressed) { avatarDescription = AvatarDescription.CreateRandom(); avatarRenderer = new AvatarRenderer(avatarDescription); } // Check to see if we need to play another animation if (currentGamePadState.Buttons.A == ButtonState.Pressed && lastGamePadState.Buttons.A != ButtonState.Pressed) { blendedAnimation.Play(avatarAnimations[1]); noBlendingAnimation = avatarAnimations[1]; } else if (currentGamePadState.Buttons.B == ButtonState.Pressed && lastGamePadState.Buttons.B != ButtonState.Pressed) { blendedAnimation.Play(avatarAnimations[2]); noBlendingAnimation = avatarAnimations[2]; } else if (currentGamePadState.Buttons.X == ButtonState.Pressed && lastGamePadState.Buttons.X != ButtonState.Pressed) { blendedAnimation.Play(avatarAnimations[0]); noBlendingAnimation = avatarAnimations[0]; } else if (currentGamePadState.Buttons.Y == ButtonState.Pressed && lastGamePadState.Buttons.Y != ButtonState.Pressed) { blendedAnimation.Play(avatarAnimations[3]); noBlendingAnimation = avatarAnimations[3]; } } /// /// Handles input for moving the camera. /// void UpdateCamera(GameTime gameTime) { float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds; // should we reset the camera? if (currentGamePadState.Buttons.RightStick == ButtonState.Pressed) { cameraArc = CameraDefaultArc; cameraDistance = CameraDefaultDistance; cameraRotation = CameraDefaultRotation; } // Check for input to rotate the camera up and down around the model. cameraArc += currentGamePadState.ThumbSticks.Right.Y * time * CameraRotateSpeed; // Limit the arc movement. cameraArc = MathHelper.Clamp(cameraArc, -90.0f, 90.0f); // Check for input to rotate the camera around the model. cameraRotation += currentGamePadState.ThumbSticks.Right.X * time * CameraRotateSpeed; // Check for input to zoom camera in and out. cameraDistance += currentGamePadState.Triggers.Left * time * CameraZoomSpeed; cameraDistance -= currentGamePadState.Triggers.Right * time * CameraZoomSpeed; // clamp the camera distance so it doesn't get too close or too far away. cameraDistance = MathHelper.Clamp(cameraDistance, CameraMinDistance, CameraMaxDistance); Matrix unrotatedView = Matrix.CreateLookAt( new Vector3(0, 0, cameraDistance), new Vector3(0, 1, 0), Vector3.Up); view = Matrix.CreateRotationY(MathHelper.ToRadians(cameraRotation)) * Matrix.CreateRotationX(MathHelper.ToRadians(cameraArc)) * unrotatedView; } #endregion } #region Entry Point /// /// The main entry point for the application. /// static class Program { static void Main() { using (AvatarAnimationBlendingGame game = new AvatarAnimationBlendingGame()) { game.Run(); } } } #endregion }