EOS 2  1.1.0
Einfache Objektbasierte Sprache
Game.java
gehe zur Dokumentation dieser Datei
1 package de.lathanda.eos.game;
2 
3 import java.util.Arrays;
4 import java.util.LinkedList;
5 import java.util.TreeMap;
6 import java.util.TreeSet;
7 
8 import de.lathanda.eos.base.MutableColor;
9 import de.lathanda.eos.base.Picture2D;
10 import de.lathanda.eos.base.math.Point;
11 import de.lathanda.eos.game.geom.CollisionDetection;
12 
27 public class Game implements Runnable {
28 
35  private enum State {
36 
37  PREPARE, // / Initialisierung
38  RUNNING, // / Die Simulation läuft
39  PAUSE, // / Die Simulation ist vorübergehend angehalten
40  SHUTDOWN
41  // / Die Simulation ist gerade dabei alle Resourcen freizugeben
42  };
43 
47  private State state = State.PREPARE;
51  private int fps;
55  private long round = 0;
59  private final boolean[] keys = new boolean[256];
63  private final boolean[] keysPressed = new boolean[256];
67  private final boolean[] keysPress = new boolean[256];
71  private final boolean[] mouseBtn = new boolean[20];
75  private final boolean[] mouseBtnPress = new boolean[20];
79  private final boolean[] mouseBtnPressed = new boolean[20];
83  private Point mousePos = new Point(0d, 0d);
84 
88  private final TreeSet<Sprite> drawingList = new TreeSet<>();
92  private final TreeMap<Integer, Sprite> sprites = new TreeMap<>();
96  private final LinkedList<Sprite> pendingDelete = new LinkedList<>();
100  private final LinkedList<Sprite> pendingAdd = new LinkedList<>();
101 
106  // draw is running
107  private final Object DRAW_LOCK = new Object();
108  // sprite list change is queued
109  private final Object CHANGE_LOCK = new Object();
110  // keyboard status is updating
111  private final Object INPUT_LOCK = new Object();
112 
113  private GameFrame gameFrame;
114 
119  public Game() {
120  this(200, 200, MutableColor.WHITE, 30, "");
121  }
122 
135  public Game(int fps) {
136  this(200, 200, MutableColor.WHITE, fps, "");
137  }
138 
139  public Game(double width, double height) {
140  this(width, height, MutableColor.WHITE, 30, "");
141  }
142 
143  public Game(double width, double height, String title) {
144  this(width, height, MutableColor.WHITE, 30, title);
145  }
146 
147  public Game(double width, double height, MutableColor back, String title) {
148  this(width, height, back, 30, title);
149  }
150 
151  public Game(double width, double height, MutableColor back, int fps, String title) {
152  gameFrame = new GameFrame(width, height, back, this, title);
153  colDetect = new CollisionDetection(this);
154  this.fps = fps;
155  start();
156  }
157 
165  public void keyDown(int keyCode) {
166  synchronized (INPUT_LOCK) {
167  try {
168  keys[keyCode] = true;
169  keysPress[keyCode] = true;
170  } catch (ArrayIndexOutOfBoundsException e) {
171  }
172  }
173  }
174 
182  public void keyUp(int keyCode) {
183  try {
184  keys[keyCode] = false;
185  } catch (ArrayIndexOutOfBoundsException e) {
186  }
187  }
188 
196  public void mouseDown(int button) {
197  synchronized (INPUT_LOCK) {
198  try {
199  mouseBtn[button] = true;
200  mouseBtnPress[button] = true;
201  } catch (ArrayIndexOutOfBoundsException e) {
202  }
203  }
204  }
205 
213  public void mouseUp(int button) {
214  try {
215  mouseBtn[button] = false;
216  } catch (ArrayIndexOutOfBoundsException e) {
217  }
218  }
219 
227  public void mousePosition(Point p) {
228  mousePos = p;
229  }
230 
234  public void resume() {
235  state = State.RUNNING;
236  }
237 
241  public void pause() {
242  state = State.PAUSE;
243  }
244 
249  public void start() {
250  state = State.RUNNING;
251  (new Thread(this)).start();
252  }
253 
257  public void shutDown() {
258  state = State.SHUTDOWN;
259  }
260 
267  public void render(Picture2D p) {
268  synchronized (DRAW_LOCK) {
269  for (Sprite s : drawingList) {
270  try {
271  p.restoreStyles();
272  synchronized (s) {
273  s.render(p);
274  }
275  } catch (Throwable t) {
276  // drawing exception shall not stop execution
277  t.printStackTrace(System.err);
278  System.err.println("error occured while render, removing " + s);
279  removeSprite(s);
280  }
281  }
282  }
283 
284  }
285 
289  protected void step() {
290  // perform step
291  for (Sprite s : sprites.values()) {
292  // the following sync block, enforces data sync.
293  // Without it Sprite properties would have to be volatile
294  try {
295  synchronized (s) {
296  s.update(round, this);
297 
298  }
299  } catch (Throwable t) {
300  // a single object shall not stop execution
301  t.printStackTrace();
302  System.err.println("error occured while step execution, removing " + s);
303  removeSprite(s);
304  }
305  }
306  synchronized (INPUT_LOCK) {
307  // clear keypressed
308  System.arraycopy(keysPress, 0, keysPressed, 0, keysPress.length);
309  Arrays.fill(keysPress, false);
310  // clear mousepressed
311  System.arraycopy(mouseBtnPress, 0, mouseBtnPressed, 0, mouseBtnPress.length);
312  Arrays.fill(mouseBtnPress, false);
313  }
314  // list changes
315  Sprite[] del;
316  Sprite[] add;
317  synchronized (CHANGE_LOCK) {
318  del = new Sprite[pendingDelete.size()];
319  pendingDelete.toArray(del);
320  pendingDelete.clear();
321  add = new Sprite[pendingAdd.size()];
322  pendingAdd.toArray(add);
323  pendingAdd.clear();
324  }
325  if (del.length > 0 || add.length > 0) {
326  synchronized (DRAW_LOCK) {
327  for (int i = 0; i < del.length; i++) {
328  colDetect.removeObject(del[i]);
329  drawingList.remove(del[i]);
330  sprites.remove(del[i].getID());
331  del[i].cleanup(this);
332  }
333  for (int i = 0; i < add.length; i++) {
334  add[i].init(this);
335  sprites.put(add[i].getID(), add[i]);
336  drawingList.add(add[i]);
337  colDetect.addObject(add[i]);
338  }
339  }
340  }
341  // check for collisions
343 
344  }
345 
350  @Override
351  public void run() {
352  long start = System.nanoTime();
353  round = 0;
354  long actual_time;
355  long debit = -1;
356  while (state != State.SHUTDOWN) {
357  actual_time = System.nanoTime();
358  if (debit <= actual_time) {
359  switch (state) {
360  case PAUSE:
361  // adjust start to be in sync with pause
362  start = actual_time - round * 1000000000 / fps;
363  break;
364  case PREPARE:
365  // adjust start to be in sync with pause
366  start = actual_time - round * 1000000000 / fps;
367  break;
368  case RUNNING:
369  step();
370  gameFrame.repaint();
371  // manage time intervals
372  round++;
373  debit = start + round * 1000000000 / fps;
374  break;
375  default:
376  throw new RuntimeException("unknown state");
377  }
378 
379  } else {
380  try {
381  long pause = debit - actual_time;
382  Thread.sleep(pause / 1000000, (int) (pause % 1000000));
383  } catch (Exception e) {
384  // shit happens
385  }
386  }
387  }
388  }
389 
393  public void clearAll() {
394  synchronized (CHANGE_LOCK) {
395  pendingAdd.clear();
396  pendingDelete.addAll(sprites.values());
397  }
398  }
399 
400  /*
401  * Prüft, ob die Taste gedrückt ist. Der KeyCode entspricht den Konstanten
402  * aus KeyEvent. zB KeyEvent.VK_Z, KeyEvent.VK_UP
403  */
404  public boolean isKeyDown(int keyCode) {
405  try {
406  return keys[keyCode];
407  } catch (ArrayIndexOutOfBoundsException e) {
408  return false;
409  }
410  }
411 
412  /*
413  * Prüft, ob die Taste gedrückt wurde. Der KeyCode entspricht den Konstanten
414  * aus KeyEvent. zB KeyEvent.VK_Z, KeyEvent.VK_UP
415  */
416  public boolean isKeyPressed(int keyCode) {
417  try {
418  return keysPressed[keyCode];
419  } catch (ArrayIndexOutOfBoundsException e) {
420  return false;
421  }
422  }
423 
424  /*
425  * Fügt ein Sprite in das Spiel hinzu.
426  *
427  * @param obj Sprite
428  */
429  public void addSprite(Sprite obj) {
430  if (obj == null) {
431  return;
432  }
433  synchronized (CHANGE_LOCK) {
434  pendingAdd.add(obj);
435  }
436  }
437 
438  /*
439  * Löscht ein Sprite aus dem Spiel
440  *
441  * @param Sprite
442  */
443  public void removeSprite(Sprite obj) {
444  synchronized (CHANGE_LOCK) {
445  pendingDelete.add(obj);
446  pendingAdd.remove(obj);
447  }
448  }
449 
450  /*
451  * Liefert die Position der Mouse
452  *
453  * @return Mouseposition
454  */
455  public Point getMouse() {
456  return new Point(mousePos);
457  }
458 
459  /*
460  * Prüft ob die Maustaste gedrückt ist.
461  *
462  * @param buttom Nummer des Knopfes
463  */
464  public boolean isMouseDown(int button) {
465  try {
466  return mouseBtn[button];
467  } catch (ArrayIndexOutOfBoundsException e) {
468  return false;
469  }
470  }
471 
472  /*
473  * Prüft ob die Maustaste gedrückt wurde. Der erste Aufruf löscht den
474  * gedrückt Zustand.
475  *
476  * @param buttom Nummer des Knopfes
477  */
478  public boolean isMousePressed(int button) {
479  try {
480  return mouseBtnPressed[button];
481  } catch (ArrayIndexOutOfBoundsException e) {
482  return false;
483  }
484  }
485 }
static final MutableColor WHITE
boolean isKeyDown(int keyCode)
Definition: Game.java:404
void render(Picture2D p)
Definition: Game.java:267
CollisionDetection colDetect
Kollisionserkennungsalgorithmus.
Definition: Game.java:105
boolean isKeyPressed(int keyCode)
Definition: Game.java:416
void keyUp(int keyCode)
Definition: Game.java:182
Game(double width, double height, MutableColor back, int fps, String title)
Definition: Game.java:151
void removeSprite(Sprite obj)
Definition: Game.java:443
void mouseUp(int button)
Definition: Game.java:213
void mouseDown(int button)
Definition: Game.java:196
Game(double width, double height)
Definition: Game.java:139
boolean isMouseDown(int button)
Definition: Game.java:464
boolean isMousePressed(int button)
Definition: Game.java:478
Game(double width, double height, MutableColor back, String title)
Definition: Game.java:147
Game(double width, double height, String title)
Definition: Game.java:143
void mousePosition(Point p)
Definition: Game.java:227
void addSprite(Sprite obj)
Definition: Game.java:429
void keyDown(int keyCode)
Definition: Game.java:165
void init(Game game)
Definition: Sprite.java:147
void cleanup(Game game)
Definition: Sprite.java:159
Impressum