CustomAvatarAnimationSample.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // CustomAvatarAnimationSample.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 Microsoft.Xna.Framework;
  13. using Microsoft.Xna.Framework.Content;
  14. using Microsoft.Xna.Framework.GamerServices;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using Microsoft.Xna.Framework.Input;
  17. using CustomAvatarAnimation;
  18. #endregion
  19. namespace CustomAvatarAnimationSample
  20. {
  21. /// <summary>
  22. /// The possible animation types on the avatar.
  23. /// </summary>
  24. public enum AnimationType { Idle1, Idle2, Idle3, Idle4, Walk,
  25. Jump, Kick, Punch, Faint };
  26. /// <summary>
  27. /// This is the main type for your game
  28. /// </summary>
  29. public class CustomAvatarAnimationSampleGame : Microsoft.Xna.Framework.Game
  30. {
  31. #region Graphics Data
  32. GraphicsDeviceManager graphics;
  33. // Model to display the ground
  34. Model groundModel;
  35. // World, View and Projection matricies used for rendering
  36. Matrix world;
  37. Matrix view;
  38. Matrix projection;
  39. // the following constants control the camera's default position
  40. const float CameraDefaultArc = MathHelper.Pi / 10;
  41. const float CameraDefaultRotation = MathHelper.Pi;
  42. const float CameraDefaultDistance = 2.5f;
  43. // Camera values
  44. float cameraArc = CameraDefaultArc;
  45. float cameraRotation = CameraDefaultRotation;
  46. float cameraDistance = CameraDefaultDistance;
  47. #endregion
  48. #region Avatar Data
  49. // The AvatarDescription and AvatarRenderer that are used to render the avatar
  50. AvatarRenderer avatarRenderer;
  51. AvatarDescription avatarDescription;
  52. // Animations that will be used
  53. IAvatarAnimation[] animations;
  54. // Tells us if we are using an idle, walking, or other animations
  55. AnimationType currentType;
  56. #endregion
  57. #region Fields
  58. // Store the current and last gamepad state
  59. GamePadState currentGamePadState;
  60. GamePadState lastGamePadState;
  61. // A random number generator for picking new idle animations
  62. Random random = new Random();
  63. #endregion
  64. #region Initialization
  65. /// <summary>
  66. /// Creates a new AvatarCustomAnimationSample object.
  67. /// </summary>
  68. public CustomAvatarAnimationSampleGame()
  69. {
  70. // initialize the graphics
  71. graphics = new GraphicsDeviceManager(this);
  72. Content.RootDirectory = "Content";
  73. graphics.PreferredBackBufferWidth = 1280;
  74. graphics.PreferredBackBufferHeight = 720;
  75. graphics.PreferMultiSampling = true;
  76. // initialize gamer services
  77. Components.Add(new GamerServicesComponent(this));
  78. SignedInGamer.SignedIn += new EventHandler<SignedInEventArgs>(SignedInGamer_SignedIn);
  79. }
  80. /// <summary>
  81. /// Handle signed in gamer event as start avatar loading
  82. /// </summary>
  83. void SignedInGamer_SignedIn(object sender, SignedInEventArgs e)
  84. {
  85. // Only load the avatar for player one
  86. if (e.Gamer.PlayerIndex == PlayerIndex.One)
  87. {
  88. // Load the player one avatar
  89. LoadAvatar(e.Gamer);
  90. }
  91. }
  92. /// <summary>
  93. /// Load all graphical content.
  94. /// </summary>
  95. protected override void LoadContent()
  96. {
  97. // Load custom animations
  98. CustomAvatarAnimationData animationData;
  99. // We will use 8 different animations
  100. animations = new IAvatarAnimation[9];
  101. // Load the idle animations
  102. for (int i = 0; i < 4; i++)
  103. {
  104. animations[i] = new AvatarAnimation(
  105. (AvatarAnimationPreset)((int)AvatarAnimationPreset.Stand0 + i));
  106. }
  107. // Load the walk animation
  108. animationData = Content.Load<CustomAvatarAnimationData>("Walk");
  109. animations[4] = new CustomAvatarAnimationPlayer(animationData.Name, animationData.Length,
  110. animationData.Keyframes, animationData.ExpressionKeyframes);
  111. // Load the jump animation
  112. animationData = Content.Load<CustomAvatarAnimationData>("Jump");
  113. animations[5] = new CustomAvatarAnimationPlayer(animationData.Name, animationData.Length,
  114. animationData.Keyframes, animationData.ExpressionKeyframes);
  115. // Load the kick animation
  116. animationData = Content.Load<CustomAvatarAnimationData>("Kick");
  117. animations[6] = new CustomAvatarAnimationPlayer(animationData.Name, animationData.Length,
  118. animationData.Keyframes, animationData.ExpressionKeyframes);
  119. // Load the punch animation
  120. animationData = Content.Load<CustomAvatarAnimationData>("Punch");
  121. animations[7] = new CustomAvatarAnimationPlayer(animationData.Name, animationData.Length,
  122. animationData.Keyframes, animationData.ExpressionKeyframes);
  123. // Load the faint animation
  124. animationData = Content.Load<CustomAvatarAnimationData>("Faint");
  125. animations[8] = new CustomAvatarAnimationPlayer(animationData.Name, animationData.Length,
  126. animationData.Keyframes, animationData.ExpressionKeyframes);
  127. // Load the model for the ground
  128. groundModel = Content.Load<Model>("ground");
  129. // Select a random idle animation to start
  130. PlayRandomIdle();
  131. // Create the projection to use
  132. projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f),
  133. GraphicsDevice.Viewport.AspectRatio, .01f, 200.0f);
  134. world = Matrix.Identity;
  135. }
  136. #endregion
  137. #region Updating
  138. protected override void Update(GameTime gameTime)
  139. {
  140. // Get the current gamepad state and store the old
  141. lastGamePadState = currentGamePadState;
  142. currentGamePadState = GamePad.GetState(PlayerIndex.One);
  143. // Allows the game to exit
  144. if (currentGamePadState.Buttons.Back == ButtonState.Pressed)
  145. this.Exit();
  146. // Handle gamer input
  147. HandleAvatarInput(gameTime);
  148. HandleCameraInput();
  149. // Loop animation if we are walking
  150. bool loopAnimation = (currentType == AnimationType.Walk);
  151. // Update the current animation
  152. animations[(int)currentType].Update(gameTime.ElapsedGameTime, loopAnimation);
  153. // Check to see if we need to end the animation
  154. if (!loopAnimation)
  155. {
  156. if (animations[(int)currentType].CurrentPosition ==
  157. animations[(int)currentType].Length)
  158. {
  159. // Start new idle animation
  160. PlayRandomIdle();
  161. }
  162. }
  163. base.Update(gameTime);
  164. }
  165. #endregion
  166. #region Drawing
  167. protected override void Draw(GameTime gameTime)
  168. {
  169. GraphicsDevice.Clear(Color.CornflowerBlue);
  170. // Draw the ground first since the avatar has transparent parts
  171. groundModel.Draw(Matrix.Identity, view, projection);
  172. // Draw the avatar
  173. if (avatarRenderer != null)
  174. {
  175. avatarRenderer.Draw(animations[(int)currentType]);
  176. }
  177. base.Draw(gameTime);
  178. }
  179. #endregion
  180. #region Input Handling
  181. /// <summary>
  182. /// Check for user input to play animations on the avatar
  183. /// </summary>
  184. private void HandleAvatarInput(GameTime gameTime)
  185. {
  186. // Check to see if the user wants to load a random avatar
  187. // by pressing the Right Shoulder
  188. if (currentGamePadState.Buttons.RightShoulder == ButtonState.Pressed &&
  189. lastGamePadState.Buttons.RightShoulder != ButtonState.Pressed)
  190. {
  191. LoadRandomAvatar();
  192. }
  193. // Check to see if the user wants to load the users avatar
  194. // by pressing the Left Shoulder
  195. else if (currentGamePadState.Buttons.LeftShoulder == ButtonState.Pressed &&
  196. lastGamePadState.Buttons.LeftShoulder != ButtonState.Pressed)
  197. {
  198. // Load the users avatar
  199. if (SignedInGamer.SignedInGamers[PlayerIndex.One] != null)
  200. {
  201. LoadAvatar(SignedInGamer.SignedInGamers[PlayerIndex.One]);
  202. }
  203. }
  204. // Check to see if the user wants to play one of the other
  205. // animations by pressing one of the gamepad buttons
  206. if (currentGamePadState.Buttons.A == ButtonState.Pressed &&
  207. lastGamePadState.Buttons.A != ButtonState.Pressed)
  208. {
  209. PlayAnimation(AnimationType.Jump);
  210. }
  211. if (currentGamePadState.Buttons.B == ButtonState.Pressed &&
  212. lastGamePadState.Buttons.B != ButtonState.Pressed)
  213. {
  214. PlayAnimation(AnimationType.Kick);
  215. }
  216. if (currentGamePadState.Buttons.X == ButtonState.Pressed &&
  217. lastGamePadState.Buttons.X != ButtonState.Pressed)
  218. {
  219. PlayAnimation(AnimationType.Punch);
  220. }
  221. if (currentGamePadState.Buttons.Y == ButtonState.Pressed &&
  222. lastGamePadState.Buttons.Y != ButtonState.Pressed)
  223. {
  224. PlayAnimation(AnimationType.Faint);
  225. }
  226. // Update the avatars location
  227. UpdateAvatarMovement(gameTime);
  228. }
  229. /// <summary>
  230. /// Update the avatars movement based on user input
  231. /// </summary>
  232. private void UpdateAvatarMovement(GameTime gameTime)
  233. {
  234. // Create vector from the left thumbstick location
  235. Vector2 leftThumbStick = currentGamePadState.ThumbSticks.Left;
  236. // The direction for our Avatar
  237. Vector3 avatarForward = world.Forward;
  238. // The amount we want to translate
  239. Vector3 translate = Vector3.Zero;
  240. // Clamp thumbstick to make sure the user really wants to move
  241. if (leftThumbStick.Length() > 0.2f)
  242. {
  243. // Create our direction vector
  244. leftThumbStick.Normalize();
  245. // Find the new avatar forward
  246. avatarForward.X = leftThumbStick.X;
  247. avatarForward.Y = 0;
  248. avatarForward.Z = -leftThumbStick.Y;
  249. // Translate the thumbstick using the current camera rotation
  250. avatarForward = Vector3.Transform(avatarForward,
  251. Matrix.CreateRotationY(cameraRotation));
  252. avatarForward.Normalize();
  253. // Determine the amount of translation
  254. translate = avatarForward
  255. * ((float)gameTime.ElapsedGameTime.TotalMilliseconds
  256. * 0.0009f);
  257. // We are now walking
  258. currentType = AnimationType.Walk;
  259. }
  260. else
  261. {
  262. // If we were walking last frame pick a random idle animation
  263. if (currentType == AnimationType.Walk)
  264. {
  265. PlayRandomIdle();
  266. }
  267. }
  268. // Update the world matrix
  269. world.Forward = avatarForward;
  270. // Normalize the matrix
  271. world.Right = Vector3.Cross(world.Forward, Vector3.Up);
  272. world.Right = Vector3.Normalize(world.Right);
  273. world.Up = Vector3.Cross(world.Right, world.Forward);
  274. world.Up = Vector3.Normalize(world.Up);
  275. // Add translation
  276. world.Translation += translate;
  277. // Set the avatar renderer world matrix
  278. if (avatarRenderer != null)
  279. {
  280. avatarRenderer.World = world;
  281. }
  282. }
  283. /// <summary>
  284. /// Move camera based on user input
  285. /// </summary>
  286. private void HandleCameraInput()
  287. {
  288. // should we reset the camera?
  289. if (currentGamePadState.Buttons.RightStick == ButtonState.Pressed)
  290. {
  291. cameraArc = CameraDefaultArc;
  292. cameraDistance = CameraDefaultDistance;
  293. cameraRotation = CameraDefaultRotation;
  294. }
  295. // Update Camera
  296. cameraArc -= currentGamePadState.ThumbSticks.Right.Y * 0.05f;
  297. cameraRotation += currentGamePadState.ThumbSticks.Right.X * 0.1f;
  298. cameraDistance += currentGamePadState.Triggers.Left * 0.1f;
  299. cameraDistance -= currentGamePadState.Triggers.Right * 0.1f;
  300. // Limit the camera movement
  301. if (cameraDistance > 5.0f)
  302. cameraDistance = 5.0f;
  303. else if (cameraDistance < 2.0f)
  304. cameraDistance = 2.0f;
  305. if (cameraArc > MathHelper.Pi / 5)
  306. cameraArc = MathHelper.Pi / 5;
  307. else if (cameraArc < -(MathHelper.Pi / 5))
  308. cameraArc = -(MathHelper.Pi / 5);
  309. // Update the camera position
  310. Vector3 cameraPos = new Vector3(0, cameraDistance, cameraDistance);
  311. cameraPos = Vector3.Transform(cameraPos, Matrix.CreateRotationX(cameraArc));
  312. cameraPos = Vector3.Transform(cameraPos,
  313. Matrix.CreateRotationY(cameraRotation));
  314. cameraPos += world.Translation;
  315. // Create new view matrix
  316. view = Matrix.CreateLookAt(cameraPos, world.Translation
  317. + new Vector3(0, 1.2f, 0), Vector3.Up);
  318. // Set the new view on the avatar renderer
  319. if (avatarRenderer != null)
  320. {
  321. avatarRenderer.View = view;
  322. }
  323. }
  324. #endregion
  325. #region Animation Selection
  326. /// <summary>
  327. /// Start playing a random idle animation
  328. /// </summary>
  329. private void PlayRandomIdle()
  330. {
  331. PlayAnimation((AnimationType)random.Next((int)AnimationType.Idle4));
  332. }
  333. /// <summary>
  334. /// Start playing one of the other animations that were loaded
  335. /// </summary>
  336. private void PlayAnimation(AnimationType animation)
  337. {
  338. animations[(int)animation].CurrentPosition = TimeSpan.Zero;
  339. currentType = animation;
  340. }
  341. #endregion
  342. #region Avatar Loading
  343. /// <summary>
  344. /// Load the avatar for a gamer
  345. /// </summary>
  346. private void LoadAvatar(Gamer gamer)
  347. {
  348. UnloadAvatar();
  349. AvatarDescription.BeginGetFromGamer(gamer, LoadAvatarDescription, null);
  350. }
  351. /// <summary>
  352. /// AsyncCallback for loading the AvatarDescription
  353. /// </summary>
  354. private void LoadAvatarDescription(IAsyncResult result)
  355. {
  356. // Get the AvatarDescription for the gamer
  357. avatarDescription = AvatarDescription.EndGetFromGamer(result);
  358. // Load the AvatarRenderer if description is valid
  359. if (avatarDescription.IsValid)
  360. {
  361. avatarRenderer = new AvatarRenderer(avatarDescription);
  362. avatarRenderer.Projection = projection;
  363. }
  364. // Load random for an invalid description
  365. else
  366. {
  367. LoadRandomAvatar();
  368. }
  369. }
  370. /// <summary>
  371. /// Load a random avatar
  372. /// </summary>
  373. private void LoadRandomAvatar()
  374. {
  375. UnloadAvatar();
  376. avatarDescription = AvatarDescription.CreateRandom();
  377. avatarRenderer = new AvatarRenderer(avatarDescription);
  378. avatarRenderer.Projection = projection;
  379. }
  380. /// <summary>
  381. /// Unloads the current avatar
  382. /// </summary>
  383. private void UnloadAvatar()
  384. {
  385. // Dispose the current Avatar
  386. if (avatarRenderer != null)
  387. {
  388. avatarRenderer.Dispose();
  389. avatarRenderer = null;
  390. }
  391. }
  392. #endregion
  393. #region Entry Point
  394. /// <summary>
  395. /// The main entry point for the application.
  396. /// </summary>
  397. static void Main(string[] args)
  398. {
  399. using (CustomAvatarAnimationSampleGame game =
  400. new CustomAvatarAnimationSampleGame())
  401. {
  402. game.Run();
  403. }
  404. }
  405. #endregion
  406. }
  407. }