You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

231 lines
8.0 KiB

  1. package base;
  2. import java.io.IOException;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.ListIterator;
  6. import org.apache.logging.log4j.LogManager;
  7. import org.apache.logging.log4j.Logger;
  8. import gameobjects.GameObject;
  9. import playground.Level1;
  10. import playground.Playground;
  11. import ui.GameUI;
  12. /**
  13. * Main class starting any game, contains main(). Apart from that, this class manages all
  14. * non-logical functionalities which should be hidden from a game designer like:
  15. * <ul>
  16. * <li>Setting up windows, panels, buttons, action callbacks, ...
  17. * <li>Reading keyboard inputs
  18. * <li>Redrawing game window if necessary
  19. * <li>managing the game time and calling the appropriate {@link GameObject} or {@link Playground}
  20. * methods periodically, at every time step of the game.
  21. * </ul>
  22. * There will normally never be a need to modify this file, a designer/game programmer should always
  23. * redefine the {@link GameObject} and {@link Playground} classes and implement new functionality
  24. * there. To make a long story short<br>
  25. */
  26. public class GameLoop {
  27. /** Pixel width of Game GUI ( above 0) */
  28. public static int SIZEX = 300;
  29. /** Pixel height of Game GUI (above 0) */
  30. public static int SIZEY = 200;
  31. /**
  32. * before call to {@link #runGame(String[])} this List should be initialized (in constructor).
  33. */
  34. private List<Playground> levels = new ArrayList<Playground>(0);
  35. private static Logger logger = LogManager.getLogger(GameLoop.class);
  36. /** constructor which calls {@link #defineLevels()}, which adds all levels of this game.
  37. */
  38. public GameLoop() {
  39. this.defineLevels();
  40. }
  41. /**
  42. * First resets (clears) the already existing level instances of this game's list of levels ({@link #resetLevels()}),
  43. * then adds one instance of {@link Level1} by calling {@link #addLevel()}.
  44. * Should be called only before playing starts (e.g. in constructor or before {@link #runGame(String[]) } is called.
  45. *
  46. * <br><strong>Note:</strong> Subclasses of {@link GameLoop} should override this method to define own levels for their game.
  47. */
  48. void defineLevels() {
  49. this.resetLevels();
  50. this.addLevel(new Level1());
  51. }
  52. /**
  53. * Adds the given level instance to the end of the currently already stored list of levels to play.
  54. * Should be called only before playing starts (e.g. in constructor or before {@link #runGame(String[]) } is called.
  55. *
  56. * @param level instance of Playground (a level) to add.
  57. */
  58. void addLevel(Playground level) {
  59. this.levels.add(level);
  60. }
  61. /**
  62. * Removes all levels from the list of levels to play! Do not call this method while {@link #runGame(String[]) } is running!
  63. */
  64. void resetLevels() {
  65. this.levels.clear();
  66. }
  67. /**
  68. * loops over all {@link #levels} and implements the game loop to update continuously the level
  69. * during play time
  70. *
  71. * @param args command line arguments forwarded (currently ignored)
  72. * @throws IOException if hitghscore.txt cannot be written.
  73. */
  74. public void runGame(String[] args) throws IOException {
  75. logger.info("GUI starts");
  76. GameUI gameUI = new GameUI(SIZEX, SIZEY); // probably change to your new GUI class
  77. double gameTime = -1;
  78. Playground currentPlayground = null;
  79. // loop over different levels
  80. ListIterator<Playground> levelIterator = levels.listIterator();
  81. while (true) {
  82. logger.debug("LevelIndex is " + (levelIterator.nextIndex()) + " (of " + levels.size() + " levels)");
  83. gameTime = 0;
  84. long start = System.nanoTime();
  85. // loop over single level
  86. while (true) {
  87. int act = GameUI.getNewAction();
  88. // Query GameUI for high-level user commands; new game/reset/etc...
  89. if (act == GameUI.ACTION_RESET) {
  90. // ReStart Game in same Level
  91. logger.info("GUI RESET");
  92. currentPlayground.prepareLevel("level" + (levelIterator.nextIndex()-1));
  93. GameUI.resetAction();
  94. }
  95. if (act == GameUI.ACTION_NEW) {
  96. // new game
  97. logger.info("GUI NEW");
  98. start = System.nanoTime();
  99. levelIterator = levels.listIterator(); // reset
  100. currentPlayground = levelIterator.next(); // again level
  101. currentPlayground.prepareLevel("level" + (levelIterator.nextIndex()-1));
  102. gameUI.setPlayground(currentPlayground);
  103. GameUI.resetAction();
  104. break;
  105. }
  106. if (act == GameUI.ACTION_BUTTON) {
  107. // Event of Button pressed --> PAUSE!
  108. logger.info("GUI PAUSE");
  109. if (currentPlayground != null) {
  110. boolean p = currentPlayground.isPaused();
  111. p = !p;
  112. currentPlayground.setPaused(p);
  113. }
  114. GameUI.resetAction();
  115. }
  116. if (act == GameUI.ACTION_SAVE) {
  117. logger.info("GUI SAVE");
  118. // UNDONE save current state (not yet working/implemented)
  119. GameUI.resetAction();
  120. }
  121. if (act == GameUI.ACTION_LOAD) {
  122. logger.info("GUI LOAD");
  123. // load game state (currently simply resets)
  124. GameUI.resetAction();
  125. }
  126. // if game has been created: execute a single iteration of the game loop
  127. if (currentPlayground != null) {
  128. // calc time that was used for painting the game, in seconds since last loop
  129. long end = System.nanoTime();
  130. double realTS = ((double) (end - start) / 1000000000.);
  131. // time calc for one loop of the while
  132. start = System.nanoTime();
  133. if (currentPlayground.levelFinished() || currentPlayground.gameOver() == true) {
  134. break; // leave level; breaks WHILE
  135. }
  136. // paint current state of level and start time measurement
  137. gameUI.waitWhilePainting();
  138. gameUI.grabFocus(); // needed to grab input events in next step
  139. // communicate inputs to level
  140. currentPlayground.processKeyEvents(gameUI.getKeyEvents());
  141. currentPlayground.processMouseEvents(gameUI.getMouseEvents());
  142. if (currentPlayground.isPaused() == false) {
  143. // update objects and level
  144. currentPlayground.updateObjects();
  145. currentPlayground.applyGameLogic();
  146. // update game time
  147. gameTime += realTS;
  148. // communicate gameTime and timestep to level
  149. currentPlayground.setTimestep(realTS);
  150. currentPlayground.setGameTime(gameTime);
  151. Playground.setGlobalFlag("gameTime", Double.valueOf(realTS));
  152. logger.trace("gameTime is now "+gameTime);
  153. } // if
  154. } // if
  155. } // inner while loop within level
  156. // after level is done: leave outer loop if game over
  157. if (currentPlayground.gameOver() == true) {
  158. break; // outer while ends game
  159. }
  160. // after level is done: reset level and go to next, if there is one
  161. if (currentPlayground.levelFinished() == true) {
  162. currentPlayground.reset();
  163. // increase level counter, go on to next one
  164. logger.debug("level finished. now new LevelIndex is " + levelIterator.nextIndex());
  165. if (levelIterator.nextIndex() >= levels.size()) {
  166. logger.info("reached end of levels");
  167. break; // outer while ends game;
  168. }
  169. currentPlayground = levelIterator.next();
  170. currentPlayground.prepareLevel("level" + (levelIterator.nextIndex()-1));
  171. }
  172. } // outer loop over levels
  173. logger.info("Game ends. Bye.");
  174. System.exit(0);
  175. } // main()
  176. /**
  177. * main to start the whole application.
  178. * initializes the {@link #levels} ArrayList of Playground instances (levels) to be played with one level {@link SpaceInvadersLevel} in constructor of {@link #GameLoop}.
  179. *
  180. * @param args Java default command line args, forwarded to {@link #runGame(String[])}
  181. * @throws IOException in case highscore.txt cannot be written.
  182. */
  183. public static void main(String[] args) throws IOException {
  184. GameLoop gl = new GameLoop();
  185. gl.runGame(args);
  186. }
  187. }