56507110fac10ba1c10502be051f1cf11545dc1f
[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 private const int hitMonsterScore = 20;
19 private const int killMonsterScore = 100;
20 public int HitMonsterScore { get { return hitMonsterScore; } }
21 public int KillMonsterScore { get { return killMonsterScore; } }
22
23 public long FrameNumber { get { return mFrameNumber; } }
24
25 public long Checksum { get { return mChecksum; } }
26
27 public int NumberOfPlayers { get { return mNumberOfPlayers; } }
28
29 public Map Map;
30 public List<IEntity> Entities = new List<IEntity>();
31 public List<Projectile> mProjectiles = new List<Projectile>();
32 public Player[] mCharacters;
33 public Display mDisplay;
34 public AI AIData;
35 #endregion
36
37
38 #region Public Methods
39
40 /// <summary>
41 /// Construct a game state container with the number of players.
42 /// </summary>
43 /// <param name="numPlayers">Number of players.</param>
44 public GameState(int numPlayers)
45 {
46 mNumberOfPlayers = numPlayers;
47 mFrameNumber = 0;
48
49 mCharacters = new Player[numPlayers];
50
51 mIsGameOver = new bool[numPlayers];
52 mIsTerminated = new bool[numPlayers];
53
54 mMouseLocation = new Point[numPlayers];
55 mMouseButton = new bool[numPlayers];
56 mKeysDown = new List<Keys>[numPlayers];
57 for (int i = 0; i < numPlayers; i++) mKeysDown[i] = new List<Keys>();
58
59 mKeypressCount = new int[numPlayers];
60 mElapsedTime = 0;
61 mChecksum = 0;
62 }
63
64
65 /// <summary>
66 /// Should be called by the Game class to advance the state
67 /// to the next frame.
68 /// </summary>
69 /// <param name="inputs">The inputs that occurred to be
70 /// applied this coming frame.</param>
71 /// <param name="milliseconds">Milliseconds; used for the checksum.</param>
72 public void AdvanceFrame(NextInputs inputs, long milliseconds)
73 {
74 mFrameNumber++;
75 mElapsedTime += milliseconds;
76
77 for (int player = 0; player < NumberOfPlayers; player++)
78 {
79 if (inputs.IsMousePressedChanged[player])
80 {
81 mMouseButton[player] = inputs.MousePressed[player];
82 }
83
84 if (inputs.IsMouseLocationChanged[player])
85 {
86 mMouseLocation[player] = inputs.MouseLocation[player];
87 }
88
89 foreach (Keys k in inputs.KeysPressed[player])
90 {
91 if (!mKeysDown[player].Contains(k))
92 {
93 mKeysDown[player].Add(k);
94 mKeypressCount[player]++;
95 }
96 }
97
98 foreach (Keys k in inputs.KeysReleased[player]) mKeysDown[player].Remove(k);
99 }
100
101 ComputeChecksum();
102 }
103
104
105 /// <summary>
106 /// Get the mouse location for a player.
107 /// </summary>
108 /// <param name="playerNum">Player Number.</param>
109 /// <returns>Mouse location.</returns>
110 public Point GetMouseLocation(int playerNum)
111 {
112 return mMouseLocation[playerNum];
113 }
114
115 /// <summary>
116 /// Get the mouse button state for a player.
117 /// </summary>
118 /// <param name="playerNum">Player number.</param>
119 /// <returns>Mouse button state..</returns>
120 public bool GetMouseButton(int playerNum)
121 {
122 return mMouseButton[playerNum];
123 }
124
125 /// <summary>
126 /// Get the keyboard state for a player.
127 /// </summary>
128 /// <param name="playerNum">Player number.</param>
129 /// <returns>Keyboard state.</returns>
130 public List<Keys> GetKeysDown(int playerNum)
131 {
132 return mKeysDown[playerNum];
133 }
134
135 #endregion
136
137
138 #region Private Methods
139
140 // Calculates a checksum for debugging network synchronization issues.
141 long ComputeChecksum()
142 {
143 mChecksum += FrameNumber;
144 for (int i = 0; i < NumberOfPlayers; i++)
145 {
146 mChecksum = mChecksum + mKeypressCount[i];
147 mChecksum = mChecksum * 3 + (mIsGameOver[i] ? 1 : 2);
148 mChecksum = mChecksum * 3 + (mIsTerminated[i] ? 1 : 2);
149 foreach (Keys k in mKeysDown[i])
150 mChecksum = mChecksum * 257 + (int)k;
151 mChecksum = mChecksum * 25789 + mMouseLocation[i].X * 259 + mMouseLocation[i].Y + 375;
152 mChecksum = mChecksum * 3 + (mMouseButton[i] ? 1 : 2);
153
154 }
155 mChecksum += mElapsedTime;
156
157 return mChecksum;
158 }
159
160 #endregion
161
162
163 #region Private Variables
164
165 int mNumberOfPlayers;
166 public Point[] mMouseLocation;
167 public bool[] mMouseButton;
168 public List<Keys>[] mKeysDown;
169
170 long mFrameNumber;
171
172 bool[] mIsGameOver;
173 bool[] mIsTerminated;
174
175 int[] mKeypressCount;
176 long mElapsedTime;
177 long mChecksum;
178
179 #endregion
180 }
181
182 /// <summary>
183 /// Container class for all the inputs for a single frame.
184 /// </summary>
185 public class NextInputs
186 {
187 public List<Keys>[] KeysPressed;
188 public List<Keys>[] KeysReleased;
189 public Point[] MouseLocation;
190 public bool[] IsMouseLocationChanged;
191 public bool[] MousePressed;
192 public bool[] IsMousePressedChanged;
193
194 public NextInputs(int numPlayers)
195 {
196 KeysPressed = new List<Keys>[numPlayers];
197 KeysReleased = new List<Keys>[numPlayers];
198 IsMouseLocationChanged = new bool[numPlayers];
199 MousePressed = new bool[numPlayers];
200 IsMousePressedChanged = new bool[numPlayers];
201 for (int i = 0; i < numPlayers; i++) KeysPressed[i] = new List<Keys>();
202 for (int i = 0; i < numPlayers; i++) KeysReleased[i] = new List<Keys>();
203 }
204 }
205
206
207 /// <summary>
208 /// The big kahuna.
209 /// </summary>
210 public class Game : IDeterministicGame
211 {
212 #region Public Properties
213
214 /// <summary>
215 /// Get the content manager associated with this game.
216 /// </summary>
217 public ContentManager ContentManager { get { return mContentManager; } }
218
219 /// <summary>
220 /// Get the state.
221 /// </summary>
222 public GameState State;
223
224 public bool[,] Grid
225 {
226 get
227 {
228 bool[,] grid = (bool[,])State.Map.Grid.Clone();
229 foreach (IEntity entity in State.Entities)
230 {
231 Point coordinates = entity.Coordinates;
232 grid[coordinates.X, coordinates.Y] = false;
233 }
234 foreach (Player player in State.mCharacters)
235 {
236 if (player == null) continue;
237 Point coordinates = player.Coordinates;
238 grid[coordinates.X, coordinates.Y] = false;
239 }
240 return grid;
241 }
242 }
243
244 #endregion
245
246
247 #region Public Methods
248
249 /// <summary>
250 /// Get an entity at a certain place on the map.
251 /// </summary>
252 /// <param name="point">The coordinates.</param>
253 /// <returns>The entity, or null if none is at that location.</returns>
254 public IEntity GetEntityAtCoordinates(Point point)
255 {
256 foreach (IEntity entity in State.Entities)
257 {
258 if (entity.Coordinates == point) return entity;
259 }
260 return null;
261 }
262
263 /// <summary>
264 /// Get a player at a certain place on the map.
265 /// </summary>
266 /// <param name="point">The coordinates.</param>
267 /// <returns>The player, or null if none is at that location.</returns>
268 public Player GetPlayerAtCoordinates(Point point)
269 {
270 foreach (Player player in State.mCharacters)
271 {
272 if (player != null && player.Coordinates == point) return player;
273 }
274 return null;
275 }
276
277 /// <summary>
278 /// Determine if a cell is open, depending on the static scenery
279 /// of the map and if there are any collidable entities.
280 /// </summary>
281 /// <param name="point">The coordinates.</param>
282 /// <returns>True if the cell is open; false otherwise.</returns>
283 public bool IsCellOpen(Point point)
284 {
285 if (!State.Map.IsCellOpen(point)) return false;
286 IEntity entity = GetEntityAtCoordinates(point);
287 if (entity != null && entity.IsCollidable) return false;
288 Player player = GetPlayerAtCoordinates(point);
289 if (player != null) return false;
290 return true;
291 }
292
293 /// <summary>
294 /// Remove a specific entity from the game. The entity can still
295 /// be tracked some other way, but it won't included when the game is
296 /// updating and drawing stuff.
297 /// </summary>
298 /// <param name="entity">The entity.</param>
299 /// <returns>The entity that was removed, or null if no entity was removed.</returns>
300 public IEntity RemoveEntity(IEntity entity)
301 {
302 if (State.Entities.Remove(entity)) return entity;
303 return null;
304 }
305
306 /// <summary>
307 /// Move on to the next map, and advance the level.
308 /// </summary>
309 public void AdvanceLevel()
310 {
311 // TODO: Load the next map, etc...
312 }
313
314 /// <summary>
315 /// Restart the current level.
316 /// </summary>
317 public void Reset()
318 {
319 State.Map.Reset();
320 // TODO: Do other stuff to reset everything.
321 }
322
323
324 public Game()
325 {
326
327 }
328 /// <summary>
329 /// This method should be called whenever the players want to move to a new map.
330 /// Not implemented yet. Need some way to get next map.
331 /// </summary>
332 public void startNewMap()
333 {
334 //TODO somehow get next map
335 State.Entities.Clear();
336 //State.Map = State.Map.getNextMap();
337 for (int i = 0; i < State.mCharacters.Length; i++)
338 {
339 State.mCharacters[i].Coordinates = State.Map.GetStartingPositionForPlayer(i + 1);
340 }
341 State.Entities = State.Map.GetAllEntities(this);
342 }
343 public void LoadContent(ContentManager contentManager)
344 {
345 mContentManager = contentManager;
346 menu = mContentManager.Load<SpriteFont>("menuFont");
347
348 }
349
350 public void UnloadContent()
351 {
352 }
353
354 private int GetPlayerNumber(Object playerIdentifier)
355 {
356 for (int i = 0; i < mPlayerIdentifiers.Length; i++)
357 {
358 if (mPlayerIdentifiers[i] == playerIdentifier) return i;
359 }
360 throw new Exception("Illegal player identifier" + playerIdentifier);
361 }
362
363 public Vector2 PreferredScreenSize
364 {
365 get { return new Vector2(800, 600); }
366 }
367
368 public int MinimumSupportedPlayers
369 {
370 get { return 1; }
371 }
372
373 public int MaximumSupportedPlayers
374 {
375 get { return 4; }
376 }
377
378 public void ResetGame(object[] playerIdentifiers, object thisPlayer)
379 {
380 int numPlayers = playerIdentifiers.Count();
381
382 mPlayerIdentifiers = new object[numPlayers];
383 for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i];
384
385 mThisPlayerID = GetPlayerNumber(thisPlayer);
386
387 State = new GameState(numPlayers);
388 mInputs = new NextInputs(numPlayers);
389 State.mDisplay = new Display(this);
390 State.mDisplay.LoadContent(mContentManager);
391
392 // Load the tilemap.
393 Texture2D mapTiles = mContentManager.Load<Texture2D>("graphics/wallAndFloorTilesNoEdgeScale");
394 Tilemap tilemap = new Tilemap(mapTiles, 10, 7);
395 tilemap.SetTile('`', new Point(0, 2), TileFlags.Closed | TileFlags.Wall);
396 tilemap.SetTile('~', new Point(1, 2), TileFlags.Closed | TileFlags.Wall);
397 tilemap.SetTile('!', new Point(2, 2), TileFlags.Closed | TileFlags.Wall);
398 tilemap.SetTile('@', new Point(3, 2), TileFlags.Closed | TileFlags.Wall);
399 tilemap.SetTile('#', new Point(4, 2), TileFlags.Closed | TileFlags.Wall);
400 tilemap.SetTile('$', new Point(5, 2), TileFlags.Closed | TileFlags.Wall);
401 tilemap.SetTile('%', new Point(6, 2), TileFlags.Closed | TileFlags.Wall);
402 tilemap.SetTile('^', new Point(8, 2), TileFlags.Closed | TileFlags.Wall);
403 tilemap.SetTile('&', new Point(9, 2), TileFlags.Closed | TileFlags.Wall);
404 tilemap.SetTile('*', new Point(0, 3), TileFlags.Closed | TileFlags.Wall);
405 tilemap.SetTile('(', new Point(1, 3), TileFlags.Closed | TileFlags.Wall);
406 tilemap.SetTile(')', new Point(2, 3), TileFlags.Closed | TileFlags.Wall);
407 tilemap.SetTile('-', new Point(3, 3), TileFlags.Closed | TileFlags.Wall);
408 tilemap.SetTile('=', new Point(4, 3), TileFlags.Closed | TileFlags.Wall);
409 tilemap.SetTile('_', new Point(5, 3), TileFlags.Closed | TileFlags.Wall);
410 tilemap.SetTile('+', new Point(6, 3), TileFlags.Closed | TileFlags.Wall);
411 tilemap.SetTile('|', new Point(8, 3), TileFlags.Closed | TileFlags.Wall);
412 tilemap.SetTile('[', new Point(0, 4), TileFlags.Default);
413 tilemap.SetTile(']', new Point(1, 4), TileFlags.Default);
414 tilemap.SetTile('{', new Point(2, 4), TileFlags.Default);
415 tilemap.SetTile('}', new Point(3, 4), TileFlags.Default);
416 tilemap.SetTile('?', new Point(4, 4), TileFlags.Default);
417 tilemap.SetTile(',', new Point(7, 4), TileFlags.Default);
418 tilemap.SetTile('.', new Point(8, 4), TileFlags.Default);
419 tilemap.SetTile('\\', new Point(9, 4), TileFlags.Default);
420 tilemap.SetTile(';', new Point(0, 5), TileFlags.Default);
421 tilemap.SetTile(':', new Point(1, 5), TileFlags.Default);
422 tilemap.SetTile('\'', new Point(2, 5), TileFlags.Default);
423 tilemap.SetTile('"', new Point(3, 5), TileFlags.Default);
424 tilemap.SetTile(' ', new Point(4, 5), TileFlags.Default);
425 tilemap.SetTile('<', new Point(7, 5), TileFlags.Default);
426 tilemap.SetTile('>', new Point(8, 5), TileFlags.Default);
427 tilemap.SetTile('/', new Point(9, 5), TileFlags.Default);
428 Map.Tilemap = tilemap;
429
430 // Load the first map.
431 State.Map = mContentManager.Load<Map>("Maps/colosseum");
432 State.Entities = State.Map.GetAllEntities(this);
433
434 //State.AIData = new AI(this);
435
436 /*
437 mPlayers.Clear();
438 for (int i = 0; i < PlayerIdentifiers.Length; i++)
439 {
440 Human player = new Human(mMap, "");
441 mPlayers.Add(player);
442 mDisplay.AddCharacters(player);
443 mPlayers.Add(player);
444 mDisplay.AddCharacters(player);
445 }
446 this.playerIdentifiers = PlayerIdentifiers;
447 for (int i = 0; i < mPlayers.Count; i++)
448 {
449 Point starting = mMap.GetStartingPositionForPlayer(i + 1);
450 mPlayers[i].Spawn(new Vector2(starting.X, starting.Y));
451 }
452 */
453 }
454
455 public long CurrentFrameNumber
456 {
457 get { return State.FrameNumber; }
458 }
459
460 public long CurrentChecksum
461 {
462 get { return 0; }
463 }
464
465 public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed)
466 {
467 //code from Prof Jensen's TestHarness
468 int player = GetPlayerNumber(playerIdentifier);
469
470 if (isKeyPressed && !mInputs.KeysPressed[player].Contains(key))
471 mInputs.KeysPressed[player].Add(key);
472
473 if (!isKeyPressed && !mInputs.KeysReleased[player].Contains(key))
474 mInputs.KeysReleased[player].Add(key);
475
476 }
477
478 public void ApplyMouseLocationInput(object playerIdentifier, int x, int y)
479 {
480
481 }
482
483 public void ApplyMouseButtonInput(object playerIdentifier, bool isButtonPressed)
484 {
485
486 }
487
488 public bool IsGameOver(object playerIdentifier)
489 {
490 return false;
491 }
492
493 public bool IsTerminated(object playerIdentifier)
494 {
495 return false;
496 }
497
498 public long Update(TimeSpan elapsedTime)
499 {
500 State.AdvanceFrame(mInputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.
501 State.mDisplay.Update(elapsedTime, mThisPlayerID);
502 State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); });
503 mInputs = new NextInputs(State.NumberOfPlayers); // Start with inputs cleared on the next frame.
504 //mDisplay.Update(elapsedTime);
505 return State.FrameNumber;
506
507 }
508
509 public long Draw(SpriteBatch spriteBatch)
510 {
511 bool allCharactersSelected = true;
512 for (int i = 0; i < State.NumberOfPlayers; i++)
513 {
514 //If player has not selected a player yet let them select one.
515 if (State.mCharacters[i] == null)
516 {
517 allCharactersSelected = false;
518 if (State.GetKeysDown(i).Contains(Keys.M))
519 {
520 State.mCharacters[i] = new Melee(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
521 State.mCharacters[i].LoadContent(mContentManager);
522 }
523 else if (State.GetKeysDown(i).Contains(Keys.R))
524 {
525 State.mCharacters[i] = new Ranged(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
526 State.mCharacters[i].LoadContent(mContentManager);
527 }
528 }
529 }
530 if (allCharactersSelected)
531 {
532
533 State.mDisplay.Draw(spriteBatch);
534 }
535 else
536 {
537 spriteBatch.GraphicsDevice.Clear(Color.Black);
538 spriteBatch.DrawString(menu, "Press R to select a Ranged Character and M to select a Melee Character", new Vector2(30, 30), Color.RosyBrown);
539 }
540 return CurrentFrameNumber;
541 }
542
543 #endregion
544
545
546 #region Private Variables
547
548 SpriteFont menu;
549
550 ContentManager mContentManager;
551 NextInputs mInputs;
552
553 Object[] mPlayerIdentifiers;
554 int mThisPlayerID;
555
556 #endregion
557 }
558 }
This page took 0.072555 seconds and 3 git commands to generate.