AvatarMultipleAnimationsSample.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // AvatarMultipleAnimationsSample.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Collections.ObjectModel;
  13. using Microsoft.Xna.Framework;
  14. using Microsoft.Xna.Framework.GamerServices;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using Microsoft.Xna.Framework.Input;
  17. #endregion
  18. namespace AvatarMultipleAnimationsSample
  19. {
  20. /// <summary>
  21. /// Defines what animation the avatar should be using
  22. /// </summary>
  23. public enum AnimationPlaybackMode { All, Celebrate, Wave };
  24. /// <summary>
  25. /// This is the main type for your game
  26. /// </summary>
  27. public class AvatarMultipleAnimationsGame : Microsoft.Xna.Framework.Game
  28. {
  29. #region Fields
  30. GraphicsDeviceManager graphics;
  31. SpriteBatch spriteBatch;
  32. SpriteFont font;
  33. // Description, renderer, and animation for
  34. // loading and drawing an animated avatar
  35. AvatarDescription avatarDescription;
  36. AvatarRenderer avatarRenderer;
  37. AvatarAnimation waveAnimation;
  38. AvatarAnimation celebrateAnimation;
  39. // List of the final list of bone transforms.
  40. // The list will contain both transforms from the wave and clap animations.
  41. List<Matrix> finalBoneTransforms = new List<Matrix>(AvatarRenderer.BoneCount);
  42. // List of the bone index values for the right arm and its children
  43. List<int> rightArmBones;
  44. // Playback mode defines what animations should be playing
  45. AnimationPlaybackMode animationPlaybackMode;
  46. // matrices used to draw the avatar
  47. Matrix world;
  48. Matrix view;
  49. Matrix projection;
  50. // The current input states. These are updated in the HandleInput function,
  51. // and used primarily in the UpdateCamera function.
  52. GamePadState currentGamePadState;
  53. GamePadState lastGamePadState;
  54. // the following constants control the speed at which the camera moves
  55. // how fast does the camera move up, down, left, and right?
  56. const float CameraRotateSpeed = .1f;
  57. // how fast does the camera zoom in and out?
  58. const float CameraZoomSpeed = .01f;
  59. // the camera can't be further away than this distance
  60. const float CameraMaxDistance = 10.0f;
  61. // and it can't be closer than this
  62. const float CameraMinDistance = 2.0f;
  63. // the following constants control the camera's default position
  64. const float CameraDefaultArc = 30.0f;
  65. const float CameraDefaultRotation = 0;
  66. const float CameraDefaultDistance = 3.0f;
  67. // Camera control values
  68. float cameraArc = CameraDefaultArc;
  69. float cameraRotation = CameraDefaultRotation;
  70. float cameraDistance = CameraDefaultDistance;
  71. #endregion
  72. #region Initialization
  73. /// <summary>
  74. /// Constructor.
  75. /// </summary>
  76. public AvatarMultipleAnimationsGame()
  77. {
  78. graphics = new GraphicsDeviceManager(this);
  79. Content.RootDirectory = "Content";
  80. graphics.PreferredBackBufferWidth = 1280;
  81. graphics.PreferredBackBufferHeight = 720;
  82. graphics.PreferMultiSampling = true;
  83. // Avatars require GamerServices
  84. Components.Add(new GamerServicesComponent(this));
  85. }
  86. /// <summary>
  87. /// Load your graphics content.
  88. /// </summary>
  89. protected override void LoadContent()
  90. {
  91. spriteBatch = new SpriteBatch(GraphicsDevice);
  92. font = Content.Load<SpriteFont>("Font");
  93. // Create random avatar description and load the renderer and animation
  94. avatarDescription = AvatarDescription.CreateRandom();
  95. avatarRenderer = new AvatarRenderer(avatarDescription);
  96. // Load the preset animations
  97. waveAnimation = new AvatarAnimation(AvatarAnimationPreset.Wave);
  98. celebrateAnimation = new AvatarAnimation(AvatarAnimationPreset.Celebrate);
  99. // Find the bone index values for the right arm and its children
  100. rightArmBones = FindInfluencedBones(AvatarBone.ShoulderRight,
  101. avatarRenderer.ParentBones);
  102. for (int i = 0; i < AvatarRenderer.BoneCount; ++i)
  103. {
  104. finalBoneTransforms.Add(Matrix.Identity);
  105. }
  106. // Initialize the rendering matrices
  107. world = Matrix.CreateRotationY(MathHelper.Pi);
  108. projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
  109. GraphicsDevice.Viewport.AspectRatio,
  110. .01f, 200.0f);
  111. }
  112. #endregion
  113. #region Update and Draw
  114. /// <summary>
  115. /// Allows the game to run logic.
  116. /// </summary>
  117. protected override void Update(GameTime gameTime)
  118. {
  119. HandleInput();
  120. UpdateCamera(gameTime);
  121. // Set avatar rendering matrices
  122. avatarRenderer.World = world;
  123. avatarRenderer.View = view;
  124. avatarRenderer.Projection = projection;
  125. // Update the current animation and world space bones
  126. if (avatarRenderer.State == AvatarRendererState.Ready)
  127. {
  128. waveAnimation.Update(gameTime.ElapsedGameTime, true);
  129. celebrateAnimation.Update(gameTime.ElapsedGameTime, true);
  130. UpdateTransforms();
  131. }
  132. base.Update(gameTime);
  133. }
  134. /// <summary>
  135. /// This is called when the game should draw itself.
  136. /// </summary>
  137. protected override void Draw(GameTime gameTime)
  138. {
  139. GraphicsDevice.Clear(Color.CornflowerBlue);
  140. string message = "Playing: ";
  141. if (animationPlaybackMode == AnimationPlaybackMode.All)
  142. {
  143. message += "Celebrate + Wave";
  144. }
  145. else if (animationPlaybackMode == AnimationPlaybackMode.Celebrate)
  146. {
  147. message += "Celebrate";
  148. }
  149. else if (animationPlaybackMode == AnimationPlaybackMode.Wave)
  150. {
  151. message += "Wave";
  152. }
  153. message += "\n(Left Shoulder Button)";
  154. // Draw the text
  155. spriteBatch.Begin();
  156. spriteBatch.DrawString(font, message, new Vector2(161, 161), Color.Black);
  157. spriteBatch.DrawString(font, message, new Vector2(160, 160), Color.White);
  158. spriteBatch.End();
  159. // Draw the avatar with the combined transforms
  160. avatarRenderer.Draw(finalBoneTransforms, celebrateAnimation.Expression);
  161. base.Draw(gameTime);
  162. }
  163. /// <summary>
  164. /// Combines the transforms of the clap and wave animations
  165. /// </summary>
  166. private void UpdateTransforms()
  167. {
  168. // List of bone transforms from the clap and wave animations
  169. ReadOnlyCollection<Matrix> celebrateTransforms =
  170. celebrateAnimation.BoneTransforms;
  171. ReadOnlyCollection<Matrix> waveTransforms = waveAnimation.BoneTransforms;
  172. // Check to see if we are playing both of the animations
  173. if (animationPlaybackMode == AnimationPlaybackMode.All)
  174. {
  175. // Copy the celebrate transforms to the final list of transforms
  176. for (int i = 0; i < finalBoneTransforms.Count; i++)
  177. {
  178. finalBoneTransforms[i] = celebrateTransforms[i];
  179. }
  180. // Overwrite the transforms for the bones that are part of the right arm
  181. // with the wave animation transforms.
  182. for (int i = 0; i < rightArmBones.Count; i++)
  183. {
  184. finalBoneTransforms[rightArmBones[i]] =
  185. waveTransforms[rightArmBones[i]];
  186. }
  187. }
  188. // Check to see if we are just playing the celebrate animation
  189. else if (animationPlaybackMode == AnimationPlaybackMode.Celebrate)
  190. {
  191. // Copy the celebrate transforms to the final list of transforms
  192. for (int i = 0; i < finalBoneTransforms.Count; i++)
  193. {
  194. finalBoneTransforms[i] = celebrateTransforms[i];
  195. }
  196. }
  197. else if (animationPlaybackMode == AnimationPlaybackMode.Wave)
  198. {
  199. // We are just using the wave so use all bones
  200. for (int i = 0; i < finalBoneTransforms.Count; i++)
  201. {
  202. finalBoneTransforms[i] = waveTransforms[i];
  203. }
  204. }
  205. }
  206. /// <summary>
  207. /// Creates a list of bone index values for the given avatar bone
  208. /// and its children.
  209. /// </summary>
  210. /// <param name="avatarBone">The root bone to start search</param>
  211. /// <param name="parentBones">List of parent bones from the avatar
  212. /// renderer</param>
  213. /// <returns></returns>
  214. List<int> FindInfluencedBones(AvatarBone avatarBone,
  215. ReadOnlyCollection<int> parentBones)
  216. {
  217. // New list of bones that will be influenced
  218. List<int> influencedList = new List<int>();
  219. // Add the first bone
  220. influencedList.Add((int)avatarBone);
  221. // Start searching after the first bone
  222. int currentBoneID = influencedList[0] + 1;
  223. // Loop until we are done with all of the bones
  224. while (currentBoneID < parentBones.Count)
  225. {
  226. // Check to see if the current bone is a child of any of the
  227. // previous bones we have found
  228. if (influencedList.Contains(parentBones[currentBoneID]))
  229. {
  230. // Add the bone to the influenced list
  231. influencedList.Add(currentBoneID);
  232. }
  233. // Move to the next bone
  234. currentBoneID++;
  235. }
  236. return influencedList;
  237. }
  238. #endregion
  239. #region Input and Camera
  240. /// <summary>
  241. /// Handles input for quitting the game.
  242. /// </summary>
  243. void HandleInput()
  244. {
  245. lastGamePadState = currentGamePadState;
  246. currentGamePadState = GamePad.GetState(PlayerIndex.One);
  247. // Check for exit.
  248. if (currentGamePadState.Buttons.Back == ButtonState.Pressed)
  249. {
  250. Exit();
  251. }
  252. // Check to see if we need to change play modes
  253. if (currentGamePadState.Buttons.LeftShoulder == ButtonState.Pressed &&
  254. lastGamePadState.Buttons.LeftShoulder != ButtonState.Pressed)
  255. {
  256. animationPlaybackMode += 1;
  257. if (animationPlaybackMode > AnimationPlaybackMode.Wave)
  258. {
  259. animationPlaybackMode = AnimationPlaybackMode.All;
  260. }
  261. }
  262. // Check to see if we should load another random avatar
  263. if (currentGamePadState.Buttons.RightShoulder == ButtonState.Pressed &&
  264. lastGamePadState.Buttons.RightShoulder != ButtonState.Pressed)
  265. {
  266. avatarDescription = AvatarDescription.CreateRandom();
  267. avatarRenderer = new AvatarRenderer(avatarDescription);
  268. }
  269. }
  270. /// <summary>
  271. /// Handles input for moving the camera.
  272. /// </summary>
  273. void UpdateCamera(GameTime gameTime)
  274. {
  275. float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds;
  276. // should we reset the camera?
  277. if (currentGamePadState.Buttons.RightStick == ButtonState.Pressed)
  278. {
  279. cameraArc = CameraDefaultArc;
  280. cameraDistance = CameraDefaultDistance;
  281. cameraRotation = CameraDefaultRotation;
  282. }
  283. // Check for input to rotate the camera up and down around the model.
  284. cameraArc += currentGamePadState.ThumbSticks.Right.Y * time *
  285. CameraRotateSpeed;
  286. // Limit the arc movement.
  287. cameraArc = MathHelper.Clamp(cameraArc, -90.0f, 90.0f);
  288. // Check for input to rotate the camera around the model.
  289. cameraRotation += currentGamePadState.ThumbSticks.Right.X * time *
  290. CameraRotateSpeed;
  291. // Check for input to zoom camera in and out.
  292. cameraDistance += currentGamePadState.Triggers.Left * time
  293. * CameraZoomSpeed;
  294. cameraDistance -= currentGamePadState.Triggers.Right * time
  295. * CameraZoomSpeed;
  296. // clamp the camera distance so it doesn't get too close or too far away.
  297. cameraDistance = MathHelper.Clamp(cameraDistance,
  298. CameraMinDistance, CameraMaxDistance);
  299. Matrix unrotatedView = Matrix.CreateLookAt(
  300. new Vector3(0, 0, cameraDistance), new Vector3(0, 1, 0), Vector3.Up);
  301. view = Matrix.CreateRotationY(MathHelper.ToRadians(cameraRotation)) *
  302. Matrix.CreateRotationX(MathHelper.ToRadians(cameraArc)) *
  303. unrotatedView;
  304. }
  305. #endregion
  306. }
  307. #region Entry Point
  308. /// <summary>
  309. /// The main entry point for the application.
  310. /// </summary>
  311. static class Program
  312. {
  313. static void Main()
  314. {
  315. using (AvatarMultipleAnimationsGame game = new AvatarMultipleAnimationsGame())
  316. {
  317. game.Run();
  318. }
  319. }
  320. }
  321. #endregion
  322. }