]> Dogcows Code - chaz/carfire/blob - CarFire/CarFire/CarFire/Game.cs
Seperated GameLogic from the Display
[chaz/carfire] / CarFire / CarFire / CarFire / Game.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using Microsoft.Xna.Framework;
6 using Microsoft.Xna.Framework.Content;
7 using Microsoft.Xna.Framework.Graphics;
8 using Microsoft.Xna.Framework.Input;
9
10 namespace CarFire
11 {
12 /// <summary>
13 /// Container class for the whole state of the game.
14 /// </summary>
15 public class GameState
16 {
17 #region Public Properties
18
19 public long FrameNumber { get { return mFrameNumber; } }
20
21 public long Checksum { get { return mChecksum; } }
22
23 public int NumberOfPlayers { get { return mNumberOfPlayers; } }
24
25 public Map Map;
26 public List<IEntity> Entities = new List<IEntity>();
27 public List<Projectile> mProjectiles = new List<Projectile>();
28 public Player[] mCharacters = new Player[4];
29 public Display mDisplay;
30
31 #endregion
32
33
34 #region Public Methods
35
36 /// <summary>
37 /// Construct a game state container with the number of players.
38 /// </summary>
39 /// <param name="numPlayers">Number of players.</param>
40 public GameState(int numPlayers)
41 {
42 mNumberOfPlayers = numPlayers;
43 mFrameNumber = 0;
44
45 mIsGameOver = new bool[numPlayers];
46 mIsTerminated = new bool[numPlayers];
47
48 mMouseLocation = new Point[numPlayers];
49 mMouseButton = new bool[numPlayers];
50 mKeysDown = new List<Keys>[numPlayers];
51 for (int i = 0; i < numPlayers; i++) mKeysDown[i] = new List<Keys>();
52
53 mKeypressCount = new int[numPlayers];
54 mElapsedTime = 0;
55 mChecksum = 0;
56 }
57
58
59 /// <summary>
60 /// Should be called by the Game class to advance the state
61 /// to the next frame.
62 /// </summary>
63 /// <param name="inputs">The inputs that occurred to be
64 /// applied this coming frame.</param>
65 /// <param name="milliseconds">Milliseconds; used for the checksum.</param>
66 public void AdvanceFrame(NextInputs inputs, long milliseconds)
67 {
68 mFrameNumber++;
69 mElapsedTime += milliseconds;
70
71 for (int player = 0; player < NumberOfPlayers; player++)
72 {
73 if (inputs.IsMousePressedChanged[player])
74 {
75 mMouseButton[player] = inputs.MousePressed[player];
76 }
77
78 if (inputs.IsMouseLocationChanged[player])
79 {
80 mMouseLocation[player] = inputs.MouseLocation[player];
81 }
82
83 foreach (Keys k in inputs.KeysPressed[player])
84 {
85 if (!mKeysDown[player].Contains(k))
86 {
87 mKeysDown[player].Add(k);
88 mKeypressCount[player]++;
89 }
90 }
91
92 foreach (Keys k in inputs.KeysReleased[player]) mKeysDown[player].Remove(k);
93 }
94
95 ComputeChecksum();
96 }
97
98
99 /// <summary>
100 /// Get the mouse location for a player.
101 /// </summary>
102 /// <param name="playerNum">Player Number.</param>
103 /// <returns>Mouse location.</returns>
104 public Point GetMouseLocation(int playerNum)
105 {
106 return mMouseLocation[playerNum];
107 }
108
109 /// <summary>
110 /// Get the mouse button state for a player.
111 /// </summary>
112 /// <param name="playerNum">Player number.</param>
113 /// <returns>Mouse button state..</returns>
114 public bool GetMouseButton(int playerNum)
115 {
116 return mMouseButton[playerNum];
117 }
118
119 /// <summary>
120 /// Get the keyboard state for a player.
121 /// </summary>
122 /// <param name="playerNum">Player number.</param>
123 /// <returns>Keyboard state.</returns>
124 public List<Keys> GetKeysDown(int playerNum)
125 {
126 return mKeysDown[playerNum];
127 }
128
129 #endregion
130
131
132 #region Private Methods
133
134 // Calculates a checksum for debugging network synchronization issues.
135 long ComputeChecksum()
136 {
137 mChecksum += FrameNumber;
138 for (int i = 0; i < NumberOfPlayers; i++)
139 {
140 mChecksum = mChecksum + mKeypressCount[i];
141 mChecksum = mChecksum * 3 + (mIsGameOver[i] ? 1 : 2);
142 mChecksum = mChecksum * 3 + (mIsTerminated[i] ? 1 : 2);
143 foreach (Keys k in mKeysDown[i])
144 mChecksum = mChecksum * 257 + (int)k;
145 mChecksum = mChecksum * 25789 + mMouseLocation[i].X * 259 + mMouseLocation[i].Y + 375;
146 mChecksum = mChecksum * 3 + (mMouseButton[i] ? 1 : 2);
147
148 }
149 mChecksum += mElapsedTime;
150
151 return mChecksum;
152 }
153
154 #endregion
155
156
157 #region Private Variables
158
159 int mNumberOfPlayers;
160 public Point[] mMouseLocation;
161 public bool[] mMouseButton;
162 public List<Keys>[] mKeysDown;
163
164 long mFrameNumber;
165
166 bool[] mIsGameOver;
167 bool[] mIsTerminated;
168
169 int[] mKeypressCount;
170 long mElapsedTime;
171 long mChecksum;
172
173 #endregion
174 }
175
176 /// <summary>
177 /// Container class for all the inputs for a single frame.
178 /// </summary>
179 public class NextInputs
180 {
181 public List<Keys>[] KeysPressed;
182 public List<Keys>[] KeysReleased;
183 public Point[] MouseLocation;
184 public bool[] IsMouseLocationChanged;
185 public bool[] MousePressed;
186 public bool[] IsMousePressedChanged;
187
188 public NextInputs(int numPlayers)
189 {
190 KeysPressed = new List<Keys>[numPlayers];
191 KeysReleased = new List<Keys>[numPlayers];
192 IsMouseLocationChanged = new bool[numPlayers];
193 MousePressed = new bool[numPlayers];
194 IsMousePressedChanged = new bool[numPlayers];
195 for (int i = 0; i < numPlayers; i++) KeysPressed[i] = new List<Keys>();
196 for (int i = 0; i < numPlayers; i++) KeysReleased[i] = new List<Keys>();
197 }
198 }
199
200
201 /// <summary>
202 /// The big kahuna.
203 /// </summary>
204 public class Game : IDeterministicGame
205 {
206 #region Public Properties
207
208 /// <summary>
209 /// Get the content manager associated with this game.
210 /// </summary>
211 public ContentManager ContentManager { get { return mContentManager; } }
212
213 /// <summary>
214 /// Get the state.
215 /// </summary>
216 public GameState State;
217
218 public bool[,] Grid
219 {
220 get
221 {
222 bool[,] grid = State.Map.Grid;
223 foreach (IEntity entity in State.Entities)
224 {
225 Point coordinates = entity.Coordinates;
226 grid[coordinates.X, coordinates.Y] = true;
227 }
228 return grid;
229 }
230 }
231
232 #endregion
233
234
235 #region Public Methods
236 public bool IsCellOpen(Point point)
237 {
238 if (!State.Map.IsCellOpen(point)) return false;
239 foreach (IEntity entity in State.Entities)
240 {
241 if (entity.Coordinates == point) return false;
242 }
243 return true;
244 }
245
246 public Game()
247 {
248
249 }
250 /// <summary>
251 /// This method should be called whenever the players want to move to a new map.
252 /// Not implemented yet. Need some way to get next map.
253 /// </summary>
254 public void startNewMap()
255 {
256 //TODO somehow get next map
257 State.Entities.Clear();
258 //State.Map = State.Map.getNextMap();
259 for (int i = 0; i < State.mCharacters.Length; i++)
260 {
261 State.mCharacters[i].Coordinates = State.Map.GetStartingPositionForPlayer(i + 1);
262 }
263 State.Entities = State.Map.GetAllEntities();
264 }
265 public void LoadContent(ContentManager contentManager)
266 {
267 mContentManager = contentManager;
268 menu = mContentManager.Load<SpriteFont>("menuFont");
269
270 }
271
272 public void UnloadContent()
273 {
274 }
275
276 private int GetPlayerNumber(Object playerIdentifier)
277 {
278 for (int i = 0; i < mPlayerIdentifiers.Length; i++)
279 {
280 if (mPlayerIdentifiers[i] == playerIdentifier) return i;
281 }
282 throw new Exception("Illegal player identifier" + playerIdentifier);
283 }
284
285 public Vector2 PreferredScreenSize
286 {
287 get { return new Vector2(800, 600); }
288 }
289
290 public int MinimumSupportedPlayers
291 {
292 get { return 1; }
293 }
294
295 public int MaximumSupportedPlayers
296 {
297 get { return 4; }
298 }
299
300 public void ResetGame(object[] playerIdentifiers, object thisPlayer)
301 {
302 int numPlayers = playerIdentifiers.Count();
303
304 mPlayerIdentifiers = new object[numPlayers];
305 for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i];
306
307 mThisPlayerID = GetPlayerNumber(thisPlayer);
308
309 State = new GameState(numPlayers);
310 mInputs = new NextInputs(numPlayers);
311 State.mDisplay = new Display(this);
312 State.mDisplay.LoadContent(mContentManager);
313
314 State.Map = mContentManager.Load<Map>("Maps/stable");
315 State.Map.Game = this;
316 State.Entities = State.Map.GetAllEntities();
317 Map.DefaultTile = mContentManager.Load<Texture2D>("default");
318
319 /*
320 mPlayers.Clear();
321 for (int i = 0; i < PlayerIdentifiers.Length; i++)
322 {
323 Human player = new Human(mMap, "");
324 mPlayers.Add(player);
325 mDisplay.AddCharacters(player);
326 mPlayers.Add(player);
327 mDisplay.AddCharacters(player);
328 }
329 this.playerIdentifiers = PlayerIdentifiers;
330 for (int i = 0; i < mPlayers.Count; i++)
331 {
332 Point starting = mMap.GetStartingPositionForPlayer(i + 1);
333 mPlayers[i].Spawn(new Vector2(starting.X, starting.Y));
334 }
335 */
336 }
337
338 public long CurrentFrameNumber
339 {
340 get { return State.FrameNumber; }
341 }
342
343 public long CurrentChecksum
344 {
345 get { return 0; }
346 }
347
348 public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed)
349 {
350 //code from Prof Jensen's TestHarness
351 int player = GetPlayerNumber(playerIdentifier);
352
353 if (isKeyPressed && !mInputs.KeysPressed[player].Contains(key))
354 mInputs.KeysPressed[player].Add(key);
355
356 if (!isKeyPressed && !mInputs.KeysReleased[player].Contains(key))
357 mInputs.KeysReleased[player].Add(key);
358
359 }
360
361 public void ApplyMouseLocationInput(object playerIdentifier, int x, int y)
362 {
363
364 }
365
366 public void ApplyMouseButtonInput(object playerIdentifier, bool isButtonPressed)
367 {
368
369 }
370
371 public bool IsGameOver(object playerIdentifier)
372 {
373 return false;
374 }
375
376 public bool IsTerminated(object playerIdentifier)
377 {
378 return false;
379 }
380
381 public long Update(TimeSpan elapsedTime)
382 {
383 State.AdvanceFrame(mInputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.
384 State.mDisplay.Update(elapsedTime, mThisPlayerID);
385 State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); });
386 mInputs = new NextInputs(State.NumberOfPlayers); // Start with inputs cleared on the next frame.
387 //mDisplay.Update(elapsedTime);
388 return State.FrameNumber;
389
390 }
391
392 public long Draw(SpriteBatch spriteBatch)
393 {
394 bool allCharactersSelected = true;
395 for (int i = 0; i < State.NumberOfPlayers; i++)
396 {
397 //If player has not selected a player yet let them select one.
398 if (State.mCharacters[i] == null)
399 {
400 allCharactersSelected = false;
401 if (State.GetKeysDown(i).Contains(Keys.M))
402 {
403 State.mCharacters[i] = new Melee(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
404 State.mCharacters[i].LoadContent(mContentManager);
405 }
406 else if (State.GetKeysDown(i).Contains(Keys.R))
407 {
408 State.mCharacters[i] = new Ranged(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
409 State.mCharacters[i].LoadContent(mContentManager);
410 }
411 }
412 }
413 if (allCharactersSelected)
414 {
415
416 State.mDisplay.Draw(spriteBatch);
417 }
418 else
419 {
420 spriteBatch.GraphicsDevice.Clear(Color.Black);
421 spriteBatch.DrawString(menu, "Press R to select a Ranged Character and M to select a Melee Character", new Vector2(30, 30), Color.RosyBrown);
422 }
423 return CurrentFrameNumber;
424 }
425
426 #endregion
427
428
429 #region Private Variables
430
431 SpriteFont menu;
432
433 ContentManager mContentManager;
434 NextInputs mInputs;
435
436 Object[] mPlayerIdentifiers;
437 int mThisPlayerID;
438
439 #endregion
440 }
441 }
This page took 0.053501 seconds and 4 git commands to generate.