#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.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
#endregion
namespace NetworkStateManagement
{
///
/// This screen implements the actual game logic. It is just a
/// placeholder to get the idea across: you'll probably want to
/// put some more interesting gameplay in here!
///
class GameplayScreen : GameScreen
{
#region Fields
NetworkSession networkSession;
ContentManager content;
SpriteFont gameFont;
Vector2 playerPosition = new Vector2(100, 100);
Vector2 enemyPosition = new Vector2(100, 100);
Random random = new Random();
float pauseAlpha;
#endregion
#region Properties
///
/// The logic for deciding whether the game is paused depends on whether
/// this is a networked or single player game. If we are in a network session,
/// we should go on updating the game even when the user tabs away from us or
/// brings up the pause menu, because even though the local player is not
/// responding to input, other remote players may not be paused. In single
/// player modes, however, we want everything to pause if the game loses focus.
///
new bool IsActive
{
get
{
if (networkSession == null)
{
// Pause behavior for single player games.
return base.IsActive;
}
else
{
// Pause behavior for networked games.
return !IsExiting;
}
}
}
#endregion
#region Initialization
///
/// Constructor.
///
public GameplayScreen(NetworkSession networkSession)
{
this.networkSession = networkSession;
TransitionOnTime = TimeSpan.FromSeconds(1.5);
TransitionOffTime = TimeSpan.FromSeconds(0.5);
}
///
/// Load graphics content for the game.
///
public override void LoadContent()
{
if (content == null)
content = new ContentManager(ScreenManager.Game.Services, "Content");
gameFont = content.Load("gamefont");
// A real game would probably have more content than this sample, so
// it would take longer to load. We simulate that by delaying for a
// while, giving you a chance to admire the beautiful loading screen.
Thread.Sleep(1000);
// once the load has finished, we use ResetElapsedTime to tell the game's
// timing mechanism that we have just finished a very long frame, and that
// it should not try to catch up.
ScreenManager.Game.ResetElapsedTime();
}
///
/// Unload graphics content used by the game.
///
public override void UnloadContent()
{
content.Unload();
}
#endregion
#region Update and Draw
///
/// Updates the state of the game.
///
public override void Update(GameTime gameTime, bool otherScreenHasFocus,
bool coveredByOtherScreen)
{
base.Update(gameTime, otherScreenHasFocus, false);
// Gradually fade in or out depending on whether we are covered by the pause screen.
if (coveredByOtherScreen)
pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
else
pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);
if (IsActive)
{
// Apply some random jitter to make the enemy move around.
const float randomization = 10;
enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;
// Apply a stabilizing force to stop the enemy moving off the screen.
Vector2 targetPosition = new Vector2(200, 200);
enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);
// TODO: this game isn't very fun! You could probably improve
// it by inserting something more interesting in this space :-)
}
// If we are in a network game, check if we should return to the lobby.
if ((networkSession != null) && !IsExiting)
{
if (networkSession.SessionState == NetworkSessionState.Lobby)
{
LoadingScreen.Load(ScreenManager, true, null,
new BackgroundScreen(),
new LobbyScreen(networkSession));
}
}
}
///
/// 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 (ControllingPlayer.HasValue)
{
// In single player games, handle input for the controlling player.
HandlePlayerInput(input, ControllingPlayer.Value);
}
else if (networkSession != null)
{
// In network game modes, handle input for all the
// local players who are participating in the session.
foreach (LocalNetworkGamer gamer in networkSession.LocalGamers)
{
if (!HandlePlayerInput(input, gamer.SignedInGamer.PlayerIndex))
break;
}
}
}
///
/// Handles input for the specified player. In local game modes, this is called
/// just once for the controlling player. In network modes, it can be called
/// more than once if there are multiple profiles playing on the local machine.
/// Returns true if we should continue to handle input for subsequent players,
/// or false if this player has paused the game.
///
bool HandlePlayerInput(InputState input, PlayerIndex playerIndex)
{
// Look up inputs for the specified player profile.
KeyboardState keyboardState = input.CurrentKeyboardStates[(int)playerIndex];
GamePadState gamePadState = input.CurrentGamePadStates[(int)playerIndex];
// The game pauses either if the user presses the pause button, or if
// they unplug the active gamepad. This requires us to keep track of
// whether a gamepad was ever plugged in, because we don't want to pause
// on PC if they are playing with a keyboard and have no gamepad at all!
bool gamePadDisconnected = !gamePadState.IsConnected &&
input.GamePadWasConnected[(int)playerIndex];
if (input.IsPauseGame(playerIndex) || gamePadDisconnected)
{
ScreenManager.AddScreen(new PauseMenuScreen(networkSession), playerIndex);
return false;
}
// Otherwise move the player position.
Vector2 movement = Vector2.Zero;
if (keyboardState.IsKeyDown(Keys.Left))
movement.X--;
if (keyboardState.IsKeyDown(Keys.Right))
movement.X++;
if (keyboardState.IsKeyDown(Keys.Up))
movement.Y--;
if (keyboardState.IsKeyDown(Keys.Down))
movement.Y++;
Vector2 thumbstick = gamePadState.ThumbSticks.Left;
movement.X += thumbstick.X;
movement.Y -= thumbstick.Y;
if (movement.Length() > 1)
movement.Normalize();
playerPosition += movement * 2;
return true;
}
///
/// Draws the gameplay screen.
///
public override void Draw(GameTime gameTime)
{
// This game has a blue background. Why? Because!
ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
Color.CornflowerBlue, 0, 0);
// Our player and enemy are both actually just text strings.
SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
spriteBatch.Begin();
spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);
spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
enemyPosition, Color.DarkRed);
if (networkSession != null)
{
string message = "Players: " + networkSession.AllGamers.Count;
Vector2 messagePosition = new Vector2(100, 480);
spriteBatch.DrawString(gameFont, message, messagePosition, Color.White);
}
spriteBatch.End();
// If the game is transitioning on or off, fade it out to black.
if (TransitionPosition > 0 || pauseAlpha > 0)
{
float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);
ScreenManager.FadeBackBufferToBlack(alpha);
}
}
#endregion
}
}