using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace CarFire { // Everything in objects built from this class represent the critical game state public class GameState { public long frameNumber; private long checksum; public long Checksum { get { return checksum; } } public bool[] isGameOver; public bool[] isTerminated; // Since this is not a game, I'll just keep track of the user inputs as the game state. public int[] mouseLocationX; public int[] mouseLocationY; public bool[] mouseButton; public List[] keysDown; public int[] keypressCount; public long elapsedTime; /* Constructor */ public GameState() { frameNumber = 0; checksum = 0; isGameOver = new bool[4]; isTerminated = new bool[4]; mouseLocationX = new int[4]; mouseLocationY = new int[4]; mouseButton = new bool[4]; keysDown = new List[4]; for (int i = 0; i < 4; i++) keysDown[i] = new List(); keypressCount = new int[4]; elapsedTime = 0; checksum = 0; } /* The game engine! */ public void advanceFrame(NextInputs inputs, long milliseconds) { // Advance frame number frameNumber++; // Advance game - for the test harness, just record statistics and input states. elapsedTime += milliseconds; for (int player = 0; player < 4; player++) { //if (isGameOver[player]) // continue; if (inputs.mousePressedChanged[player]) mouseButton[player] = inputs.mousePressed[player]; if (inputs.mouseLocationChanged[player]) { mouseLocationX[player] = inputs.mouseLocationX[player]; mouseLocationY[player] = inputs.mouseLocationY[player]; } foreach (Keys k in inputs.keysPressed[player]) if (!keysDown[player].Contains(k)) { keysDown[player].Add(k); keypressCount[player]++; } foreach (Keys k in inputs.keysReleased[player]) keysDown[player].Remove(k); // If the mouse was pressed for a certain player, activate game over or terminated states as appropriate if (inputs.mousePressed[player]) for (int p = 0; p < 4; p++) { int x = 200 * p + 10; int y = 220; if (mouseLocationX[player] >= x && mouseLocationY[player] >= y && mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25) { isGameOver[p] = true; } y += 25; if (mouseLocationX[player] >= x && mouseLocationY[player] >= y && mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25) { isGameOver[p] = true; isTerminated[p] = true; } } } // Advance the checksum. computeChecksum(); } /* Just hash the values */ private long computeChecksum() { checksum += frameNumber; for (int i = 0; i < 4; i++) { checksum = checksum + keypressCount[i]; checksum = checksum * 3 + (isGameOver[i] ? 1 : 2); checksum = checksum * 3 + (isTerminated[i] ? 1 : 2); foreach (Keys k in keysDown[i]) checksum = checksum * 257 + (int)k; checksum = checksum * 25789 + mouseLocationX[i] * 259 + mouseLocationY[i] + 375; checksum = checksum * 3 + (mouseButton[i] ? 1 : 2); } checksum += elapsedTime; return checksum; } } //code from Prof Jensen's TestHarness // This class encapsulates inputs from the players. public class NextInputs { public List[] keysPressed; public List[] keysReleased; public int[] mouseLocationX; public int[] mouseLocationY; public bool[] mouseLocationChanged; public bool[] mousePressed; public bool[] mousePressedChanged; public NextInputs() { keysPressed = new List[4]; keysReleased = new List[4]; mouseLocationX = new int[4]; mouseLocationY = new int[4]; mouseLocationChanged = new bool[4]; mousePressed = new bool[4]; mousePressedChanged = new bool[4]; for (int i = 0; i < 4; i++) keysPressed[i] = new List(); for (int i = 0; i < 4; i++) keysReleased[i] = new List(); } } public class Game : IDeterministicGame { #region IDeterministicGame Members List mPlayers; NextInputs inputs; Object[] playerIdentifiers; Display mDisplay; Map mMap; GameState state; int thisPlayerID; public Game() { mDisplay = new Display(); mPlayers = new List(); playerIdentifiers = new Object[4]; } public void LoadContent(ContentManager contentManager) { //Texture2D everything = contentManager.Load("default"); mDisplay.LoadContent(contentManager); int currentCenterX = 5; //Creates a map like the one in Display int currentCenterY = 5; mMap = contentManager.Load("Maps/stable"); Map.DefaultTile = contentManager.Load("default"); mMap.CenterCell = new Vector2(currentCenterX, currentCenterY); } public void UnloadContent() { } private int idPlayer(Object playerIdentifier) { for (int i = 0; i < playerIdentifiers.Length; i++) if (playerIdentifiers[i] == playerIdentifier) return i; throw new Exception("Illegal player identifier" + playerIdentifier); } public Vector2 PreferredScreenSize { get { return new Vector2(800, 600); } } public int MinimumSupportedPlayers { get { return 1; } } public int MaximumSupportedPlayers { get { return 4; } } public void ResetGame(object[] PlayerIdentifiers, object thisPlayer) { // Now the test harness will at least run with less than 4 players... int numPlayers = PlayerIdentifiers.Count(); for (int i = 0; i < numPlayers; i++) this.playerIdentifiers[i] = PlayerIdentifiers[i]; // Create new game state and inputs objects. state = new GameState(); inputs = new NextInputs(); // Record 'this' player. this.thisPlayerID = idPlayer(thisPlayer); /* mPlayers.Clear(); for (int i = 0; i < PlayerIdentifiers.Length; i++) { Human player = new Human(mMap, ""); mPlayers.Add(player); mDisplay.AddCharacters(player); mPlayers.Add(player); mDisplay.AddCharacters(player); } this.playerIdentifiers = PlayerIdentifiers; for (int i = 0; i < mPlayers.Count; i++) { Point starting = mMap.GetStartingPositionForPlayer(i + 1); mPlayers[i].Spawn(new Vector2(starting.X, starting.Y)); } */ } public long CurrentFrameNumber { get { return state.frameNumber; } } public long CurrentChecksum { get { return 0; } } public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed) { //code from Prof Jensen's TestHarness int player = idPlayer(playerIdentifier); if (isKeyPressed && !inputs.keysPressed[player].Contains(key)) inputs.keysPressed[player].Add(key); if (!isKeyPressed && !inputs.keysReleased[player].Contains(key)) inputs.keysReleased[player].Add(key); } public void ApplyMouseLocationInput(object playerIdentifier, int x, int y) { } public void ApplyMouseButtonInput(object playerIdentifier, bool isButtonPressed) { } public bool IsGameOver(object playerIdentifier) { return false; } public bool IsTerminated(object playerIdentifier) { return false; } public long Update(TimeSpan elapsedTime) { state.advanceFrame(inputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state. mDisplay.Update(elapsedTime, state); inputs = new NextInputs(); // Start with inputs cleared on the next frame. //mDisplay.Update(elapsedTime); return state.frameNumber; } public long Draw(SpriteBatch spriteBatch) { mDisplay.Draw(spriteBatch); return CurrentFrameNumber; } #endregion } }