GameplayScreen.cs 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // GameplayScreen.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.GamerServices;
  14. using Microsoft.Xna.Framework.Graphics;
  15. using Microsoft.Xna.Framework.Input;
  16. using HoneycombRush.GameDebugTools;
  17. using Microsoft.Xna.Framework.Input.Touch;
  18. using System.Xml.Linq;
  19. using MonoMac.Foundation;
  20. using System.IO;
  21. #endregion
  22. namespace HoneycombRush
  23. {
  24. /// <summary>
  25. /// This is the class the handle the entire game
  26. /// </summary>
  27. public class GameplayScreen : GameScreen
  28. {
  29. #region Fields/Properties
  30. SpriteFont font16px;
  31. SpriteFont font36px;
  32. Texture2D arrowTexture;
  33. Texture2D background;
  34. Texture2D controlstickBoundary;
  35. Texture2D controlstick;
  36. Texture2D beehiveTexture;
  37. Texture2D smokeButton;
  38. ScoreBar smokeButtonScorebar;
  39. Vector2 controlstickStartupPosition;
  40. Vector2 controlstickBoundaryPosition;
  41. Vector2 smokeButtonPosition;
  42. Vector2 smokeTextLocation;
  43. Vector2 lastTouchPosition;
  44. /// <summary>
  45. /// A vector describing the movement direction according to the current user input.
  46. /// </summary>
  47. Vector2 movementVector;
  48. Vector2 vatArrowPosition;
  49. bool isSmokebuttonClicked;
  50. bool drawArrow;
  51. bool drawArrowInInterval;
  52. bool isInMotion;
  53. bool isAtStartupCountDown;
  54. bool isLevelEnd;
  55. bool levelEnded;
  56. bool isUserWon;
  57. bool userInputToExit;
  58. Dictionary<string, ScaledAnimation> animations;
  59. int amountOfSoldierBee;
  60. int amountOfWorkerBee;
  61. int arrowCounter;
  62. List<Beehive> beehives = new List<Beehive>();
  63. List<Bee> bees = new List<Bee>();
  64. const string SmokeText = "Smoke";
  65. TimeSpan gameElapsed;
  66. TimeSpan startScreenTime;
  67. BeeKeeper beeKeeper;
  68. HoneyJar jar;
  69. Vat vat;
  70. DifficultyMode gameDifficultyLevel;
  71. public bool IsStarted
  72. {
  73. get
  74. {
  75. return !isAtStartupCountDown && !levelEnded;
  76. }
  77. }
  78. private bool IsInMotion
  79. {
  80. get
  81. {
  82. return isInMotion;
  83. }
  84. set
  85. {
  86. isInMotion = value;
  87. if (beeKeeper != null)
  88. {
  89. beeKeeper.IsInMotion = isInMotion;
  90. }
  91. }
  92. }
  93. DebugSystem debugSystem;
  94. bool showDebugInfo = false;
  95. Rectangle deviceUpperRightCorner = new Rectangle(750, 0, 50, 50);
  96. public static int FinalScore;
  97. #endregion
  98. #region Initializations
  99. /// <summary>
  100. /// Creates a new gameplay screen.
  101. /// </summary>
  102. /// <param name="gameDifficultyMode">The desired game difficulty.</param>
  103. public GameplayScreen(DifficultyMode gameDifficultyMode)
  104. {
  105. TransitionOnTime = TimeSpan.FromSeconds(0.0);
  106. TransitionOffTime = TimeSpan.FromSeconds(0.0);
  107. startScreenTime = TimeSpan.FromSeconds(3);
  108. //Loads configuration
  109. var config = Path.Combine(NSBundle.MainBundle.ResourcePath,"Content/Configuration/Configuration.xml");
  110. //ConfigurationManager.LoadConfiguration(XDocument.Load("Content/Configuration/Configuration.xml"));
  111. ConfigurationManager.LoadConfiguration(XDocument.Load(config));
  112. ConfigurationManager.DifficultyMode = gameDifficultyMode;
  113. gameDifficultyLevel = gameDifficultyMode;
  114. gameElapsed = ConfigurationManager.ModesConfiguration[gameDifficultyLevel].GameElapsed;
  115. amountOfSoldierBee = 4;
  116. amountOfWorkerBee = 16;
  117. controlstickBoundaryPosition = new Vector2(34, 347);
  118. smokeButtonPosition = new Vector2(664, 346);
  119. controlstickStartupPosition = new Vector2(55, 369);
  120. IsInMotion = false;
  121. isAtStartupCountDown = true;
  122. isLevelEnd = false;
  123. EnabledGestures = GestureType.Tap;
  124. }
  125. #endregion
  126. #region Loading and Unloading
  127. /// <summary>
  128. /// Initialize the game's debug console.
  129. /// </summary>
  130. public override void LoadContent()
  131. {
  132. base.LoadContent();
  133. debugSystem = DebugSystem.Instance;
  134. }
  135. /// <summary>
  136. /// Loads content and assets.
  137. /// </summary>
  138. public void LoadAssets()
  139. {
  140. // Loads the animation dictionary from an xml file
  141. animations = new Dictionary<string, ScaledAnimation>();
  142. LoadAnimationFromXML();
  143. // Loads all textures that are required
  144. LoadTextures();
  145. // Create all game components
  146. CreateGameComponents();
  147. AudioManager.PlayMusic("InGameSong_Loop");
  148. }
  149. /// <summary>
  150. /// Unloads game components which are no longer needed once the game ends.
  151. /// </summary>
  152. public override void UnloadContent()
  153. {
  154. var componentList = ScreenManager.Game.Components;
  155. for (int index = 0; index < componentList.Count; index++)
  156. {
  157. if (componentList[index] is TexturedDrawableGameComponent || componentList[index] is ScoreBar)
  158. {
  159. componentList.RemoveAt(index);
  160. index--;
  161. }
  162. }
  163. base.UnloadContent();
  164. }
  165. #endregion
  166. #region Update
  167. /// <summary>
  168. /// Handle the player's input.
  169. /// </summary>
  170. /// <param name="input"></param>
  171. public override void HandleInput(GameTime gameTime, InputState input)
  172. {
  173. if (IsActive)
  174. {
  175. if (input == null)
  176. {
  177. throw new ArgumentNullException("input");
  178. }
  179. if (input.IsPauseGame(null))
  180. {
  181. PauseCurrentGame();
  182. }
  183. }
  184. if (input.TouchState.Count > 0)
  185. {
  186. foreach (TouchLocation touch in input.TouchState)
  187. {
  188. lastTouchPosition = touch.Position;
  189. }
  190. }
  191. isSmokebuttonClicked = false;
  192. PlayerIndex player;
  193. VirtualThumbsticks.Update(input);
  194. if (input.Gestures.Count > 0)
  195. {
  196. GestureSample topGesture = input.Gestures[0];
  197. if (topGesture.GestureType == GestureType.Tap &&
  198. deviceUpperRightCorner.Contains(new Point((int)topGesture.Position.X, (int)topGesture.Position.Y)))
  199. {
  200. showDebugInfo = !showDebugInfo;
  201. }
  202. }
  203. if (isLevelEnd)
  204. {
  205. if (input.Gestures.Count > 0)
  206. {
  207. if (input.Gestures[0].GestureType == GestureType.Tap)
  208. {
  209. userInputToExit = true;
  210. }
  211. }
  212. if (input.IsNewKeyPress(Keys.Enter, ControllingPlayer, out player) ||
  213. input.IsNewKeyPress(Keys.Space, ControllingPlayer, out player))
  214. {
  215. userInputToExit = true;
  216. }
  217. }
  218. if (!IsStarted)
  219. {
  220. return;
  221. }
  222. // If there was any touch
  223. if (VirtualThumbsticks.RightThumbstickCenter.HasValue)
  224. {
  225. // Button Bounds
  226. Rectangle buttonRectangle = new Rectangle((int)smokeButtonPosition.X, (int)smokeButtonPosition.Y,
  227. smokeButton.Width / 2, smokeButton.Height);
  228. // Touch Bounds
  229. Rectangle touchRectangle = new Rectangle((int)VirtualThumbsticks.RightThumbstickCenter.Value.X,
  230. (int)VirtualThumbsticks.RightThumbstickCenter.Value.Y,
  231. 1, 1);
  232. // If the touch is in the button
  233. if (buttonRectangle.Contains(touchRectangle) && !beeKeeper.IsCollectingHoney && !beeKeeper.IsStung)
  234. {
  235. isSmokebuttonClicked = true;
  236. }
  237. }
  238. // Handle keyboard
  239. if (input.IsNewKeyPress(Keys.Y, ControllingPlayer, out player))
  240. {
  241. showDebugInfo = !showDebugInfo;
  242. }
  243. if (input.IsKeyDown(Keys.Space, ControllingPlayer, out player) && !beeKeeper.IsCollectingHoney &&
  244. !beeKeeper.IsStung)
  245. {
  246. isSmokebuttonClicked = true;
  247. }
  248. movementVector = SetMotion(input);
  249. beeKeeper.SetDirection(movementVector);
  250. }
  251. /// <summary>
  252. /// Perform the game's update logic.
  253. /// </summary>
  254. /// <param name="gameTime">Game time information.</param>
  255. /// <param name="otherScreenHasFocus">Whether or not another screen currently has the focus.</param>
  256. /// <param name="coveredByOtherScreen">Whether or not this screen is covered by another.</param>
  257. public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
  258. {
  259. // When the game starts the first thing the user sees is the count down before the game actually begins
  260. if (isAtStartupCountDown)
  261. {
  262. startScreenTime -= gameTime.ElapsedGameTime;
  263. }
  264. // Check for and handle a game over
  265. if (CheckIfCurrentGameFinished())
  266. {
  267. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  268. return;
  269. }
  270. if (!(IsActive && IsStarted))
  271. {
  272. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  273. return;
  274. }
  275. // Show all diagnostic counters
  276. debugSystem.FpsCounter.Visible = showDebugInfo;
  277. debugSystem.TimeRuler.Visible = showDebugInfo;
  278. debugSystem.TimeRuler.ShowLog = showDebugInfo;
  279. gameElapsed -= gameTime.ElapsedGameTime;
  280. #if WINDOWS_PHONE
  281. HandleThumbStick();
  282. #endif
  283. HandleSmoke();
  284. HandleCollision(gameTime);
  285. HandleVatHoneyArrow();
  286. beeKeeper.DrawOrder = 1;
  287. int beeKeeperY = (int)(beeKeeper.Position.Y + beeKeeper.Bounds.Height - 2);
  288. // We want to determine the draw order of the beekeeper,
  289. // if the beekeeper is under half the height of the beehive
  290. // it should be drawn over the beehive.
  291. foreach (Beehive beehive in beehives)
  292. {
  293. if (beeKeeperY > beehive.Bounds.Y)
  294. {
  295. if (beehive.Bounds.Y + beehive.Bounds.Height / 2 < beeKeeperY)
  296. {
  297. beeKeeper.DrawOrder = Math.Max(beeKeeper.DrawOrder, beehive.Bounds.Y + 1);
  298. }
  299. }
  300. }
  301. if (gameElapsed.Minutes == 0 && gameElapsed.Seconds == 10)
  302. {
  303. AudioManager.PlaySound("10SecondCountDown");
  304. }
  305. if (gameElapsed.Minutes == 0 && gameElapsed.Seconds == 30)
  306. {
  307. AudioManager.PlaySound("30SecondWarning");
  308. }
  309. // Update the time remaining displayed on the vat
  310. vat.DrawTimeLeft(gameElapsed);
  311. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  312. }
  313. #endregion
  314. #region Render
  315. /// <summary>
  316. /// Draw the game screen.
  317. /// </summary>
  318. /// <param name="gameTime">Game time information.</param>
  319. public override void Draw(GameTime gameTime)
  320. {
  321. ScreenManager.SpriteBatch.Begin();
  322. ScreenManager.SpriteBatch.Draw(background, ScreenManager.GraphicsDevice.Viewport.Bounds, null,
  323. Color.White, 0f, Vector2.Zero, SpriteEffects.None, 1);
  324. // Draw count down screen
  325. if (isAtStartupCountDown)
  326. {
  327. DrawStartupString();
  328. }
  329. if (IsActive && IsStarted)
  330. {
  331. DrawSmokeButton();
  332. #if WINDOWS_PHONE
  333. // Only draw the virtual thumbstick on the phone
  334. ScreenManager.SpriteBatch.Draw(controlstickBoundary, controlstickBoundaryPosition, Color.White);
  335. ScreenManager.SpriteBatch.Draw(controlstick, controlstickStartupPosition, Color.White);
  336. #endif
  337. ScreenManager.SpriteBatch.DrawString(font16px, SmokeText, smokeTextLocation, Color.White);
  338. DrawVatHoneyArrow();
  339. }
  340. DrawLevelEndIfNecessary();
  341. ScreenManager.SpriteBatch.End();
  342. base.Draw(gameTime);
  343. }
  344. #endregion
  345. #region Private Methods
  346. /// <summary>
  347. /// If the level is over, draws text describing the level's outcome.
  348. /// </summary>
  349. private void DrawLevelEndIfNecessary()
  350. {
  351. if (isLevelEnd)
  352. {
  353. string stringToDisplay = string.Empty;
  354. if (isUserWon)
  355. {
  356. if (FinalScore != 0 && HighScoreScreen.IsInHighscores(FinalScore))
  357. {
  358. stringToDisplay = "It's a new\nHigh-Score!";
  359. }
  360. else
  361. {
  362. stringToDisplay = "You Win!";
  363. }
  364. }
  365. else
  366. {
  367. stringToDisplay = "Time Is Up!";
  368. }
  369. Vector2 stringVector = font36px.MeasureString(stringToDisplay) * ScreenManager.SpriteBatch.ScaleVector;
  370. ScreenManager.SpriteBatch.DrawString(font36px, stringToDisplay,
  371. new Vector2(ScreenManager.GraphicsDevice.Viewport.Width / 2 - stringVector.X / 2,
  372. ScreenManager.GraphicsDevice.Viewport.Height / 2 - stringVector.Y / 2),
  373. Color.White);
  374. }
  375. }
  376. /// <summary>
  377. /// Advances to the next screen based on the current difficulty and whether or not the user has won.
  378. /// </summary>
  379. /// <param name="isWon">Whether or not the user has won the current level.</param>
  380. private void MoveToNextScreen(bool isWon)
  381. {
  382. ScreenManager.AddScreen(new BackgroundScreen("pauseBackground"), null);
  383. if (isWon)
  384. {
  385. switch (gameDifficultyLevel)
  386. {
  387. case DifficultyMode.Easy:
  388. case DifficultyMode.Medium:
  389. ScreenManager.AddScreen(
  390. new LevelOverScreen("You Finished Level: " + gameDifficultyLevel.ToString(),
  391. ++gameDifficultyLevel), null);
  392. break;
  393. case DifficultyMode.Hard:
  394. ScreenManager.AddScreen(new LevelOverScreen("You Win", null), null);
  395. break;
  396. }
  397. }
  398. else
  399. {
  400. ScreenManager.AddScreen(new LevelOverScreen("You Lose", null), null);
  401. }
  402. AudioManager.StopMusic();
  403. AudioManager.StopSound("BeeBuzzing_Loop");
  404. }
  405. /// <summary>
  406. /// Pause the game.
  407. /// </summary>
  408. private void PauseCurrentGame()
  409. {
  410. debugSystem.FpsCounter.Visible = false;
  411. debugSystem.TimeRuler.Visible = false;
  412. debugSystem.TimeRuler.ShowLog = false;
  413. // Pause sounds
  414. AudioManager.PauseResumeSounds(false);
  415. // Set pause screen
  416. ScreenManager.AddScreen(new BackgroundScreen("pauseBackground"), null);
  417. ScreenManager.AddScreen(new PauseScreen(), null);
  418. }
  419. /// <summary>
  420. /// Loads animation settings from an xml file.
  421. /// </summary>
  422. private void LoadAnimationFromXML()
  423. {
  424. XDocument doc = XDocument.Load("Content/Textures/AnimationsDefinition.xml");
  425. XName name = XName.Get("Definition");
  426. var definitions = doc.Document.Descendants(name);
  427. // Loop over all definitions in the XML
  428. foreach (XElement animationDefinition in definitions)
  429. {
  430. // Get the name of the animation
  431. string animationAlias = animationDefinition.Attribute("Alias").Value;
  432. Texture2D texture =
  433. ScreenManager.Game.Content.Load<Texture2D>(animationDefinition.Attribute("SheetName").Value);
  434. // Get the frame size (width & height)
  435. Point frameSize = new Point();
  436. frameSize.X = int.Parse(animationDefinition.Attribute("FrameWidth").Value);
  437. frameSize.Y = int.Parse(animationDefinition.Attribute("FrameHeight").Value);
  438. // Get the frames sheet dimensions
  439. Point sheetSize = new Point();
  440. sheetSize.X = int.Parse(animationDefinition.Attribute("SheetColumns").Value);
  441. sheetSize.Y = int.Parse(animationDefinition.Attribute("SheetRows").Value);
  442. ScaledAnimation animation = new ScaledAnimation(texture, frameSize, sheetSize);
  443. // Checks for sub-animation definition
  444. if (animationDefinition.Element("SubDefinition") != null)
  445. {
  446. int startFrame = int.Parse(
  447. animationDefinition.Element("SubDefinition").Attribute("StartFrame").Value);
  448. int endFrame = int.Parse
  449. (animationDefinition.Element("SubDefinition").Attribute("EndFrame").Value);
  450. animation.SetSubAnimation(startFrame, endFrame);
  451. }
  452. if (animationDefinition.Attribute("Speed") != null)
  453. {
  454. animation.SetFrameInterval(TimeSpan.FromMilliseconds(
  455. double.Parse(animationDefinition.Attribute("Speed").Value)));
  456. }
  457. // If the definition has an offset defined - it should be
  458. // rendered relative to some element/animation
  459. if (null != animationDefinition.Attribute("OffsetX") &&
  460. null != animationDefinition.Attribute("OffsetY"))
  461. {
  462. animation.Offset = new Vector2(int.Parse(animationDefinition.Attribute("OffsetX").Value),
  463. int.Parse(animationDefinition.Attribute("OffsetY").Value));
  464. }
  465. animations.Add(animationAlias, animation);
  466. }
  467. }
  468. /// <summary>
  469. /// Create all the game components.
  470. /// </summary>
  471. private void CreateGameComponents()
  472. {
  473. Vector2 scaleVector = ScreenManager.SpriteBatch.ScaleVector;
  474. Rectangle safeArea = SafeArea;
  475. Texture2D jarTexture = ScreenManager.Game.Content.Load<Texture2D>("Textures/honeyJar");
  476. Vector2 honeyJarLocation =
  477. safeArea.GetVector() + new Vector2(UIConstants.HoneyJarLeftMargin, UIConstants.HoneyJarTopMargin);
  478. Vector2 jarBarLocation = honeyJarLocation + new Vector2(0, jarTexture.Height * scaleVector.Y + 7);
  479. ScoreBar scoreBar = new ScoreBar(ScreenManager.Game, 0, 100, jarBarLocation,
  480. (int)(jarTexture.Height / 6 * scaleVector.Y), (int)(jarTexture.Width * scaleVector.X), Color.Blue,
  481. ScoreBar.ScoreBarOrientation.Horizontal, 0, this, true);
  482. ScreenManager.Game.Components.Add(scoreBar);
  483. // Create the honey jar
  484. jar = new HoneyJar(ScreenManager.Game, this, honeyJarLocation, scoreBar);
  485. ScreenManager.Game.Components.Add(jar);
  486. // Create all the beehives and the bees
  487. CreateBeehives(safeArea, jar);
  488. // We only initialize the smoke button position here since we need access
  489. // to the screen manager in order to do so (and it is null in the
  490. // constructor)
  491. smokeButtonPosition =
  492. new Vector2(safeArea.Right - UIConstants.SmokeButtonRightAbsoluteMargin,
  493. safeArea.Bottom - UIConstants.SmokeButtonBottomAbsoluteMargin);
  494. // Create the smoke gun's score bar
  495. int totalSmokeAmount = ConfigurationManager.ModesConfiguration[gameDifficultyLevel].TotalSmokeAmount;
  496. Vector2 smokeBarLocation = smokeButtonPosition +
  497. new Vector2(UIConstants.SmokeButtonSize * scaleVector.X / 8,
  498. UIConstants.SmokeButtonSize * scaleVector.Y);
  499. smokeButtonScorebar = new ScoreBar(ScreenManager.Game, 0, totalSmokeAmount,
  500. smokeBarLocation, (int)(UIConstants.SmokeButtonSize * scaleVector.X / 10),
  501. (int)(UIConstants.SmokeButtonSize * scaleVector.Y * 3 / 4), Color.White,
  502. ScoreBar.ScoreBarOrientation.Horizontal, totalSmokeAmount, this, false);
  503. smokeTextLocation = smokeButtonPosition +
  504. new Vector2(
  505. UIConstants.SmokeButtonSize * scaleVector.X / 2 -
  506. font16px.MeasureString(SmokeText).X * scaleVector.X / 2,
  507. UIConstants.SmokeButtonSize * scaleVector.Y * 11 / 10);
  508. ScreenManager.Game.Components.Add(smokeButtonScorebar);
  509. // Creates the BeeKeeper
  510. beeKeeper = new BeeKeeper(ScreenManager.Game, this);
  511. beeKeeper.AnimationDefinitions = animations;
  512. beeKeeper.ThumbStickArea = new Rectangle((int)controlstickBoundaryPosition.X,
  513. (int)controlstickBoundaryPosition.Y, controlstickBoundary.Width, controlstickBoundary.Height);
  514. ScreenManager.Game.Components.Add(beeKeeper);
  515. // Creates the vat
  516. Texture2D vatTexture = ScreenManager.Game.Content.Load<Texture2D>("Textures/vat");
  517. Vector2 vatLocation = new Vector2(safeArea.Center.X - vatTexture.Width * scaleVector.X / 2,
  518. safeArea.Bottom - vatTexture.Height * scaleVector.Y - UIConstants.VatBottomMargin);
  519. Vector2 vatScorebarLocation = vatLocation +
  520. new Vector2((vatTexture.Width * scaleVector.X - UIConstants.VatScorebarWidth) / 2,
  521. vatTexture.Height * scaleVector.Y * 7 / 10);
  522. scoreBar = new ScoreBar(ScreenManager.Game, 0, 300, vatScorebarLocation, UIConstants.VatScorebarHeight,
  523. UIConstants.VatScorebarWidth, Color.White, ScoreBar.ScoreBarOrientation.Horizontal, 0, this, true);
  524. vat = new Vat(ScreenManager.Game, this, vatTexture, vatLocation, scoreBar);
  525. ScreenManager.Game.Components.Add(vat);
  526. vatArrowPosition =
  527. vatLocation + new Vector2(vatTexture.Width * scaleVector.X / 2 -
  528. arrowTexture.Width * scaleVector.X / 2, UIConstants.VatArrowOffset);
  529. ScreenManager.Game.Components.Add(scoreBar);
  530. scoreBar.DrawOrder = vat.DrawOrder + 1;
  531. }
  532. /// <summary>
  533. /// Creates all the beehives and bees.
  534. /// </summary>
  535. private void CreateBeehives(Rectangle safeArea, HoneyJar jar)
  536. {
  537. Vector2 scaleVector = ScreenManager.SpriteBatch.ScaleVector;
  538. // Init position parameters
  539. Vector2 scorebarPosition =
  540. new Vector2(beehiveTexture.Width * scaleVector.X / 4, beehiveTexture.Height * scaleVector.Y * 9 / 10);
  541. Vector2[] beehivePositions = new Vector2[5]
  542. {
  543. // top left
  544. new Vector2(safeArea.Left + UIConstants.BeehiveLeftMargin,
  545. safeArea.Top + UIConstants.BeehiveTopMargin),
  546. // top middle
  547. new Vector2(safeArea.Center.X - beehiveTexture.Width * scaleVector.X / 2,
  548. safeArea.Top + UIConstants.BeehiveTopMargin),
  549. // top right
  550. new Vector2(safeArea.Right - beehiveTexture.Width * scaleVector.X - UIConstants.BeehiveRightMargin,
  551. safeArea.Top + UIConstants.BeehiveTopMargin),
  552. // left
  553. new Vector2(safeArea.Left + UIConstants.BeehiveLeftMargin,
  554. safeArea.Center.Y - beehiveTexture.Height * scaleVector.Y / 2 + UIConstants.BeehiveMiddleOffset),
  555. // right
  556. new Vector2(safeArea.Right - beehiveTexture.Width * scaleVector.X - UIConstants.BeehiveRightMargin,
  557. safeArea.Center.Y - beehiveTexture.Height * scaleVector.Y / 2 + UIConstants.BeehiveMiddleOffset)
  558. };
  559. // Create the beehives
  560. for (int beehiveCounter = 0; beehiveCounter < beehivePositions.Length; beehiveCounter++)
  561. {
  562. ScoreBar scoreBar = new ScoreBar(ScreenManager.Game, 0, 100, beehivePositions[beehiveCounter] +
  563. scorebarPosition, (int)(beehiveTexture.Height * scaleVector.Y / 10),
  564. (int)(beehiveTexture.Width * scaleVector.X / 2), Color.Green,
  565. ScoreBar.ScoreBarOrientation.Horizontal, 100, this, false);
  566. ScreenManager.Game.Components.Add(scoreBar);
  567. Beehive beehive =
  568. new Beehive(ScreenManager.Game, this, beehiveTexture, scoreBar, beehivePositions[beehiveCounter]);
  569. beehive.AnimationDefinitions = animations;
  570. ScreenManager.Game.Components.Add(beehive);
  571. beehives.Add(beehive);
  572. scoreBar.DrawOrder = beehive.DrawOrder;
  573. }
  574. for (int beehiveIndex = 0; beehiveIndex < beehivePositions.Length; beehiveIndex++)
  575. {
  576. // Create the Soldier bees
  577. for (int SoldierBeeCounter = 0; SoldierBeeCounter < amountOfSoldierBee; SoldierBeeCounter++)
  578. {
  579. SoldierBee bee = new SoldierBee(ScreenManager.Game, this, beehives[beehiveIndex]);
  580. bee.AnimationDefinitions = animations;
  581. ScreenManager.Game.Components.Add(bee);
  582. bees.Add(bee);
  583. }
  584. // Creates the worker bees
  585. for (int workerBeeCounter = 0; workerBeeCounter < amountOfWorkerBee; workerBeeCounter++)
  586. {
  587. WorkerBee bee = new WorkerBee(ScreenManager.Game, this, beehives[beehiveIndex]);
  588. bee.AnimationDefinitions = animations;
  589. ScreenManager.Game.Components.Add(bee);
  590. bees.Add(bee);
  591. }
  592. }
  593. }
  594. /// <summary>
  595. /// Loads all the necessary textures.
  596. /// </summary>
  597. private void LoadTextures()
  598. {
  599. beehiveTexture = ScreenManager.Game.Content.Load<Texture2D>("Textures/beehive");
  600. background = ScreenManager.Game.Content.Load<Texture2D>("Textures/Backgrounds/GamePlayBackground");
  601. controlstickBoundary = ScreenManager.Game.Content.Load<Texture2D>("Textures/controlstickBoundary");
  602. controlstick = ScreenManager.Game.Content.Load<Texture2D>("Textures/controlstick");
  603. smokeButton = ScreenManager.Game.Content.Load<Texture2D>("Textures/smokeBtn");
  604. font16px = ScreenManager.Game.Content.Load<SpriteFont>("Fonts/GameScreenFont16px");
  605. arrowTexture = ScreenManager.Game.Content.Load<Texture2D>("Textures/arrow");
  606. font16px = ScreenManager.Game.Content.Load<SpriteFont>("Fonts/GameScreenFont16px");
  607. font36px = ScreenManager.Game.Content.Load<SpriteFont>("Fonts/GameScreenFont36px");
  608. }
  609. #if WINDOWS_PHONE
  610. /// <summary>
  611. /// Handle ThumbStick logic
  612. /// </summary>
  613. private void HandleThumbStick()
  614. {
  615. // Calculate the rectangle of the outer circle of the thumbstick
  616. Rectangle outerControlstick = new Rectangle(0, (int)controlstickBoundaryPosition.Y - 35,
  617. controlstickBoundary.Width + 60, controlstickBoundary.Height + 60);
  618. // Reset the thumbstick position when it is idle
  619. if (VirtualThumbsticks.LeftThumbstick == Vector2.Zero)
  620. {
  621. IsInMotion = false;
  622. controlstickStartupPosition = new Vector2(55, 369);
  623. }
  624. else
  625. {
  626. // If not in motion and the touch point is not in the control bounds - there is no movement
  627. Rectangle touchRectangle = new Rectangle((int)lastTouchPosition.X, (int)lastTouchPosition.Y, 1, 1);
  628. if (!outerControlstick.Contains(touchRectangle))
  629. {
  630. controlstickStartupPosition = new Vector2(55, 369);
  631. IsInMotion = false;
  632. return;
  633. }
  634. // Moves the thumbstick's inner circle
  635. float radius = controlstick.Width / 2 + 35;
  636. controlstickStartupPosition = new Vector2(55, 369) + (VirtualThumbsticks.LeftThumbstick * radius);
  637. }
  638. }
  639. #endif
  640. /// <summary>
  641. /// Moves the beekeeper.
  642. /// </summary>
  643. /// <returns>Returns a vector indicating the beekeeper's movement direction.
  644. /// </returns>
  645. private Vector2 SetMotion(InputState input)
  646. {
  647. // Calculate the beekeeper location, if allow moving
  648. Rectangle safeArea = SafeArea;
  649. PlayerIndex playerIndex;
  650. Vector2 leftThumbstick = VirtualThumbsticks.LeftThumbstick;
  651. // Move on to keyboard input if we still have nothing
  652. if (leftThumbstick == Vector2.Zero)
  653. {
  654. float vecX = 0;
  655. float vecY = 0;
  656. if (input.IsKeyDown(Keys.Left, ControllingPlayer, out playerIndex))
  657. {
  658. vecX--;
  659. }
  660. if (input.IsKeyDown(Keys.Right, ControllingPlayer, out playerIndex))
  661. {
  662. vecX++;
  663. }
  664. if (input.IsKeyDown(Keys.Up, ControllingPlayer, out playerIndex))
  665. {
  666. vecY--;
  667. }
  668. if (input.IsKeyDown(Keys.Down, ControllingPlayer, out playerIndex))
  669. {
  670. vecY++;
  671. }
  672. leftThumbstick = new Vector2(vecX, vecY);
  673. }
  674. Vector2 movementVector = leftThumbstick * 12f * ScreenManager.SpriteBatch.ScaleVector;
  675. Rectangle futureBounds = beeKeeper.Bounds;
  676. futureBounds.X += (int)movementVector.X;
  677. futureBounds.Y += (int)movementVector.Y;
  678. if (futureBounds.Left <= safeArea.Left || futureBounds.Right >= safeArea.Right)
  679. {
  680. movementVector.X = 0;
  681. }
  682. if (futureBounds.Top <= safeArea.Top || futureBounds.Bottom >= safeArea.Bottom)
  683. {
  684. movementVector.Y = 0;
  685. }
  686. if (movementVector == Vector2.Zero)
  687. {
  688. IsInMotion = false;
  689. beeKeeper.SetMovement(Vector2.Zero);
  690. }
  691. else
  692. {
  693. Vector2 beekeeperCalculatedPosition =
  694. new Vector2(beeKeeper.CentralCollisionArea.X, beeKeeper.CentralCollisionArea.Y) + movementVector;
  695. if (!CheckBeehiveCollision(beekeeperCalculatedPosition))
  696. {
  697. beeKeeper.SetMovement(movementVector);
  698. IsInMotion = true;
  699. }
  700. }
  701. return movementVector;
  702. }
  703. /// <summary>
  704. /// Checks if the beekeeper collides with a beehive.
  705. /// </summary>
  706. /// <param name="beekeeperPosition">The beekeeper's position.</param>
  707. /// <returns>True if the beekeeper collides with a beehive and false otherwise.</returns>
  708. private bool CheckBeehiveCollision(Vector2 beekeeperPosition)
  709. {
  710. // We do not use the beekeeper's collision area property as he has not actually moved at this point and
  711. // is still in his previous position
  712. Rectangle beekeeperTempCollisionArea = new Rectangle((int)beekeeperPosition.X, (int)beekeeperPosition.Y,
  713. beeKeeper.CentralCollisionArea.Width, beeKeeper.CentralCollisionArea.Height);
  714. foreach (Beehive currentBeehive in beehives)
  715. {
  716. if (beekeeperTempCollisionArea.Intersects(currentBeehive.CentralCollisionArea))
  717. {
  718. return true;
  719. }
  720. }
  721. return false;
  722. }
  723. /// <summary>
  724. /// Check for any of the possible collisions.
  725. /// </summary>
  726. /// <param name="gameTime">Game time information.</param>
  727. private void HandleCollision(GameTime gameTime)
  728. {
  729. bool isCollectingHoney = HandleBeeKeeperBeehiveCollision();
  730. HandleSmokeBeehiveCollision();
  731. bool hasCollisionWithVat = HandleVatCollision();
  732. HandleBeeInteractions(gameTime, hasCollisionWithVat, isCollectingHoney);
  733. }
  734. /// <summary>
  735. /// Handle the interaction of the bees with other game components.
  736. /// </summary>
  737. /// <param name="gameTime">Game time information.</param>
  738. /// <param name="isBeeKeeperCollideWithVat">Whether the beekeeper is currently touching the vat.</param>
  739. /// <param name="isBeeKeeperCollideWithBeehive">Whether the beekeeper is currently touching a beehive.</param>
  740. private void HandleBeeInteractions(GameTime gameTime, bool isBeeKeeperCollideWithVat,
  741. bool isBeeKeeperCollideWithBeehive)
  742. {
  743. // Goes over all the bees
  744. foreach (Bee bee in bees)
  745. {
  746. // Check for smoke collisions
  747. SmokePuff intersectingPuff = beeKeeper.CheckSmokeCollision(bee.Bounds);
  748. if (intersectingPuff != null)
  749. {
  750. bee.HitBySmoke(intersectingPuff);
  751. }
  752. // Check for vat collision
  753. if (vat.Bounds.HasCollision(bee.Bounds))
  754. {
  755. bee.Collide(vat.Bounds);
  756. }
  757. // Check for beekeeper collision
  758. if (beeKeeper.Bounds.HasCollision(bee.Bounds))
  759. {
  760. if (!bee.IsBeeHit && !isBeeKeeperCollideWithVat && !beeKeeper.IsStung && !beeKeeper.IsFlashing &&
  761. !isBeeKeeperCollideWithBeehive)
  762. {
  763. jar.DecreaseHoneyByPercent(20);
  764. beeKeeper.Stung(gameTime.TotalGameTime);
  765. AudioManager.PlaySound("HoneyPotBreak");
  766. AudioManager.PlaySound("Stung");
  767. }
  768. bee.Collide(beeKeeper.Bounds);
  769. }
  770. // Soldier bee chase logic
  771. if (bee is SoldierBee)
  772. {
  773. SoldierBee SoldierBee = bee as SoldierBee;
  774. SoldierBee.DistanceFromBeeKeeper =
  775. (Vector2.Distance(beeKeeper.Bounds.GetVector(), SoldierBee.Bounds.GetVector()));
  776. SoldierBee.BeeKeeperVector = beeKeeper.Bounds.GetVector() - SoldierBee.Bounds.GetVector();
  777. }
  778. }
  779. }
  780. /// <summary>
  781. /// Handle the beekeeper's collision with the vat component.
  782. /// </summary>
  783. /// <returns>True if the beekeeper collides with the vat and false otherwise.</returns>
  784. private bool HandleVatCollision()
  785. {
  786. if (beeKeeper.Bounds.HasCollision(vat.VatDepositArea))
  787. {
  788. if (jar.HasHoney && !beeKeeper.IsStung && !beeKeeper.IsDepositingHoney &&
  789. movementVector == Vector2.Zero)
  790. {
  791. beeKeeper.StartTransferHoney(4, EndHoneyDeposit);
  792. }
  793. return true;
  794. }
  795. beeKeeper.EndTransferHoney();
  796. return false;
  797. }
  798. /// <summary>
  799. /// Handler for finalizing the honey deposit to the vat.
  800. /// </summary>
  801. /// <param name="result"></param>
  802. public void EndHoneyDeposit(IAsyncResult result)
  803. {
  804. int HoneyAmount = jar.DecreaseHoneyByPercent(100);
  805. vat.IncreaseHoney(HoneyAmount);
  806. AudioManager.StopSound("DepositingIntoVat_Loop");
  807. }
  808. /// <summary>
  809. /// Handle the beekeeper's collision with beehive components.
  810. /// </summary>
  811. /// <returns>True if the beekeeper collides with a beehive and false otherwise.</returns>
  812. /// <remarks>This method is also responsible for allowing bees to regenerate when the beekeeper is not
  813. /// intersecting with a specific hive.</remarks>
  814. private bool HandleBeeKeeperBeehiveCollision()
  815. {
  816. bool isCollidingWithBeehive = false;
  817. Beehive collidedBeehive = null;
  818. // Goes over all the beehives
  819. foreach (Beehive beehive in beehives)
  820. {
  821. // If the beekeeper intersects with the beehive
  822. if (beeKeeper.Bounds.HasCollision(beehive.Bounds))
  823. {
  824. if (movementVector == Vector2.Zero)
  825. {
  826. collidedBeehive = beehive;
  827. isCollidingWithBeehive = true;
  828. }
  829. }
  830. else
  831. {
  832. beehive.AllowBeesToGenerate = true;
  833. }
  834. }
  835. if (collidedBeehive != null)
  836. {
  837. // The beehive has honey, the jar can carry more honey, and the beekeeper is not stung
  838. if (collidedBeehive.HasHoney && jar.CanCarryMore && !beeKeeper.IsStung)
  839. {
  840. // Take honey from the beehive and put it in the jar
  841. collidedBeehive.DecreaseHoney(1);
  842. jar.IncreaseHoney(1);
  843. beeKeeper.IsCollectingHoney = true;
  844. AudioManager.PlaySound("FillingHoneyPot_Loop");
  845. }
  846. else
  847. {
  848. beeKeeper.IsCollectingHoney = false;
  849. }
  850. // Bees are not allowed to regenerate while the beekeeper is colliding with their beehive
  851. isCollidingWithBeehive = true;
  852. collidedBeehive.AllowBeesToGenerate = false;
  853. }
  854. else
  855. {
  856. beeKeeper.IsCollectingHoney = false;
  857. AudioManager.StopSound("FillingHoneyPot_Loop");
  858. }
  859. return isCollidingWithBeehive;
  860. }
  861. /// <summary>
  862. /// Handle the smoke puff collision with beehive components.
  863. /// </summary>
  864. /// <remarks>Only disables bee regeneration, as it assumes that it will be enabled by
  865. /// <see cref="HandleBeeKeeperBeehiveCollision"/></remarks>
  866. private void HandleSmokeBeehiveCollision()
  867. {
  868. foreach (Beehive beehive in beehives)
  869. {
  870. foreach (SmokePuff smokePuff in beeKeeper.FiredSmokePuffs)
  871. {
  872. if (beehive.Bounds.HasCollision(smokePuff.CentralCollisionArea))
  873. {
  874. beehive.AllowBeesToGenerate = false;
  875. }
  876. }
  877. }
  878. }
  879. /// <summary>
  880. /// Sets an internal value which determines whether or not to display an arrow above the vat.
  881. /// </summary>
  882. private void HandleVatHoneyArrow()
  883. {
  884. if (jar.HasHoney)
  885. {
  886. drawArrow = true;
  887. }
  888. else
  889. {
  890. drawArrow = false;
  891. }
  892. }
  893. /// <summary>
  894. /// Handle smoke logic.
  895. /// </summary>
  896. private void HandleSmoke()
  897. {
  898. // If not currently shooting, refill the gun
  899. if (!isSmokebuttonClicked)
  900. {
  901. smokeButtonScorebar.IncreaseCurrentValue(
  902. ConfigurationManager.ModesConfiguration[gameDifficultyLevel].IncreaseAmountSpeed);
  903. beeKeeper.IsShootingSmoke = false;
  904. }
  905. else
  906. {
  907. // Check that the gun is not empty
  908. if (smokeButtonScorebar.CurrentValue <= smokeButtonScorebar.MinValue)
  909. {
  910. beeKeeper.IsShootingSmoke = false;
  911. }
  912. else
  913. {
  914. beeKeeper.IsShootingSmoke = true;
  915. smokeButtonScorebar.DecreaseCurrentValue(
  916. ConfigurationManager.ModesConfiguration[gameDifficultyLevel].DecreaseAmountSpeed);
  917. }
  918. }
  919. }
  920. /// <summary>
  921. /// Checks whether the current game is over, and if so performs the necessary actions.
  922. /// </summary>
  923. /// <returns>True if the current game is over and false otherwise.</returns>
  924. private bool CheckIfCurrentGameFinished()
  925. {
  926. levelEnded = false;
  927. isUserWon = vat.CurrentVatCapacity >= vat.MaxVatCapacity;
  928. // If the vat is full, the player wins
  929. if (isUserWon || gameElapsed <= TimeSpan.Zero)
  930. {
  931. levelEnded = true;
  932. if (gameDifficultyLevel == DifficultyMode.Hard)
  933. {
  934. FinalScore = ConfigurationManager.ModesConfiguration[gameDifficultyLevel].HighScoreFactor
  935. * (int)gameElapsed.TotalMilliseconds;
  936. }
  937. else
  938. {
  939. FinalScore = 0;
  940. }
  941. }
  942. // if true, game is over
  943. if (gameElapsed <= TimeSpan.Zero || levelEnded)
  944. {
  945. isLevelEnd = true;
  946. if (userInputToExit)
  947. {
  948. ScreenManager.RemoveScreen(this);
  949. if (isUserWon) // True - the user won
  950. {
  951. AudioManager.PlaySound("Victory");
  952. }
  953. else
  954. {
  955. AudioManager.PlaySound("Defeat");
  956. }
  957. MoveToNextScreen(isUserWon);
  958. }
  959. }
  960. return false;
  961. }
  962. /// <summary>
  963. /// Draws the arrow in intervals of 20 game update loops.
  964. /// </summary>
  965. private void DrawVatHoneyArrow()
  966. {
  967. // If the arrow needs to be drawn, and it is not invisible during the current interval
  968. if (drawArrow && drawArrowInInterval)
  969. {
  970. ScreenManager.SpriteBatch.Draw(arrowTexture, vatArrowPosition, Color.White);
  971. if (arrowCounter == 20)
  972. {
  973. drawArrowInInterval = false;
  974. arrowCounter = 0;
  975. }
  976. arrowCounter++;
  977. }
  978. else
  979. {
  980. if (arrowCounter == 20)
  981. {
  982. drawArrowInInterval = true;
  983. arrowCounter = 0;
  984. }
  985. arrowCounter++;
  986. }
  987. }
  988. /// <summary>
  989. /// Draws the smoke button.
  990. /// </summary>
  991. private void DrawSmokeButton()
  992. {
  993. #if WINDOWS_PHONE
  994. int buttonSize = UIConstants.SmokeButtonSize;
  995. if (isSmokebuttonClicked)
  996. {
  997. ScreenManager.SpriteBatch.Draw(
  998. smokeButton, smokeButtonPosition, new Rectangle(buttonSize, 0, buttonSize, buttonSize),
  999. Color.White);
  1000. }
  1001. else
  1002. {
  1003. ScreenManager.SpriteBatch.Draw(
  1004. smokeButton, smokeButtonPosition, new Rectangle(0, 0, buttonSize, buttonSize), Color.White);
  1005. }
  1006. #else
  1007. ScreenManager.SpriteBatch.Draw(smokeButton,
  1008. new Rectangle(
  1009. (int)smokeButtonPosition.X,
  1010. (int)smokeButtonPosition.Y,
  1011. (int)(UIConstants.SmokeButtonSize * ScreenManager.SpriteBatch.ScaleVector.X),
  1012. (int)(UIConstants.SmokeButtonSize * ScreenManager.SpriteBatch.ScaleVector.Y)),
  1013. Color.White);
  1014. #endif
  1015. }
  1016. /// <summary>
  1017. /// Draws the count down string.
  1018. /// </summary>
  1019. private void DrawStartupString()
  1020. {
  1021. // If needed
  1022. if (isAtStartupCountDown)
  1023. {
  1024. string text = string.Empty;
  1025. // If countdown is done
  1026. if (startScreenTime.Seconds == 0)
  1027. {
  1028. text = "Go!";
  1029. isAtStartupCountDown = false;
  1030. AudioManager.PlaySound("BeeBuzzing_Loop", true, .6f);
  1031. }
  1032. else
  1033. {
  1034. text = startScreenTime.Seconds.ToString();
  1035. }
  1036. Vector2 size = font16px.MeasureString(text);
  1037. Vector2 textPosition = (new Vector2(ScreenManager.GraphicsDevice.Viewport.Width,
  1038. ScreenManager.GraphicsDevice.Viewport.Height) - size) / 2f;
  1039. ScreenManager.SpriteBatch.DrawString(font36px, text, textPosition, Color.White);
  1040. }
  1041. }
  1042. #endregion
  1043. }
  1044. }