GameplayScreen.cs 47 KB

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