#region File Description
//-----------------------------------------------------------------------------
// GameplayScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Media;
#endregion
namespace NetRumble
{
///
/// This screen implements the actual game logic.
///
///
/// This public class is somewhat similar to one of the same name in the
/// GameStateManagement sample.
///
public class GameplayScreen : GameScreen, IDisposable
{
#region Gameplay Data
///
/// The primary gameplay object.
///
private World world;
///
/// The ship for the local player.
///
private Ship localShip;
///
/// The game-winner text.
///
private string winnerString = String.Empty;
///
/// The position of the game-winner text.
///
private Vector2 winnerStringPosition;
#endregion
#region Graphics Data
///
/// The bloom component, applied to part of the game world.
///
private BloomComponent bloomComponent;
///
/// The starfield, rendering behind the game.
///
private Starfield starfield;
#endregion
#region Networking Data
///
/// The network session used in this game.
///
private NetworkSession networkSession;
///
/// Event handler for the session-ended event.
///
EventHandler sessionEndedHandler;
///
/// Event handler for the game-ended event.
///
EventHandler gameEndedHandler;
///
/// Event handler for the gamer-left event.
///
EventHandler gamerLeftHandler;
#endregion
#region Initialization Methods
///
/// Construct a new GameplayScreen object.
///
/// The network session for this game.
/// The primary gameplay object.
public GameplayScreen(NetworkSession networkSession, World world)
{
// safety-check the parameters
if (networkSession == null)
{
throw new ArgumentNullException("networkSession");
}
if (world == null)
{
throw new ArgumentNullException("world");
}
// apply the parameters
this.networkSession = networkSession;
this.world = world;
// set up the network events
sessionEndedHandler = new EventHandler(
networkSession_SessionEnded);
networkSession.SessionEnded += sessionEndedHandler;
gameEndedHandler = new EventHandler(
networkSession_GameEnded);
networkSession.GameEnded += gameEndedHandler;
gamerLeftHandler = new EventHandler(
networkSession_GamerLeft);
networkSession.GamerLeft += gamerLeftHandler;
// cache the local player's ship object
if (networkSession.LocalGamers.Count > 0)
{
PlayerData playerData = networkSession.LocalGamers[0].Tag as PlayerData;
if (playerData != null)
{
localShip = playerData.Ship;
}
}
// set the transition times
TransitionOnTime = TimeSpan.FromSeconds(1.0);
TransitionOffTime = TimeSpan.FromSeconds(1.0);
}
///
/// Load graphics content for the game.
///
public override void LoadContent()
{
// Developers Comment or uncomment the bloomComponent to run with effects or not
// ***************************
// Comment or uncomment from here
// ***************************
// create and add the bloom effect
#if !BLOOM
bloomComponent = new BloomComponent(ScreenManager.Game);
bloomComponent.Settings = BloomSettings.PresetSettings[0];
ScreenManager.Game.Components.Add(bloomComponent);
bloomComponent.Initialize();
bloomComponent.Visible = false; // we want to control when bloom component is drawn
#endif
// ***************************
// Comment or uncomment to here
// ***************************
// create the starfield
starfield = new Starfield(Vector2.Zero, ScreenManager.GraphicsDevice,
ScreenManager.Content);
starfield.LoadContent();
// start the background soundtrack
AudioManager.PlaySoundTrack();
base.LoadContent();
}
///
/// Release graphics data.
///
public override void UnloadContent()
{
if (starfield != null)
{
starfield.UnloadContent();
}
base.UnloadContent();
}
#endregion
#region Updating Methods
///
/// Updates the state of the game. This method checks the GameScreen.IsActive
/// property, so the game will stop updating when the pause menu is active,
/// or if you tab away to a different application.
///
public override void Update(GameTime gameTime, bool otherScreenHasFocus,
bool coveredByOtherScreen)
{
base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
// if something else has canceled our game, then exit
if ((networkSession == null) || (world == null))
{
if (!IsExiting)
{
ExitScreen();
}
base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
return;
}
// update the world
if (world != null)
{
if (otherScreenHasFocus || coveredByOtherScreen)
{
world.Update((float)gameTime.ElapsedGameTime.TotalSeconds, true);
}
else if (world.GameExited)
{
if (!IsExiting)
{
ExitScreen();
}
networkSession = null;
base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
return;
}
else
{
world.Update((float)gameTime.ElapsedGameTime.TotalSeconds, false);
// if the game was just won, then build the winner string
if (world.GameWon && String.IsNullOrEmpty(winnerString) &&
(world.WinnerIndex >= 0) &&
(world.WinnerIndex < networkSession.AllGamers.Count))
{
winnerString =
networkSession.AllGamers[world.WinnerIndex].Gamertag;
winnerString +=
" has won the game!\nPress A to return to the lobby.";
Vector2 winnerStringSize =
world.PlayerFont.MeasureString(winnerString);
winnerStringPosition = new Vector2(
ScreenManager.GraphicsDevice.Viewport.X +
ScreenManager.GraphicsDevice.Viewport.Width / 2 -
(float)Math.Floor(winnerStringSize.X / 2),
ScreenManager.GraphicsDevice.Viewport.Y +
ScreenManager.GraphicsDevice.Viewport.Height / 2 -
(float)Math.Floor(winnerStringSize.Y / 2));
}
}
}
}
///
/// Lets the game respond to player input. Unlike the Update method,
/// this will only be called when the gameplay screen is active.
///
public override void HandleInput(InputState input)
{
if (input == null)
throw new ArgumentNullException("input");
if (!IsExiting)
{
if ((world != null) && !world.GameExited)
{
if (input.PauseGame && !world.GameWon)
{
// If they pressed pause, bring up the pause menu screen.
const string message = "Exit the game?";
MessageBoxScreen messageBox = new MessageBoxScreen(message,
false);
messageBox.Accepted += ExitMessageBoxAccepted;
ScreenManager.AddScreen(messageBox);
}
if (input.MenuSelect && world.GameWon)
{
world.GameExited = true;
world = null;
if (!IsExiting)
{
ExitScreen();
}
networkSession = null;
}
}
}
}
///
/// Event handler for when the user selects "yes" on the "are you sure
/// you want to exit" message box.
///
private void ExitMessageBoxAccepted(object sender, EventArgs e)
{
world.GameExited = true;
world = null;
}
///
/// Force the end of a network session so that a new one can be joined.
///
public void EndSession()
{
if (networkSession != null)
{
networkSession.Dispose();
networkSession = null;
}
}
///
/// Exit this screen.
///
public override void ExitScreen()
{
if (bloomComponent != null)
{
bloomComponent.Visible = false;
ScreenManager.Game.Components.Remove(bloomComponent);
bloomComponent = null;
}
if (!IsExiting && (networkSession != null))
{
networkSession.SessionEnded -= sessionEndedHandler;
networkSession.GameEnded -= gameEndedHandler;
networkSession.GamerLeft -= gamerLeftHandler;
}
MediaPlayer.Stop();
base.ExitScreen();
}
///
/// Screen-specific update to gamer rich presence.
///
public override void UpdatePresence()
{
if (!IsExiting && (networkSession != null))
{
bool isTied = (world.HighScorers.Count > 1);
for (int i = 0; i < networkSession.AllGamers.Count; ++i)
{
NetworkGamer networkGamer = networkSession.AllGamers[i];
if (networkGamer.IsLocal)
{
SignedInGamer signedInGamer = (networkGamer as LocalNetworkGamer).SignedInGamer;
if (signedInGamer.IsSignedInToLive)
{
if (world.HighScorers.Contains(i))
{
if (isTied)
signedInGamer.Presence.PresenceMode = GamerPresenceMode.ScoreIsTied;
else
signedInGamer.Presence.PresenceMode = GamerPresenceMode.Winning;
}
else
{
signedInGamer.Presence.PresenceMode = GamerPresenceMode.Losing;
}
}
}
}
}
}
#endregion
#region Drawing Methods
///
/// Draws the gameplay screen.
///
public override void Draw(GameTime gameTime)
{
float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
if (networkSession != null)
{
// make sure we know what the local ship is
if ((localShip == null) && (networkSession.LocalGamers.Count > 0))
{
PlayerData playerData = networkSession.LocalGamers[0].Tag
as PlayerData;
if (playerData.Ship != null)
{
localShip = playerData.Ship;
starfield.Reset(localShip.Position);
}
}
if (bloomComponent != null)
{
bloomComponent.BeginDraw();
}
// draw the world
if ((world != null) && (localShip != null) && !IsExiting)
{
Vector2 center = new Vector2(
localShip.Position.X + ScreenManager.GraphicsDevice.Viewport.X -
ScreenManager.GraphicsDevice.Viewport.Width / 2,
localShip.Position.Y + ScreenManager.GraphicsDevice.Viewport.Y -
ScreenManager.GraphicsDevice.Viewport.Height / 2);
starfield.Draw(center);
world.Draw(elapsedTime, center);
if (bloomComponent != null)
{
bloomComponent.Draw(gameTime);
}
}
// draw the user-interface elements of the game (scores, etc.)
DrawHud((float)gameTime.TotalGameTime.TotalSeconds);
}
// If the game is transitioning on or off, fade it out to black.
if (ScreenState == ScreenState.TransitionOn && (TransitionPosition > 0))
ScreenManager.FadeBackBufferToBlack(255 - TransitionAlpha);
}
///
/// Draw the user interface elements of the game (scores, etc.).
///
/// The amount of elapsed time, in seconds.
private void DrawHud(float totalTime)
{
if ((networkSession != null) && (world != null))
{
ScreenManager.SpriteBatch.Begin();
// draw players 0 - 3 at the top of the screen
Vector2 position = new Vector2(
ScreenManager.GraphicsDevice.Viewport.Width * 0.2f,
ScreenManager.GraphicsDevice.Viewport.Height * 0.1f);
for (int i = 0; i < Math.Min(4, networkSession.AllGamers.Count); i++)
{
world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
position, ScreenManager.SpriteBatch, false);
position.X += ScreenManager.GraphicsDevice.Viewport.Width * 0.2f;
}
// draw players 4 - 7 at the bottom of the screen
position = new Vector2(
ScreenManager.GraphicsDevice.Viewport.Width * 0.2f,
ScreenManager.GraphicsDevice.Viewport.Height * 0.9f);
for (int i = 4; i < Math.Min(8, networkSession.AllGamers.Count); i++)
{
world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
position, ScreenManager.SpriteBatch, false);
position.X += ScreenManager.GraphicsDevice.Viewport.Width * 0.2f;
}
// draw players 8 - 11 at the left of the screen
position = new Vector2(
ScreenManager.GraphicsDevice.Viewport.Width * 0.13f,
ScreenManager.GraphicsDevice.Viewport.Height * 0.2f);
for (int i = 8; i < Math.Min(12, networkSession.AllGamers.Count); i++)
{
world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
position, ScreenManager.SpriteBatch, false);
position.Y += ScreenManager.GraphicsDevice.Viewport.Height * 0.2f;
}
// draw players 12 - 15 at the right of the screen
position = new Vector2(
ScreenManager.GraphicsDevice.Viewport.Width * 0.9f,
ScreenManager.GraphicsDevice.Viewport.Height * 0.2f);
for (int i = 12; i < Math.Min(16, networkSession.AllGamers.Count); i++)
{
world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
position, ScreenManager.SpriteBatch, false);
position.Y += ScreenManager.GraphicsDevice.Viewport.Height * 0.2f;
}
// if the game is over, draw the winner text
if (world.GameWon && !String.IsNullOrEmpty(winnerString))
{
ScreenManager.SpriteBatch.DrawString(world.PlayerFont, winnerString,
winnerStringPosition, Color.White, 0f, Vector2.Zero, 1.3f,
SpriteEffects.None, 0f);
}
ScreenManager.SpriteBatch.End();
}
}
#endregion
#region Networking Event Handlers
///
/// Handle the end of the game session.
///
void networkSession_GameEnded(object sender, GameEndedEventArgs e)
{
if ((world != null) && !world.GameWon && !world.GameExited)
{
world.GameExited = true;
}
if (!IsExiting && ((world == null) || world.GameExited))
{
world = null;
ExitScreen();
networkSession = null;
}
}
///
/// Handle the end of the session.
///
void networkSession_SessionEnded(object sender, NetworkSessionEndedEventArgs e)
{
if ((world != null) && !world.GameExited)
{
world.GameExited = true;
world = null;
}
if (!IsExiting)
{
ExitScreen();
}
networkSession = null;
}
///
/// Handle a player leaving the game.
///
void networkSession_GamerLeft(object sender, GamerLeftEventArgs e)
{
PlayerData playerData = e.Gamer.Tag as PlayerData;
if ((playerData != null) && (playerData.Ship != null))
{
playerData.Ship.Die(null, true);
}
}
#endregion
#region IDisposable Implementation
///
/// Finalizes the GameplayScreen object, calls Dispose(false)
///
~GameplayScreen()
{
Dispose(false);
}
///
/// Disposes the GameplayScreen object.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Disposes this object.
///
///
/// True if this method was called as part of the Dispose method.
///
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
lock (this)
{
if (bloomComponent != null)
{
bloomComponent.Dispose();
bloomComponent = null;
}
if (starfield != null)
{
starfield.Dispose();
starfield = null;
}
}
}
}
#endregion
}
}