| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- #region File Description
- //-----------------------------------------------------------------------------
- // FuelCellGame.cs
- //
- // Microsoft XNA Community Game Platform
- // Copyright (C) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- #endregion
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Audio;
- using Microsoft.Xna.Framework.Graphics;
- using Microsoft.Xna.Framework.Input;
- using Microsoft.Xna.Framework.Media;
- using System;
- using MediaPlayer = Microsoft.Xna.Framework.Media.MediaPlayer;
- namespace FuelCell
- {
- /// <summary>
- /// The available states of the game
- /// </summary>
- public enum GameState { Loading, Running, Won, Lost }
- /// <summary>
- /// This is the main type for your game
- /// </summary>
- public class FuelCellGame : Game
- {
- // Resources for drawing.
- private GraphicsDeviceManager graphics;
- private SpriteBatch spriteBatch;
- private SpriteFont statsFont;
- private GameObject ground;
- private Camera gameCamera;
- private Random random;
- private GameState currentGameState = GameState.Loading;
- // Game objects
- private FuelCarrier fuelCarrier;
- private FuelCell[] fuelCells;
- private Barrier[] barriers;
- private GameObject boundingSphere;
- private int retrievedFuelCells = 0;
- private TimeSpan startTime, roundTimer, roundTime;
- private float aspectRatio;
- private IInputState inputState;
- private Song backgroundMusic;
- public FuelCellGame()
- {
- graphics = new GraphicsDeviceManager(this);
- Content.RootDirectory = "Content";
- random = new Random();
- roundTime = GameConstants.RoundTime;
- graphics.PreferredBackBufferWidth = 853;
- graphics.PreferredBackBufferHeight = 480;
- inputState = new InputState(this);
- }
- protected override void Initialize()
- {
- // Initialize the Game objects
- ground = new GameObject();
- gameCamera = new Camera();
- boundingSphere = new GameObject();
- aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;
- base.Initialize();
- }
- /// <summary>
- /// LoadContent will be called once per game and is the place to load
- /// all of your content.
- /// </summary>
- protected override void LoadContent()
- {
- this.Content.RootDirectory = "Content";
- // Create a new SpriteBatch, which can be used to draw textures.
- spriteBatch = new SpriteBatch(GraphicsDevice);
- statsFont = Content.Load<SpriteFont>("Fonts/StatsFont");
- ground.Model = Content.Load<Model>("Models/ground");
- boundingSphere.Model = Content.Load<Model>("Models/sphere1uR");
- // Audio
- backgroundMusic = Content.Load<Song>("Audio/background-music");
- //Initialize fuel cells
- fuelCells = new FuelCell[GameConstants.NumFuelCells];
- for (int index = 0; index < fuelCells.Length; index++)
- {
- fuelCells[index] = new FuelCell();
- fuelCells[index].LoadContent(Content, "Models/fuelcellmodel");
- }
- //Initialize barriers
- barriers = new Barrier[GameConstants.NumBarriers];
- int randomBarrier = random.Next(3);
- string barrierName = null;
- for (int index = 0; index < barriers.Length; index++)
- {
- switch (randomBarrier)
- {
- case 0:
- barrierName = "Models/cube10uR";
- break;
- case 1:
- barrierName = "Models/cylinder10uR";
- break;
- case 2:
- barrierName = "Models/pyramid10uR";
- break;
- }
- barriers[index] = new Barrier();
- barriers[index].LoadContent(Content, barrierName);
- randomBarrier = random.Next(3);
- }
- PlaceFuelCellsAndBarriers();
- //Initialize fuel carrier
- fuelCarrier = new FuelCarrier();
- fuelCarrier.LoadContent(Content, "Models/fuelcarrier");
- }
- /// <summary>
- /// Allows the game to run logic such as updating the world,
- /// checking for collisions, gathering input, and playing audio.
- /// </summary>
- /// <param name="gameTime">Provides a snapshot of timing values.</param>
- protected override void Update(GameTime gameTime)
- {
- // Update the InputState class.
- inputState.Update();
- // Allows the game to exit
- if (inputState.PlayerExit(PlayerIndex.One))
- {
- this.Exit();
- }
- // If the player has only just pressed the Enter key or has pressed the Start button
- if (currentGameState == GameState.Loading)
- {
- if (inputState.StartGame(PlayerIndex.One))
- {
- ResetGame(gameTime, aspectRatio);
- }
- }
- // Main gameplay running screen
- if ((currentGameState == GameState.Running))
- {
- fuelCarrier.Update(inputState, barriers);
- float aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;
- gameCamera.Update(fuelCarrier.ForwardDirection, fuelCarrier.Position, aspectRatio);
- retrievedFuelCells = 0;
- foreach (FuelCell fuelCell in fuelCells)
- {
- fuelCell.Update(fuelCarrier.BoundingSphere);
- if (fuelCell.Retrieved)
- {
- retrievedFuelCells++;
- }
- }
- if (retrievedFuelCells == GameConstants.NumFuelCells)
- {
- currentGameState = GameState.Won;
- }
- roundTimer -= gameTime.ElapsedGameTime;
- if ((roundTimer < TimeSpan.Zero) && (retrievedFuelCells != GameConstants.NumFuelCells))
- {
- currentGameState = GameState.Lost;
- }
- }
- if ((currentGameState == GameState.Won) || (currentGameState == GameState.Lost))
- {
- // Gameplay has stopped and if audio is still playing, stop it.
- if (MediaPlayer.State == MediaState.Playing)
- {
- MediaPlayer.Stop();
- }
- // Reset the world for a new game
- if (inputState.StartGame(PlayerIndex.One))
- {
- ResetGame(gameTime, aspectRatio);
- }
- }
- base.Update(gameTime);
- }
- /// <summary>
- /// Draws the game from background to foreground.
- /// </summary>
- /// <param name="gameTime">Provides a snapshot of timing values.</param>
- protected override void Draw(GameTime gameTime)
- {
- GraphicsDevice.Clear(Color.Black);
- switch (currentGameState)
- {
- case GameState.Loading:
- DrawSplashScreen();
- break;
- case GameState.Running:
- DrawGameplayScreen();
- break;
- case GameState.Won:
- DrawWinOrLossScreen(GameConstants.StrGameWon);
- break;
- case GameState.Lost:
- DrawWinOrLossScreen(GameConstants.StrGameLost);
- break;
- };
- base.Draw(gameTime);
- }
- private void DrawGameplayScreen()
- {
- // Draw the ground terrain model
- DrawTerrain(ground.Model);
- // Draw the fuel cells on the map
- foreach (FuelCell fuelCell in fuelCells)
- {
- if (!fuelCell.Retrieved)
- {
- fuelCell.Draw(gameCamera.ViewMatrix, gameCamera.ProjectionMatrix);
- // Draw the bounding sphere for the fuel cells
- // ChangeRasterizerState(FillMode.WireFrame);
- // fuelCell.DrawBoundingSphere(gameCamera.ViewMatrix, gameCamera.ProjectionMatrix, boundingSphere);
- // ChangeRasterizerState(FillMode.Solid);
- }
- }
- // Draw the barriers on the map
- foreach (Barrier barrier in barriers)
- {
- barrier.Draw(gameCamera.ViewMatrix, gameCamera.ProjectionMatrix);
- // Draw the bounding sphere for the barriers
- // ChangeRasterizerState(FillMode.WireFrame);
- // barrier.DrawBoundingSphere(gameCamera.ViewMatrix, gameCamera.ProjectionMatrix, boundingSphere);
- // ChangeRasterizerState(FillMode.Solid);
- }
- // Draw the player fuelcarrier on the map
- fuelCarrier.Draw(gameCamera.ViewMatrix, gameCamera.ProjectionMatrix);
- // Draw the bounding sphere for the fuel carrier
- // ChangeRasterizerState(FillMode.WireFrame);
- // fuelCarrier.DrawBoundingSphere(gameCamera.ViewMatrix, gameCamera.ProjectionMatrix, boundingSphere);
- // ChangeRasterizerState(FillMode.Solid);
- DrawStats();
- }
- /// <summary>
- /// Helper function to change the rasterizer state for drawing the wireframe bounding spheres
- /// </summary>
- /// <param name="fillmode">The render `FillMode` to draw with, e.g. WireFrame</param>
- /// <param name="cullMode">The culling mode to draw with, e.g. None</param>
- /// <returns>Returns a new RasterizerState to apply to a graphics device</returns>
- private RasterizerState ChangeRasterizerState(FillMode fillmode, CullMode cullMode = CullMode.None)
- {
- RasterizerState rasterizerState = new RasterizerState()
- {
- FillMode = fillmode,
- CullMode = cullMode
- };
- graphics.GraphicsDevice.RasterizerState = rasterizerState;
- return rasterizerState;
- }
- private void DrawTerrain(Model model)
- {
- foreach (ModelMesh mesh in model.Meshes)
- {
- foreach (BasicEffect effect in mesh.Effects)
- {
- effect.EnableDefaultLighting();
- effect.PreferPerPixelLighting = true;
- effect.World = Matrix.Identity;
- // Use the matrices provided by the game camera
- effect.View = gameCamera.ViewMatrix;
- effect.Projection = gameCamera.ProjectionMatrix;
- }
- mesh.Draw();
- }
- }
- private void DrawSplashScreen()
- {
- float xOffsetText, yOffsetText;
- Vector2 viewportSize = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
- Vector2 strCenter;
- graphics.GraphicsDevice.Clear(Color.SteelBlue);
- xOffsetText = yOffsetText = 0;
- Vector2 strInstructionsSize = statsFont.MeasureString(GameConstants.StrInstructions1);
- Vector2 strPosition;
- strCenter = new Vector2(strInstructionsSize.X / 2, strInstructionsSize.Y / 2);
- yOffsetText = (viewportSize.Y / 2 - strCenter.Y);
- xOffsetText = (viewportSize.X / 2 - strCenter.X);
- strPosition = new Vector2(xOffsetText, yOffsetText);
- spriteBatch.Begin();
- spriteBatch.DrawString(statsFont, GameConstants.StrInstructions1, strPosition, Color.White);
- strInstructionsSize = statsFont.MeasureString(GameConstants.StrInstructions2);
- strCenter = new Vector2(strInstructionsSize.X / 2, strInstructionsSize.Y / 2);
- yOffsetText = (viewportSize.Y / 2 - strCenter.Y) + statsFont.LineSpacing;
- xOffsetText = (viewportSize.X / 2 - strCenter.X);
- strPosition = new Vector2(xOffsetText, yOffsetText);
- spriteBatch.DrawString(statsFont, GameConstants.StrInstructions2, strPosition, Color.LightGray);
- spriteBatch.End();
- ResetRenderStates();
- }
- private void DrawWinOrLossScreen(string gameResult)
- {
- float xOffsetText, yOffsetText;
- Vector2 viewportSize = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
- Vector2 strCenter;
- xOffsetText = yOffsetText = 0;
- Vector2 strResult = statsFont.MeasureString(gameResult);
- Vector2 strPlayAgainSize = statsFont.MeasureString(GameConstants.StrPlayAgain);
- Vector2 strPosition;
- strCenter = new Vector2(strResult.X / 2, strResult.Y / 2);
- yOffsetText = (viewportSize.Y / 2 - strCenter.Y);
- xOffsetText = (viewportSize.X / 2 - strCenter.X);
- strPosition = new Vector2(xOffsetText, yOffsetText);
- spriteBatch.Begin();
- spriteBatch.DrawString(statsFont, gameResult, strPosition, Color.Red);
- strCenter = new Vector2(strPlayAgainSize.X / 2, strPlayAgainSize.Y / 2);
- yOffsetText = (viewportSize.Y / 2 - strCenter.Y) + (float)statsFont.LineSpacing;
- xOffsetText = (viewportSize.X / 2 - strCenter.X);
- strPosition = new Vector2(xOffsetText, yOffsetText);
- spriteBatch.DrawString(statsFont, GameConstants.StrPlayAgain, strPosition, Color.AntiqueWhite);
- spriteBatch.End();
- ResetRenderStates();
- }
- private void DrawStats()
- {
- float xOffsetText, yOffsetText;
- string str1 = GameConstants.StrTimeRemaining;
- string str2 = GameConstants.StrCellsFound + retrievedFuelCells.ToString() + " of " + GameConstants.NumFuelCells.ToString();
- Rectangle rectSafeArea;
- str1 += (roundTimer.Seconds).ToString();
- //Calculate str1 position
- rectSafeArea = GraphicsDevice.Viewport.TitleSafeArea;
- xOffsetText = rectSafeArea.X;
- yOffsetText = rectSafeArea.Y;
- Vector2 strSize = statsFont.MeasureString(str1);
- Vector2 strPosition = new Vector2(xOffsetText + 10, yOffsetText);
- spriteBatch.Begin();
- spriteBatch.DrawString(statsFont, str1, strPosition, Color.White);
- strPosition.Y += strSize.Y;
- spriteBatch.DrawString(statsFont, str2, strPosition, Color.White);
- spriteBatch.End();
- ResetRenderStates();
- }
- private void ResetRenderStates()
- {
- //re-enable depth buffer after sprite batch disablement
- GraphicsDevice.DepthStencilState = DepthStencilState.Default;
- GraphicsDevice.BlendState = BlendState.Opaque;
- GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
- GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
- }
- private void PlaceFuelCellsAndBarriers()
- {
- int min = GameConstants.MinDistance;
- int max = GameConstants.MaxDistance;
- Vector3 tempCenter;
- //place fuel cells
- foreach (FuelCell cell in fuelCells)
- {
- cell.Position = GenerateRandomPosition(min, max);
- tempCenter = cell.BoundingSphere.Center;
- tempCenter.X = cell.Position.X;
- tempCenter.Z = cell.Position.Z;
- cell.BoundingSphere = new BoundingSphere(tempCenter, cell.BoundingSphere.Radius);
- cell.Retrieved = false;
- }
- //place barriers
- foreach (Barrier barrier in barriers)
- {
- barrier.Position = GenerateRandomPosition(min, max);
- tempCenter = barrier.BoundingSphere.Center;
- tempCenter.X = barrier.Position.X;
- tempCenter.Z = barrier.Position.Z;
- barrier.BoundingSphere = new BoundingSphere(tempCenter, barrier.BoundingSphere.Radius);
- }
- }
- private Vector3 GenerateRandomPosition(int min, int max)
- {
- int xValue, zValue;
- do
- {
- xValue = random.Next(min, max);
- zValue = random.Next(min, max);
- if (random.Next(100) % 2 == 0)
- xValue *= -1;
- if (random.Next(100) % 2 == 0)
- zValue *= -1;
- } while (IsOccupied(xValue, zValue));
- return new Vector3(xValue, 0, zValue);
- }
- private bool IsOccupied(int xValue, int zValue)
- {
- foreach (GameObject currentObj in fuelCells)
- {
- if (((int)(MathHelper.Distance(xValue, currentObj.Position.X)) < 15) &&
- ((int)(MathHelper.Distance(zValue, currentObj.Position.Z)) < 15))
- {
- return true;
- }
- }
- foreach (GameObject currentObj in barriers)
- {
- if (((int)(MathHelper.Distance(xValue, currentObj.Position.X)) < 15) &&
- ((int)(MathHelper.Distance(zValue, currentObj.Position.Z)) < 15))
- {
- return true;
- }
- }
- return false;
- }
- private void ResetGame(GameTime gameTime, float aspectRatio)
- {
- fuelCarrier.Reset();
- gameCamera.Update(fuelCarrier.ForwardDirection, fuelCarrier.Position, aspectRatio);
- InitializeGameField();
- retrievedFuelCells = 0;
- startTime = gameTime.TotalGameTime;
- roundTimer = roundTime;
- currentGameState = GameState.Running;
- // We use a try catch around the Media player, else in debug mode it can cause an exception which we need to catch.
- try
- {
- MediaPlayer.Stop();
- MediaPlayer.IsRepeating = true;
- MediaPlayer.Volume = 0.5f;
- MediaPlayer.Play(backgroundMusic);
- }
- catch { }
- }
- private void InitializeGameField()
- {
- //Initialize barriers
- barriers = new Barrier[GameConstants.NumBarriers];
- int randomBarrier = random.Next(3);
- string barrierName = null;
- for (int index = 0; index < GameConstants.NumBarriers; index++)
- {
- switch (randomBarrier)
- {
- case 0:
- barrierName = "Models/cube10uR";
- break;
- case 1:
- barrierName = "Models/cylinder10uR";
- break;
- case 2:
- barrierName = "Models/pyramid10uR";
- break;
- }
- barriers[index] = new Barrier();
- barriers[index].LoadContent(Content, barrierName);
- randomBarrier = random.Next(3);
- }
- PlaceFuelCellsAndBarriers();
- }
- }
- }
|