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.

374 lines
10 KiB

  1. package playground;
  2. import java.awt.Graphics2D;
  3. import java.util.HashMap;
  4. import java.util.LinkedList;
  5. import java.util.Map;
  6. import java.util.Stack;
  7. import java.awt.event.*;
  8. import gameobjects.GameObject;
  9. import org.apache.logging.log4j.Logger;
  10. import org.apache.logging.log4j.LogManager;
  11. /**
  12. * Playground represents a level of the game, focusing on the game LOGIC, i.e., not so much on the
  13. * graphical representation. In particular, an instance of Playground
  14. * <ul>
  15. * <li>manages the different moving or static objects in a level (e.g., collisions, adding objects,
  16. * removing objects). This is mainly done by the methods {@link #addObject}, {@link #deleteObject}.
  17. * <li>processes keyboard inputs provided by GameLoop in {@link #processKeyEvents(Stack)} and
  18. * {@link #processMouseEvents(Stack)}
  19. * <li>represents the state of a level represented by <b>flags</b>. Each flag has a name (a String)
  20. * and an arbitrary value of any type. Methods: {@link #setLevelFlag(String, Object)},
  21. * {@link #getLevelFlag(String)}. As an example, the current score is a flag usually named "points",
  22. * with an Integer as a value. This value can be retrieved and manipulated using the above mentioned
  23. * methods.
  24. * </ul>
  25. */
  26. public abstract class Playground {
  27. public static final int FLAGS_GLOBAL = 1;
  28. public static final int FLAGS_LEVEL = 2;
  29. public static final int FLAGS_ALL = 3;
  30. protected int canvasX = -1;
  31. protected int canvasY = -1;
  32. /** only one set of objects exists concurrently so this can be static */
  33. protected static HashMap<String, GameObject> gameObjects = new HashMap<String, GameObject>();
  34. /** only one set of objects exists concurrently so this can be static */
  35. protected static HashMap<String, Object> flags = new HashMap<String, Object>();
  36. protected String level = "";
  37. protected double timeStep = 0;
  38. protected double gameTime = 0;
  39. LinkedList<GameObject> addables = new LinkedList<GameObject>();
  40. LinkedList<String> removables = new LinkedList<String>();
  41. // HashMap<Integer,Integer> keys ;
  42. Stack<KeyEvent> keyEvents;
  43. Stack<MouseEvent> mouseEvents;
  44. protected boolean pausedFlag = false;
  45. private static Logger logger = LogManager.getLogger(Playground.class);
  46. public Playground() {
  47. this.canvasX = -1;
  48. this.canvasY = -1;
  49. }
  50. // here, the level communicates its size preference to the GameUI
  51. // called automatically
  52. public abstract int preferredSizeX();
  53. public abstract int preferredSizeY();
  54. /**
  55. * Adds a graphics object to a level.
  56. *
  57. * @param o GameObject The object to be added
  58. */
  59. public void addObject(GameObject o) {
  60. // gameObjects.put(o.getId(), o);
  61. addables.addLast(o);
  62. }
  63. /**
  64. * Adds a graphics object to a level.
  65. *
  66. * @param o GameObject The object to be added
  67. */
  68. public void addObjectNow(GameObject o) {
  69. gameObjects.put(o.getId(), o);
  70. }
  71. /**
  72. * Puts objects with a certain substring in their name into a LinkedLisrt and returns them.
  73. *
  74. * @param substr The string that must be part of the object name if object is to be considered
  75. * found.
  76. * @param filterInactive if set true only active objects are considered.
  77. * @return a reference to a LinkedList filled with all objects that have <b>substr</b> in their
  78. * name
  79. */
  80. public LinkedList<GameObject> collectObjects(String substr, boolean filterInactive) {
  81. LinkedList<GameObject> l = new LinkedList<GameObject>();
  82. for (Map.Entry<String, GameObject> entry : Playground.gameObjects.entrySet()) { // Iterator
  83. // usage
  84. GameObject obj = entry.getValue();
  85. if (obj.getId().contains(substr)) {
  86. if (filterInactive == true) {
  87. if (obj.isActive()) {
  88. l.add(obj);
  89. }
  90. } else {
  91. l.add(obj);
  92. }
  93. }
  94. }
  95. return l;
  96. };
  97. /**
  98. * Removes a graphics object from a level.
  99. *
  100. * @param id String The unique identifier of the object
  101. */
  102. public void deleteObject(String id) {
  103. // gameObjects.remove(id);
  104. removables.addLast(id);
  105. }
  106. /**
  107. * Removes a graphics object from a level immediately, CAUTION.
  108. *
  109. * @param id String The unique identifier of the object
  110. */
  111. public void deleteObjectNow(String id) {
  112. gameObjects.remove(id);
  113. }
  114. /**
  115. * Retrieves a graphics object by name.
  116. *
  117. * @param id String Unique id of the object
  118. * @return reference to the requested game object, or null if not found
  119. */
  120. public GameObject getObject(String id) {
  121. return gameObjects.get(id);
  122. }
  123. /**
  124. * Sets a level-wide permanent flag.
  125. *
  126. * @param flag String Q unique name in this level. If it exists value is overwritten.
  127. * @param value Object Any Object can be the value of a flag!
  128. */
  129. public static void setGlobalFlag(String flag, Object value) {
  130. flags.put("/global/" + flag, value);
  131. }
  132. public Object setLevelFlag(String flag, Object value) {
  133. flags.put("/" + this.level + "/" + flag, value);
  134. return value;
  135. }
  136. /**
  137. * mode can be: FLAGS_ALL (all), FLAGS_GLOBAL(global), FLAGs_LEVEL(level)
  138. *
  139. * @param mode can be only one of {@link #FLAGS_GLOBAL} {@link #FLAGS_ALL} or
  140. * {@link #FLAGS_LEVEL }
  141. */
  142. public void resetFlags(int mode) {
  143. LinkedList<String> delKeys = new LinkedList<String>();
  144. for (Map.Entry<String, Object> entry : Playground.flags.entrySet()) {
  145. logger.trace(entry.getKey() + " IndexofGlobal = " + entry.getKey().indexOf("/global/"));
  146. if ((mode == FLAGS_GLOBAL) && (entry.getKey().indexOf("/global/") != -1)) {
  147. logger.debug("GLOBAL: scheduling for removal: " + entry.getKey());
  148. delKeys.add(entry.getKey());
  149. } else if ((mode == FLAGS_LEVEL) && (entry.getKey().indexOf("/global/") == -1)) {
  150. logger.debug("LEVEL: scheduling for removal: " + entry.getKey());
  151. delKeys.add(entry.getKey());
  152. } else if (mode == FLAGS_ALL) {
  153. logger.debug("ALL: scheduling for removal: " + entry.getKey());
  154. delKeys.add(entry.getKey());
  155. }
  156. }
  157. for (String str : delKeys) {
  158. logger.trace("removing key " + str);
  159. flags.remove(str);
  160. }
  161. }
  162. /**
  163. * Retrieves a level-wide flag by name.
  164. *
  165. * @param flag String Unique flag id
  166. * @return the value associated with <b>flag</b>, or <b>null</b> if the flag does not exist.
  167. */
  168. public static Object getGlobalFlag(String flag) {
  169. return flags.get("/global/" + flag);
  170. }
  171. /** checks for existence and if not creates the new global flag with the given initial value. Returns the value.
  172. * afterwards it is guaranteed that no priorly existing value is overridden and that it definitely exists (created if not present before).
  173. *
  174. * @param flag String name for the global flag (created if not present)
  175. * @param value Object value to be stored (used only if flag was not present)
  176. * @return the current value of the flag (maybe the initial one in case flag was not there before)
  177. */
  178. public static Object getOrCreateGlobalFlag(String flag, Object value) {
  179. Object tmp = getGlobalFlag(flag);
  180. if (tmp == null) {
  181. setGlobalFlag(flag, value);
  182. return value;
  183. } else {
  184. return tmp;
  185. }
  186. }
  187. public Object getLevelFlag(String flag) {
  188. return flags.get("/" + this.level + "/" + flag);
  189. }
  190. public Object getOrCreateLevelFlag(String flag, Object createValue) {
  191. Object tmp = getLevelFlag(flag);
  192. if (tmp == null) {
  193. return setLevelFlag(flag, createValue);
  194. } else {
  195. return tmp;
  196. }
  197. }
  198. /**
  199. * Reinitializes the level.
  200. */
  201. public void reset() {
  202. gameObjects.clear();
  203. }
  204. public boolean isPaused() {
  205. return this.pausedFlag;
  206. }
  207. public void setPaused(boolean p) {
  208. this.pausedFlag = p;
  209. }
  210. public void togglePause() {
  211. pausedFlag = !pausedFlag;
  212. }
  213. /**
  214. * Method meant to be filled with own code, processes Keyboard inputs.
  215. *
  216. * @param keyEvents all collected {@link KeyEvent}s collected since last game loop.
  217. */
  218. public void processKeyEvents(Stack<KeyEvent> keyEvents) {
  219. this.keyEvents = keyEvents;
  220. Playground.setGlobalFlag("inputs", keyEvents);
  221. }
  222. public void processMouseEvents(Stack<MouseEvent> mouseEvents) {
  223. this.mouseEvents = mouseEvents;
  224. Playground.setGlobalFlag("inputs", mouseEvents);
  225. }
  226. public Stack<KeyEvent> getKeyEvents() {
  227. return this.keyEvents;
  228. }
  229. public Stack<MouseEvent> getMouseEvents() {
  230. return this.mouseEvents;
  231. }
  232. /**
  233. * Method meant to be filled with own code, handles the entore game logic (collision checks, timed
  234. * events, ...).
  235. *
  236. */
  237. public abstract void applyGameLogic();
  238. /**
  239. * Sets up a single level. Prepares all objects etc.
  240. *
  241. * @param level String a string identifying the level number etc
  242. */
  243. public abstract void prepareLevel(String level);
  244. public abstract boolean gameOver();
  245. public abstract boolean levelFinished();
  246. public int getSizeX() {
  247. return canvasX;
  248. }
  249. public int getSizeY() {
  250. return canvasY;
  251. }
  252. /**
  253. * Calls all object update methods in level. Internal, never call directly.
  254. *
  255. */
  256. public void updateObjects() {
  257. for (GameObject gameObject : gameObjects.values()) { // Iterator usage
  258. if (gameObject.isActive() == true) {
  259. gameObject.updateObject();
  260. logger.trace("updated object " + gameObject.scol);
  261. }
  262. }
  263. for (GameObject o : addables) { // Iterator usage
  264. addObjectNow(o);
  265. }
  266. for (String s : removables) { // Iterator usage
  267. deleteObjectNow(s);
  268. }
  269. removables.clear();
  270. addables.clear();
  271. }
  272. public void setTimestep(double s) {
  273. timeStep = s;
  274. }
  275. public double getTimestep() {
  276. return timeStep;
  277. }
  278. /** set the game time value (in seconds)
  279. *
  280. * @param s seconds the game is running
  281. */
  282. public void setGameTime(double s) {
  283. this.gameTime = s;
  284. }
  285. /** returns time in seconds since level start */
  286. public double getGameTime() {
  287. return this.gameTime;
  288. }
  289. /**
  290. * To be redefined!! Draws mainly h level background and global information like points etc.
  291. *
  292. * @param g2 Graphics2D abstract drawing object of java Swing, used to carry out all drawing
  293. * operations.
  294. */
  295. public abstract void redrawLevel(Graphics2D g2);
  296. /**
  297. * Internal, do not call directly.
  298. *
  299. * @param g2 Graphics2D abstract drawing object of java Swing, used to carry out all drawing
  300. * operations.
  301. */
  302. public void redraw(Graphics2D g2) {
  303. redrawLevel(g2);
  304. for (GameObject gameObject : gameObjects.values()) {
  305. if (gameObject.isActive()) {
  306. gameObject.draw(g2);
  307. }
  308. }
  309. }
  310. }