/// <summary> /// Update the positions of the missile and, if applicable, updates the player's /// health if the player has been hit by a missile /// </summary> /// <param name="player">To update the player's health, if applicable</param> /// <param name="floorPlan">To determine if a missile is no longer in the map</param> /// <param name="gameState">The current state of the game</param> /// <remarks> /// If the player has lost all health, the game will transition to the end state /// </remarks> public void Update(Player player, int[,] floorPlan, ref GameConstants.GameState gameState) { // update each missile for (int i = 0; i < missileList.Count; i++) { missileList[i].Update(); if (missileList[i].Position.Y < 0.0f || floorPlan[(int)missileList[i].Position.X, (int)-missileList[i].Position.Z] != 0) { // this missile is off of the map (either ran into a building or under the map) missileList.Remove(missileList[i]); continue; } if (player.BoundingSphere.Contains(missileList[i].Position) != ContainmentType.Disjoint) { // the player was hit missileList.Remove(missileList[i]); player.HitByMissile(ref gameState); explosionEffect.Play(); } } }
/// <summary> /// Update the player's attributes (called 60 times sec). /// </summary> /// <param name="keyboardState">Information about user keyboard input</param> /// <param name="gamePadState">Information about user gamepad input</param> /// <param name="gameTime">Information about time elapsed since last update</param> /// <param name="map">The map the player is within</param> /// <param name="gameState">The state of the game</param> /// <remarks>If the player runs out of fuel or is out of health, the gamestate will be changed to end</remarks> public void Update(KeyboardState keyboardState, GamePadState gamePadState, GameTime gameTime, ref Map map, ref GameConstants.GameState gameState) { Vector3 movement; float turnAmount = DetermineTurnAmount(keyboardState, gamePadState); // determine if the user wants to turn UpdateVelocity(keyboardState, gamePadState); // update the velocity of the player based on user input // Move the player to the next position based on the current position and movement amount ForwardDirection += turnAmount * velocity * TurnSpeed; // note: the final turn amount takes velocity into account movement = Vector3.Transform(new Vector3(0.0f, 0.0f, -1.0f), Matrix.CreateRotationY(ForwardDirection)); movement *= velocity; UpdatePositionAndBoundingSphere(Position + movement); // Check for collision with objects in the map GameConstants.CollisionType collision = map.CheckCollision(this.BoundingSphere); if (collision == GameConstants.CollisionType.Building) { // undo the movement and set velocity to zero since we ran into building // can cause "bounceback effect" UpdatePositionAndBoundingSphere(Position - movement); // Update the player's health based on the velocity the player was at during the crash // If player's health moves below zero, transition to ending gamestate healthMeter.HitBarrier(velocity, ref gameState); // Play crash sound effect (major or minor crash effect based on player velocity) soundEffects.PlayCrash(velocity); velocity = 0.0f; } else if (collision == GameConstants.CollisionType.Bonus) { // update the player's bonus score with the bonus amount bonusScore += 25; } // Update the gauges sped.Update(velocity); UpdateFuel(gameTime, collision, ref gameState); }
/// <summary> /// Update the amount of fuel the player has and the player's fuel gauges. /// </summary> /// <param name="gameTime">Lets us determine the amount of time since last update</param> /// <param name="collision">Lets us determine if the car collided with a fuel object</param> /// <param name="gameState">Current state of the game</param> /// <remarks>The gamestate is changed to end if the player runs out of fuel</remarks> private void UpdateFuel(GameTime gameTime, GameConstants.CollisionType collision, ref GameConstants.GameState gameState) { fuel -= (float) gameTime.ElapsedGameTime.TotalSeconds; // decrement fuel usage based on time since last update if (fuel < 0) { // out of fuel, transition to ending fuel = 0; gameState = GameConstants.GameState.End; } else if (collision == GameConstants.CollisionType.Fuel) { // picked up fuel while driving fuel = MaxFuel; } fuelGauge.Update(fuel); }
/// <summary> /// Updates the player's health when the player is hit by a missile /// </summary> /// <param name="gameState">The current state of the game</param> /// <remarks> /// This method should only be called when a missile hits the player. /// If the player's health drops below zero, the game will transition /// to the end state. /// </remarks> public void HitByMissile(ref GameConstants.GameState gameState) { healthMeter.HitByMissile(ref gameState); }
/// <summary> /// Draw the player model and the player's gauges (if applicable) /// </summary> /// <param name="gameCamera">For view and projection matrices</param> /// <param name="gameState">State of the game</param> /// <remarks>The player's gauges are not drawn during the intro</remarks> public void Draw(Camera gameCamera, GameConstants.GameState gameState) { DrawModel(ref gameCamera); if (gameState != GameConstants.GameState.Intro) { sped.Draw(); fuelGauge.Draw(); healthMeter.Draw(); } }
/// <summary> /// Moves the player around the map during the introduction without user input. /// </summary> /// <param name="gameState">The state of the game</param> /// <remarks> /// If the player makes a complete revolution of the map, the gameState transitions /// to ready. /// </remarks> public void AutoPilot(ref GameConstants.GameState gameState) { float turnAmount = 0.0f; velocity = IntroVelocity; for (int i = 0; i < pivots.Length; i++) { if (pivots[i].Contains((int)Position.X, (int)-Position.Z)) { // This a square the player should make a turn on // Update the forward direction based on turn amount turnAmount = IntroTurnAmount; ForwardDirection += turnAmount * velocity * TurnSpeed; // Only turn as far as required by this pivot if (ForwardDirection > pivotForwardDirections[i]) ForwardDirection = pivotForwardDirections[i]; } } // Check if player has made a complete reveloution and move into ready gamestate if so if (playerStartRect.Contains((int)Position.X, (int)-Position.Z) && ForwardDirection > 0) { gameState = GameConstants.GameState.Ready; } // Move the player to the next position based on the current position and movement amount Vector3 movement = Vector3.Transform(new Vector3(0.0f, 0.0f, -1.0f), Matrix.CreateRotationY(ForwardDirection)); movement *= velocity; UpdatePositionAndBoundingSphere(Position + movement); // play the sound of the engine soundEffects.PlayEngine(0); }
/// <summary> /// Allows the client to move the enemy craft /// </summary> /// <param name="enemies">For positions of all of the other enemies in the game</param> /// <param name="player">Allows queries for attributes of the player</param> /// <param name="floorPlan">Gives the arrangement of the building in the city</param> ///<param name="gameTime">Information on the time since last update for missiles</param> /// <param name="gameState">Gives the current state of the game</param> /// <remarks> /// If the player is caught or the player is hit by a missile and runs /// out of health, the gamestate will transition to end /// </remarks> public void Update(Enemies enemies, Player player, int[,] floorPlan, GameTime gameTime, ref GameConstants.GameState gameState) { bool canMakeMovement = false; // boolean for status if the player was able to make a move on this update Vector3 movement; // the movement to be applied to the enemy // check if the player has been caught, that is the enemy craft and player are in the same // grid unit, and if so transition to game ending state if (((int)Position.X - (int)player.Position.X) == 0 && ((int)Position.Z - (int)player.Position.Z) == 0) { gameState = GameConstants.GameState.End; return; } // Update the missiles and time during chase missiles.Update(player, floorPlan, ref gameState); if (chasing) { // Update the timeOfChase with the elapsed time since the last update timeOfChase += gameTime.ElapsedGameTime.TotalSeconds; } if (ReadyForNextMove()) { // mark the spots on the grid where the enemies are and where they are headed in the next move MarkEnemySquares(enemies, floorPlan); // the player is in the center of a grid square, and can decide on the next direction to face // now, check if the player is in the enemy's line of sight (no buildings or enemies obstructing view // from enemy to player), and, if so, set the chasing property // to true chasing = CheckIfInLineOfSight(player, floorPlan); if (chasing) { // we are chasing the player, set direction toward the player SetDirectionTowardPlayer(player); // we can make a movement since nothing is obstructing between player and this enemy canMakeMovement = true; // Check if we are locked on to the player, and if so, attempt to fire if (this.LockedOn) { missiles.FireAt(this.Position, FindTargetPosition(player), gameTime); } } else { // reset the time of chase to zero since we are not chasing timeOfChase = 0.0; // check to see if no other enemyies are chasing and this is the closest enemy // in terms of linear distance // If so, find an A* path to the player if possible. // This makes the game more challenging since the player will always be under pressure // from some enemy if (ShouldMoveTowardPlayer(player, enemies)) { List<Vector2> aStarPath = AStar.FindPath(floorPlan, Position, player.Position); //Helpers.AStarDebugList = aStarPath; if (aStarPath == null) { // We could not find an A* path to the player, move randomly canMakeMovement = MoveRandomly(floorPlan); // returns true if a move was able to be made } else { // set the enemy direction to follow the A* path UpdateDirectionFromPath(aStarPath); canMakeMovement = true; } } else { // we are not chasing or the closest enemy // move randomly around the grid until we spot the player next canMakeMovement = MoveRandomly(floorPlan); // returns true if a move was able to be made } } // unmark the spots on the grid where the enemies are and where they are headed in the next move UnmarkEnemySquares(enemies, floorPlan); if (!canMakeMovement) { // the enemy is surrounded and cannot make a move // set velocity to zero and stay put for this move speed = 0.0f; } else { // update positionOfLastMove with grid square of current position positionOfLastMove = new Rectangle((int)Position.X, (int)-Position.Z, 1, 1); // update nextPosition with next grid space in the direction // we are headed nextPosition = new Rectangle( (int)(Position.X - Math.Sin(ForwardDirection)), (int)(Position.Z - Math.Cos(ForwardDirection)), 1, 1); speed = EnemySpeed; } } // Make the movement movement = Vector3.Transform(new Vector3(0.0f, 0.0f, -1.0f), Matrix.CreateRotationY(ForwardDirection)); movement *= speed; UpdatePositionAndBoundingSphere(Position + movement); }
/// <summary> /// Draw the enemy model and missiles /// </summary> /// <param name="device">Graphics card to draw the missiles</param> /// <param name="gameCamera">For view and projection matrices</param> /// <param name="gameState">For the state of the game (do not draw missiles once game over)</param> public void Draw(ref GraphicsDevice device, Camera gameCamera, GameConstants.GameState gameState) { // Draw the enemy model Matrix[] transforms = new Matrix[Model.Bones.Count]; Model.CopyAbsoluteBoneTransformsTo(transforms); Matrix translateMatrix = Matrix.CreateTranslation(Position); // move the model to the correct position Matrix worldMatrix = translateMatrix; // setup world matrix based on translation foreach (ModelMesh mesh in Model.Meshes) { foreach (BasicEffect effect in mesh.Effects) { // setup effect based on worldMatrix and properties of the camera effect.World = worldMatrix * transforms[mesh.ParentBone.Index]; effect.View = gameCamera.ViewMatrix; effect.Projection = gameCamera.ProjectionMatrix; effect.EnableDefaultLighting(); effect.PreferPerPixelLighting = true; } mesh.Draw(); } // Draw the missiles if we are still playing if (gameState == GameConstants.GameState.Playing) missiles.Draw(ref device, gameCamera); }