WaypointSample.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // WaypointSample.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.Linq;
  13. using Microsoft.Xna.Framework;
  14. using Microsoft.Xna.Framework.Audio;
  15. using Microsoft.Xna.Framework.Content;
  16. using Microsoft.Xna.Framework.GamerServices;
  17. using Microsoft.Xna.Framework.Graphics;
  18. using Microsoft.Xna.Framework.Input;
  19. using Microsoft.Xna.Framework.Input.Touch;
  20. using Microsoft.Xna.Framework.Media;
  21. #endregion
  22. namespace Waypoint
  23. {
  24. /// <summary>
  25. /// This is the main type for your game
  26. /// </summary>
  27. public class WaypointSample : Microsoft.Xna.Framework.Game
  28. {
  29. #region Constants
  30. #if WINDOWS_PHONE
  31. /// <summary>
  32. /// Screen width in pixels
  33. /// </summary>
  34. const int screenWidth = 800;
  35. /// <summary>
  36. /// Screen height in pixels
  37. /// </summary>
  38. const int screenHeight = 480;
  39. #else
  40. /// <summary>
  41. /// Screen width in pixels
  42. /// </summary>
  43. const int screenWidth = 853;
  44. /// <summary>
  45. /// Screen height in pixels
  46. /// </summary>
  47. const int screenHeight = 480;
  48. #endif
  49. /// <summary>
  50. /// Cursor move speed in pixels per second
  51. /// </summary>
  52. const float cursorMoveSpeed = 250.0f;
  53. // the text we display on screen, created here to make our Draw method cleaner
  54. private const string helpText =
  55. "Use the arrow keys to move the cursor\n" +
  56. "Press A to place a waypoint\n" +
  57. "Press B to change steering behavior\n" +
  58. "Press X to reset the tank and waypoints\n";
  59. #endregion
  60. #region Fields
  61. // Graphics data
  62. GraphicsDeviceManager graphics;
  63. SpriteBatch spriteBatch;
  64. // Cursor data
  65. Texture2D cursorTexture;
  66. Vector2 cursorCenter;
  67. Vector2 cursorLocation;
  68. // HUD data
  69. SpriteFont hudFont;
  70. // Where the HUD draws on the screen
  71. Vector2 hudLocation;
  72. // Input data
  73. KeyboardState previousKeyboardState;
  74. GamePadState previousGamePadState;
  75. KeyboardState currentKeyboardState;
  76. GamePadState currentGamePadState;
  77. // The waypoint-following tank
  78. Tank tank;
  79. #if WINDOWS_PHONE
  80. //Menu Bar data
  81. Texture2D blankTexture;
  82. int menuBarButton1_Left = 150;
  83. int menuBarButton2_Left = 500;
  84. int menuBarButtonTop = 5;
  85. int menuBarButtonWidth = 150;
  86. int menuBarButtonHeight = 30;
  87. int menuBar_Height = 40;
  88. RenderTarget2D renderTarget;
  89. bool isBehaviorChangeRequested = false;
  90. bool isClearRequested = false;
  91. #endif
  92. #endregion
  93. #region Initialization
  94. /// <summary>
  95. /// Construct a WaypointSample object
  96. /// </summary>
  97. public WaypointSample()
  98. {
  99. graphics = new GraphicsDeviceManager(this);
  100. Content.RootDirectory = "Content";
  101. #if WINDOWS_PHONE
  102. // Frame rate is 30 fps by default for Windows Phone.
  103. TargetElapsedTime = TimeSpan.FromTicks(333333);
  104. // Pre-autoscale settings.
  105. graphics.PreferredBackBufferWidth = 480;
  106. graphics.PreferredBackBufferHeight = 800;
  107. graphics.SupportedOrientations = DisplayOrientation.Default;
  108. graphics.IsFullScreen = true;
  109. #else
  110. // Pre-autoscale settings.
  111. graphics.PreferredBackBufferWidth = screenWidth;
  112. graphics.PreferredBackBufferHeight = screenHeight;
  113. #endif
  114. tank = new Tank(this);
  115. Components.Add(tank);
  116. }
  117. /// <summary>
  118. /// Allows the game to perform any initialization it needs to before starting to run.
  119. /// This is where it can query for any required services and load any non-graphic
  120. /// related content. Calling base.Initialize will enumerate through any components
  121. /// and initialize them as well.
  122. /// </summary>
  123. protected override void Initialize()
  124. {
  125. // This places the HUD near the upper left corner of the screen
  126. hudLocation = new Vector2(
  127. (float)Math.Floor(screenWidth * .1f),
  128. (float)Math.Floor(screenHeight * .1f));
  129. // places the cursor in the center of the screen
  130. cursorLocation =
  131. new Vector2((float)screenWidth / 2, (float)screenHeight / 2);
  132. // places the tank halfway between the center of the screen and the
  133. // upper left corner
  134. tank.Reset(
  135. new Vector2((float)screenWidth / 4, (float)screenHeight / 4));
  136. base.Initialize();
  137. #if WINDOWS_PHONE
  138. renderTarget = new RenderTarget2D(graphics.GraphicsDevice, 800, 480);
  139. #endif
  140. }
  141. /// <summary>
  142. /// LoadContent will be called once per game and is the place to load
  143. /// all of your content.
  144. /// </summary>
  145. protected override void LoadContent()
  146. {
  147. // Create a new SpriteBatch, which can be used to draw textures.
  148. spriteBatch = new SpriteBatch(GraphicsDevice);
  149. cursorTexture = Content.Load<Texture2D>("cursor");
  150. cursorCenter =
  151. new Vector2(cursorTexture.Width / 2, cursorTexture.Height / 2);
  152. hudFont = Content.Load<SpriteFont>("HUDFont");
  153. #if WINDOWS_PHONE
  154. blankTexture = Content.Load<Texture2D>("blank");
  155. #endif
  156. }
  157. #endregion
  158. #region Update and Draw
  159. /// <summary>
  160. /// Allows the game to run logic such as updating the world,
  161. /// checking for collisions, gathering input, and playing audio.
  162. /// </summary>
  163. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  164. protected override void Update(GameTime gameTime)
  165. {
  166. // Allows the game to exit
  167. if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
  168. this.Exit();
  169. // TODO: Add your update logic here
  170. float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
  171. HandleInput(elapsedTime);
  172. base.Update(gameTime);
  173. }
  174. /// <summary>
  175. /// This is called when the game should draw itself.
  176. /// </summary>
  177. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  178. protected override void Draw(GameTime gameTime)
  179. {
  180. #if WINDOWS_PHONE
  181. GraphicsDevice.SetRenderTarget(renderTarget);
  182. #endif
  183. GraphicsDevice.Clear(Color.CornflowerBlue);
  184. base.Draw(gameTime);
  185. string HudString = "Behavior Type: " + tank.BehaviorType.ToString();
  186. spriteBatch.Begin();
  187. #if WINDOWS_PHONE
  188. DrawMenuBar();
  189. #endif
  190. // Draw the cursor
  191. spriteBatch.Draw(cursorTexture, cursorLocation, null, Color.White, 0f,
  192. cursorCenter, 1f, SpriteEffects.None, 0f);
  193. #if !WINDOWS_PHONE
  194. // Draw the string for current behavior
  195. spriteBatch.DrawString(hudFont, HudString, hudLocation, Color.White);
  196. // draw our helper text so users know what they're doing.
  197. spriteBatch.DrawString(hudFont, helpText, new Vector2(10f, 250f), Color.White);
  198. #endif
  199. spriteBatch.End();
  200. #if WINDOWS_PHONE
  201. GraphicsDevice.SetRenderTarget(null);
  202. spriteBatch.Begin();
  203. spriteBatch.Draw(renderTarget as Texture2D,
  204. new Vector2(240, 400),
  205. null,
  206. Color.White,
  207. MathHelper.PiOver2,
  208. new Vector2(400, 240),
  209. 1f,
  210. SpriteEffects.None,
  211. 0);
  212. spriteBatch.End();
  213. #endif
  214. }
  215. #if WINDOWS_PHONE
  216. private void DrawMenuBar()
  217. {
  218. //Draw white rectangle
  219. Rectangle rect = new Rectangle(0, 0, screenWidth, menuBar_Height);
  220. spriteBatch.Draw(blankTexture, rect, Color.White);
  221. //Draw first "Button"
  222. Rectangle buttonRect1 = new Rectangle(menuBarButton1_Left, menuBarButtonTop, menuBarButtonWidth, menuBarButtonHeight);
  223. spriteBatch.Draw(blankTexture, buttonRect1, Color.Orange);
  224. spriteBatch.DrawString(hudFont, "Clear", new Vector2(menuBarButton1_Left + /*50*/60, menuBarButtonTop * 2), Color.Black);
  225. //Draw second "Button"
  226. Rectangle buttonRect2 = new Rectangle(menuBarButton2_Left, menuBarButtonTop, menuBarButtonWidth, menuBarButtonHeight);
  227. spriteBatch.Draw(blankTexture, buttonRect2, Color.Orange);
  228. spriteBatch.DrawString(hudFont, tank.BehaviorType.ToString(), new Vector2(menuBarButton2_Left + 50, menuBarButtonTop * 2), Color.Black);
  229. }
  230. #endif
  231. #endregion
  232. #region Handle Input
  233. /// <summary>
  234. /// Read keyboard and gamepad input
  235. /// </summary>
  236. private void HandleInput(float elapsedTime)
  237. {
  238. previousGamePadState = currentGamePadState;
  239. previousKeyboardState = currentKeyboardState;
  240. currentGamePadState = GamePad.GetState(PlayerIndex.One);
  241. currentKeyboardState = Keyboard.GetState();
  242. // Allows the game to exit
  243. if (currentGamePadState.Buttons.Back == ButtonState.Pressed ||
  244. currentKeyboardState.IsKeyDown(Keys.Escape))
  245. this.Exit();
  246. // Update the cursor location by listening for left thumbstick input on
  247. // the GamePad and direction key input on the Keyboard, making sure to
  248. // keep the cursor inside the screen boundary
  249. cursorLocation.X +=
  250. currentGamePadState.ThumbSticks.Left.X * cursorMoveSpeed * elapsedTime;
  251. cursorLocation.Y -=
  252. currentGamePadState.ThumbSticks.Left.Y * cursorMoveSpeed * elapsedTime;
  253. if (currentKeyboardState.IsKeyDown(Keys.Up))
  254. {
  255. cursorLocation.Y -= elapsedTime * cursorMoveSpeed;
  256. }
  257. if (currentKeyboardState.IsKeyDown(Keys.Down))
  258. {
  259. cursorLocation.Y += elapsedTime * cursorMoveSpeed;
  260. }
  261. if (currentKeyboardState.IsKeyDown(Keys.Left))
  262. {
  263. cursorLocation.X -= elapsedTime * cursorMoveSpeed;
  264. }
  265. if (currentKeyboardState.IsKeyDown(Keys.Right))
  266. {
  267. cursorLocation.X += elapsedTime * cursorMoveSpeed;
  268. }
  269. #if WINDOWS_PHONE
  270. bool isTouchDetected = false;
  271. bool isMenuBarUsed = false;
  272. TouchCollection touches = TouchPanel.GetState();
  273. if (touches.Count == 1)
  274. {
  275. //Use only the single (first) touch point to make experience close to Windows/XBOX - Simulates move by mouse/gamepad & "A" button press
  276. TouchLocation touch = touches[0];
  277. if (touch.State != TouchLocationState.Invalid)
  278. {
  279. //TODO: Check on device and swap X/Y + remove Y tweaking. Workaround for EMU:
  280. double halfHeight = screenHeight / 2;
  281. double delta = halfHeight - touch.Position.X;
  282. //Check "button click" on menuBar
  283. if (halfHeight + delta < menuBar_Height)
  284. {
  285. Rectangle touchRect = new Rectangle((int)touch.Position.Y, (int)(halfHeight + delta - 5) - 5, 10, 10);
  286. Rectangle button1Rect = new Rectangle(menuBarButton1_Left, menuBarButtonTop, menuBarButtonWidth, menuBarButtonHeight);
  287. Rectangle button2Rect = new Rectangle(menuBarButton2_Left, menuBarButtonTop, menuBarButtonWidth, menuBarButtonHeight);
  288. bool button1Press, button2Press;
  289. button1Rect.Intersects(ref touchRect, out button1Press);
  290. button2Rect.Intersects(ref touchRect, out button2Press);
  291. if (button1Press && touch.State == TouchLocationState.Released)
  292. isClearRequested = true;
  293. else if (button2Press && touch.State == TouchLocationState.Released)
  294. isBehaviorChangeRequested = true;
  295. isMenuBarUsed = true;
  296. }
  297. else
  298. {
  299. cursorLocation.X = touch.Position.Y;
  300. cursorLocation.Y = (int)(halfHeight + delta);
  301. }
  302. //Don't let the cursor move under the MenuBar
  303. if (cursorLocation.Y < menuBar_Height + (cursorTexture.Height / 2))
  304. cursorLocation.Y = menuBar_Height + (cursorTexture.Height / 2);
  305. }
  306. if (touch.State == TouchLocationState.Released && !isMenuBarUsed)
  307. isTouchDetected = true;
  308. }
  309. else if (touches.Count > 1 && touches[0].State == TouchLocationState.Released) //Multiple touch simulates pressing "B" button press to change the behavior
  310. isBehaviorChangeRequested = true;
  311. #endif
  312. cursorLocation.X = MathHelper.Clamp(cursorLocation.X, 0f, screenWidth);
  313. cursorLocation.Y = MathHelper.Clamp(cursorLocation.Y, 0f, screenHeight);
  314. // Change the tank move behavior if the user pressed B on
  315. // the GamePad or on the Keyboard.
  316. if ((previousGamePadState.Buttons.B == ButtonState.Released &&
  317. currentGamePadState.Buttons.B == ButtonState.Pressed) ||
  318. (previousKeyboardState.IsKeyUp(Keys.B) &&
  319. currentKeyboardState.IsKeyDown(Keys.B))
  320. #if WINDOWS_PHONE
  321. || isBehaviorChangeRequested
  322. #endif
  323. )
  324. {
  325. tank.CycleBehaviorType();
  326. #if WINDOWS_PHONE
  327. isBehaviorChangeRequested = false;
  328. #endif
  329. }
  330. // Add the cursor's location to the WaypointList if the user pressed A on
  331. // the GamePad or on the Keyboard.
  332. if ((previousGamePadState.Buttons.A == ButtonState.Released &&
  333. currentGamePadState.Buttons.A == ButtonState.Pressed) ||
  334. (previousKeyboardState.IsKeyUp(Keys.A) &&
  335. currentKeyboardState.IsKeyDown(Keys.A))
  336. #if WINDOWS_PHONE
  337. || isTouchDetected
  338. #endif
  339. )
  340. {
  341. tank.Waypoints.Enqueue(cursorLocation);
  342. }
  343. // Delete all the current waypoints and reset the tanks’ location if
  344. // the user pressed X on the GamePad or on the Keyboard.
  345. if ((previousGamePadState.Buttons.X == ButtonState.Released &&
  346. currentGamePadState.Buttons.X == ButtonState.Pressed) ||
  347. (previousKeyboardState.IsKeyUp(Keys.X) &&
  348. currentKeyboardState.IsKeyDown(Keys.X))
  349. #if WINDOWS_PHONE
  350. || isClearRequested
  351. #endif
  352. )
  353. {
  354. tank.Reset(
  355. new Vector2((float)screenWidth / 4, (float)screenHeight / 4));
  356. #if WINDOWS_PHONE
  357. isClearRequested = false;
  358. #endif
  359. }
  360. }
  361. #endregion
  362. }
  363. }