PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/game/Main.java

https://github.com/kflorence/pathfinding-java
Java | 534 lines | 278 code | 96 blank | 160 comment | 22 complexity | 15b516f3f01909253d34a275acc87b5a MD5 | raw file
  1. package game;
  2. import java.awt.Color;
  3. import java.awt.Font;
  4. import java.awt.FontMetrics;
  5. import java.awt.Frame;
  6. import java.awt.Graphics2D;
  7. import java.awt.GraphicsConfiguration;
  8. import java.awt.GraphicsEnvironment;
  9. import java.awt.event.KeyListener;
  10. import java.awt.event.MouseEvent;
  11. import java.awt.event.MouseListener;
  12. import java.awt.event.WindowEvent;
  13. import java.awt.event.WindowListener;
  14. import java.awt.image.BufferStrategy;
  15. import java.util.ArrayList;
  16. import game.map.*;
  17. import game.entities.*;
  18. public class Main implements WindowListener, MouseListener, KeyListener
  19. {
  20. private static final long serialVersionUID = -8882280247883036030L;
  21. /**
  22. *
  23. * DEBUG AND TESTING VARIABLES
  24. *
  25. **/
  26. // Number of entities in our game (will be dynamic later)
  27. private static int entityCount = 1;
  28. // Screen refresh information
  29. private long timeElapsed;
  30. private long frameDelay;
  31. private int frameCount;
  32. private int framesPerSecond;
  33. // The list of places the user has clicked, for grid redrawing
  34. private static ArrayList<Cell> clickList = new ArrayList<Cell>();
  35. /**
  36. *
  37. * PERMANENT VARIABLES
  38. *
  39. **/
  40. // Our single eference to this class
  41. private static Main game;
  42. // The title of the game
  43. public static final String GAMETITLE = "jUntitled";
  44. // The width and height of the game window
  45. public static final int WIDTH = 800;
  46. public static final int HEIGHT = 600;
  47. // Variables for the window environment
  48. private static Frame frame;
  49. // Game States
  50. private static final int MENU = 0;
  51. private static final int ABOUT = 1;
  52. private static final int SCORES = 2;
  53. private static final int PLAY = 3;
  54. private static final int GAMEOVER = 4;
  55. // Frame delay rates (milliseconds)
  56. private static final int DELAY = 10;
  57. private static final int DEBUGDELAY = 10;
  58. // Lives and rounds
  59. //private static final int LIVES = 5;
  60. //private static final int ROUNDS = 25;
  61. // Variables related to the game environment
  62. private static Map map;
  63. private static Graphics2D g;
  64. private static BufferStrategy strategy;
  65. // Entity list for keeping track of the entities in the game
  66. private static ArrayList<Entity> entityList = new ArrayList<Entity>();
  67. private static ArrayList<Entity> removeList = new ArrayList<Entity>();
  68. // Retrieve a graphics configuration according to the computer environment
  69. private static GraphicsConfiguration gc =
  70. GraphicsEnvironment.getLocalGraphicsEnvironment().
  71. getDefaultScreenDevice().getDefaultConfiguration();
  72. // Variables relating to the state of the game
  73. private static int gameState = MENU;
  74. private static boolean gameWaiting = true;
  75. private static boolean gameRunning = true;
  76. private static boolean gamePaused = true;
  77. private static boolean gameDebug = false;
  78. private static boolean gameKeyLock = false;
  79. // Font Stuffs
  80. Font font = new Font("Arial", Font.PLAIN, 12);
  81. FontMetrics fm = frame.getFontMetrics(font);
  82. int fontWidth = fm.getMaxAdvance();
  83. int fontHeight = fm.getHeight();
  84. // Create game window, initialize game variables, etc...
  85. public Main()
  86. {
  87. // Create Frame
  88. frame = new Frame();
  89. frame.addWindowListener(this);
  90. // We are handling repaint's, not AWT
  91. setIgnoreRepaint(true);
  92. // Finalize Frame properties, then set visible
  93. frame.pack();
  94. frame.setResizable(false);
  95. frame.setVisible(true);
  96. // Create and retain focus for keyEvents
  97. addKeyListener(this);
  98. requestFocus();
  99. // Create mouse listener for mouseEvents
  100. addMouseListener(this);
  101. // Create buffer strategy for off-screen accelerated graphics
  102. createBufferStrategy(2);
  103. strategy = getBufferStrategy();
  104. // Finally, initialize game
  105. initialize();
  106. }
  107. /**
  108. *
  109. * Private functions
  110. *
  111. **/
  112. // Initializes the game
  113. private void initialize()
  114. {
  115. // TODO: this is where most of the initial loading/parsing will take place
  116. // - load resource file (links to images, sounds and files)
  117. // - load map file (grid size, node information) * passed to Map
  118. // - load entity file (entity images, states and other information)
  119. // New Map (20x20) with cell size of 20
  120. map = new Map(20, 20, 25);
  121. }
  122. // The bread and butter of Main, this is the games infinite loop.
  123. private void loop()
  124. {
  125. String s;
  126. long lastLoopTime = System.nanoTime();
  127. // The main game loop
  128. while (gameRunning)
  129. {
  130. // The elapsed time between now and the last loop, for movement purposes
  131. long delta = System.nanoTime() - lastLoopTime;
  132. lastLoopTime = System.nanoTime();
  133. // Blank graphics context for the accelerated graphics
  134. g = (Graphics2D) strategy.getDrawGraphics();
  135. g.setColor(new Color(50, 50, 50));
  136. g.fillRect(0, 0, WIDTH, HEIGHT);
  137. // Game state handler
  138. switch(gameState)
  139. {
  140. // The user is playing the game
  141. case PLAY:
  142. // Does the grid need to be redrawn?
  143. if (!clickList.isEmpty())
  144. {
  145. // Loop through clicks and toggle the cells
  146. for (Cell cell : clickList) cell.togglePlayable();
  147. // Redraw the grid
  148. Map.draw();
  149. // Clear the clickList
  150. clickList.clear();
  151. }
  152. // Grab the grid's image
  153. g.setClip(Map.getClip());
  154. g.drawImage(Map.getImage(), 0, 0, null);
  155. g.setClip(0, 0, WIDTH, HEIGHT);
  156. // Update frameCount and elapsed time
  157. frameCount++;
  158. timeElapsed += delta;
  159. // If a second has passed...
  160. if (timeElapsed >= 1000000000)
  161. {
  162. // Set our new FPS
  163. framesPerSecond = frameCount;
  164. // Reset our variables
  165. frameCount = 0;
  166. timeElapsed = 0;
  167. }
  168. // Display FPS
  169. g.setColor(Color.white);
  170. s = "Frame Delay: " + frameDelay + " (FPS: " + framesPerSecond + ")";
  171. g.drawString(s, WIDTH - (fm.stringWidth(s)) - 10, 20);
  172. // The game is paused
  173. if (gamePaused)
  174. {
  175. // Display notification
  176. g.setColor(Color.white);
  177. s = "The game is paused.";
  178. g.drawString(s, 10, 20);
  179. }
  180. // Waiting for next round
  181. else if (gameWaiting)
  182. {
  183. // Display notification
  184. g.setColor(Color.white);
  185. s = "Press SPACEBAR to start the next round.";
  186. g.drawString(s, 10, 20);
  187. }
  188. // Update entity position, draw it, and update it's logic for the next loop
  189. for (Entity entity : entityList)
  190. {
  191. // Make sure the game isn't paused
  192. if (!isPaused() && !isWaiting())
  193. {
  194. // If it's a logical entity, update it's logic
  195. if (entity.isLogical()) entity.doLogic();
  196. // If it's an animated entity, update it's animation
  197. if (entity instanceof AnimatedEntity) entity.update(delta);
  198. // If it's a moveable entity, update it's movement
  199. if (entity instanceof MovableEntity) entity.move(delta);
  200. }
  201. // If the game is in debug mode...
  202. if (inDebugMode())
  203. {
  204. // Set this entity's color
  205. g.setColor(entity.getColor());
  206. // Draw this entity's bounding box
  207. g.fill(entity.getRectangle());
  208. }
  209. // Draw the entity on screen
  210. entity.draw(g);
  211. }
  212. // Do we need to remove any entities?
  213. if (!removeList.isEmpty())
  214. {
  215. // Remove any entities that have been marked for deletion
  216. entityList.removeAll(removeList);
  217. // Clear the remove list
  218. removeList.clear();
  219. }
  220. // Populate our entityList if it's empty
  221. if (entityList.isEmpty())
  222. {
  223. // The round has ended, wait for key press to start next round
  224. gameWaiting = true;
  225. // Create the entities for the next round
  226. // This number will be dynamic later, as well as their placement positions
  227. for (int i = 0; i < entityCount; i++)
  228. {
  229. entityList.add(
  230. new AlienEntity(
  231. new Point(6 + i, 1),
  232. new Point(6 + i, 20)
  233. )
  234. );
  235. }
  236. //entityCount++;
  237. }
  238. break;
  239. // Main menu
  240. case MENU:
  241. g.setColor(Color.white);
  242. s = "Menu will be here soon. Press 'S' to start.";
  243. g.drawString(s, 10, 20);
  244. break;
  245. // About section
  246. case ABOUT:
  247. g.setColor(Color.white);
  248. s = "About: Game development by Kyle Florence.";
  249. g.drawString(s, 10, 20);
  250. break;
  251. // High scores section
  252. case SCORES:
  253. g.setColor(Color.white);
  254. s = "Someday, there will be high scores here.";
  255. g.drawString(s, 10, 20);
  256. break;
  257. // Game over, player has no more lives left
  258. case GAMEOVER:
  259. break;
  260. }
  261. // Finished drawing, display graphics context
  262. g.dispose();
  263. strategy.show();
  264. try {
  265. /*
  266. * Each frame is shown for 10 milliseconds. This is to give the
  267. * game some leeway in running through the loop process. That
  268. * way our animation stays smooth instead of getting choppy when
  269. * certain loops take longer than others. So, in order to know
  270. * how long we have left to wait we calculate the time of the last
  271. * loop plus 10 milliseconds, then subtract the time now and we
  272. * are left with our answer.
  273. */
  274. frameDelay = ((lastLoopTime + (gameDebug ? DEBUGDELAY : DELAY) * 1000000 - System.nanoTime()) / 1000000);
  275. // Sleep for specified time
  276. Thread.sleep(frameDelay);
  277. }
  278. // Thread could not sleep
  279. catch (Exception e) {
  280. //System.out.println("the main loop has insomnia.");
  281. }
  282. }
  283. }
  284. // Toggle waiting state
  285. private static void toggleWait() {
  286. gameWaiting = !gameWaiting;
  287. }
  288. // Toggle debug mode
  289. private static void toggleDebug() {
  290. gameDebug = !gameDebug;
  291. }
  292. // Toggle paused mode
  293. private static void togglePause() {
  294. gamePaused = !gamePaused;
  295. }
  296. /**
  297. *
  298. * Public functions
  299. *
  300. */
  301. // This function is called when the JAR is opened
  302. public static void main(String[] args)
  303. {
  304. // Call constructor
  305. game = new Main();
  306. // Start up the game loop
  307. game.loop();
  308. }
  309. // FOR DEBUG
  310. // Returns the number of the most recent entity in entityList
  311. public static int entityNumber() {
  312. return entityList.size() + 1;
  313. }
  314. // Returns the list of entities
  315. public static ArrayList<Entity> getEntities() {
  316. return entityList;
  317. }
  318. // Returns the game's graphics configuration context
  319. public static GraphicsConfiguration getGC() {
  320. return gc;
  321. }
  322. // Returns a reference to the Map class
  323. public static Map getMap() {
  324. return map;
  325. }
  326. // Whether or not the game is in the waiting state
  327. public static boolean isWaiting() {
  328. return gameWaiting;
  329. }
  330. // Whether or not we are in debug mode
  331. public static boolean inDebugMode() {
  332. return gameDebug;
  333. }
  334. // Whether or not the game is paused
  335. public static boolean isPaused() {
  336. return gamePaused;
  337. }
  338. // Remove an entity from the game
  339. public static void removeEntity(Entity entity)
  340. {
  341. // Mark this entity for deletion
  342. removeList.add(entity);
  343. }
  344. /**
  345. * This section contains the implementation of the WindowListener
  346. * class (abstract overrides). This controls aspects of the window
  347. * such as closing, opening, and minimizing.
  348. **/
  349. // Perhaps move Listeners to another file someday
  350. public void windowClosing(WindowEvent e) { System.exit(0);}
  351. public void windowOpened(WindowEvent e) {}
  352. public void windowClosed(WindowEvent e) {}
  353. public void windowIconified(WindowEvent e) {}
  354. public void windowDeiconified(WindowEvent e) {}
  355. public void windowActivated(WindowEvent e) {}
  356. public void windowDeactivated(WindowEvent e) {}
  357. /**
  358. * This section contains the implementation of the ActionListener
  359. * class (abstract overrides). This controls what happens to the
  360. * menubar and menu items.
  361. */
  362. /**
  363. * This section contains the implementation of the KeyListener
  364. * class (abstract overrides). This controls what happens when
  365. * the user presses and releases keys on the keyboard.
  366. *
  367. */
  368. public void keyTyped(KeyEvent e) {}
  369. public void keyPressed (KeyEvent e)
  370. {
  371. // If keys are locked, don't do anything
  372. if (gameKeyLock) return;
  373. // Check for other keys
  374. switch(e.getKeyChar())
  375. {
  376. // Toggle pause
  377. case 'p':
  378. togglePause();
  379. break;
  380. // Start game
  381. case 's':
  382. gameState = PLAY;
  383. gamePaused = false;
  384. break;
  385. // Toggle debug
  386. case 'd':
  387. toggleDebug();
  388. Map.draw();
  389. break;
  390. // Toggle grid
  391. case 'g':
  392. Map.toggleGrid();
  393. Map.draw();
  394. break;
  395. // SPACE, Toggle gameWaiting
  396. case 32:
  397. if (gameWaiting) toggleWait();
  398. break;
  399. // ESC, exit game
  400. case 27:
  401. System.exit(0);
  402. break;
  403. }
  404. }
  405. public void keyReleased(KeyEvent e) {}
  406. /**
  407. * This section contains the implementation of the MouseListener
  408. * class (abstract overrides). This controls what happens when
  409. * the user interacts with the game with a mouse.
  410. *
  411. */
  412. public void mouseClicked(MouseEvent e)
  413. {
  414. switch(gameState)
  415. {
  416. // In-game
  417. case PLAY:
  418. Cell cell;
  419. // Make sure we are in-between rounds
  420. if (gameWaiting)
  421. {
  422. // Grab the cell that was clicked on
  423. if ((cell = Grid.getCell(Grid.cellFromLocation(e.getPoint()))) != null)
  424. clickList.add(cell);
  425. }
  426. break;
  427. }
  428. }
  429. public void mousePressed(MouseEvent e) {}
  430. public void mouseReleased(MouseEvent e) {}
  431. public void mouseEntered(MouseEvent e) {}
  432. public void mouseExited(MouseEvent e) {}
  433. // Not yet implemented
  434. //private void newGame() {}
  435. //private void removeEntity() {}
  436. //private void notifyLevelChange() {}
  437. //private void notifyGameOver() {}
  438. }