package playground;
import java.awt.Graphics2D;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Stack;
import java.awt.event.*;
import gameobjects.GameObject;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
/**
* Playground represents a level of the game, focusing on the game LOGIC, i.e., not so much on the
* graphical representation. In particular, an instance of Playground
*
* - manages the different moving or static objects in a level (e.g., collisions, adding objects,
* removing objects). This is mainly done by the methods {@link #addObject}, {@link #deleteObject}.
*
- processes keyboard inputs provided by GameLoop in {@link #processKeyEvents(Stack)} and
* {@link #processMouseEvents(Stack)}
*
- represents the state of a level represented by flags. Each flag has a name (a String)
* and an arbitrary value of any type. Methods: {@link #setLevelFlag(String, Object)},
* {@link #getLevelFlag(String)}. As an example, the current score is a flag usually named "points",
* with an Integer as a value. This value can be retrieved and manipulated using the above mentioned
* methods.
*
*/
public abstract class Playground {
public static final int FLAGS_GLOBAL = 1;
public static final int FLAGS_LEVEL = 2;
public static final int FLAGS_ALL = 3;
protected int canvasX = -1;
protected int canvasY = -1;
/** only one set of objects exists concurrently so this can be static */
protected static HashMap gameObjects = new HashMap();
/** only one set of objects exists concurrently so this can be static */
protected static HashMap flags = new HashMap();
protected String level = "";
protected double timeStep = 0;
protected double gameTime = 0;
LinkedList addables = new LinkedList();
LinkedList removables = new LinkedList();
// HashMap keys ;
Stack keyEvents;
Stack mouseEvents;
protected boolean pausedFlag = false;
private static Logger logger = LogManager.getLogger(Playground.class);
public Playground() {
this.canvasX = -1;
this.canvasY = -1;
}
// here, the level communicates its size preference to the GameUI
// called automatically
public abstract int preferredSizeX();
public abstract int preferredSizeY();
/**
* Adds a graphics object to a level.
*
* @param o GameObject The object to be added
*/
public void addObject(GameObject o) {
// gameObjects.put(o.getId(), o);
addables.addLast(o);
}
/**
* Adds a graphics object to a level.
*
* @param o GameObject The object to be added
*/
public void addObjectNow(GameObject o) {
gameObjects.put(o.getId(), o);
}
/**
* Puts objects with a certain substring in their name into a LinkedLisrt and returns them.
*
* @param substr The string that must be part of the object name if object is to be
* considered found.
* @param filterInactive if set true only active objects are considered.
* @return a reference to a LinkedList filled with all objects that have substr in their name
*/
public LinkedList collectObjects(String substr, boolean filterInactive) {
LinkedList l = new LinkedList();
for (Map.Entry entry : Playground.gameObjects.entrySet()) { // Iterator
// usage
GameObject obj = entry.getValue();
if (obj.getId().contains(substr)) {
if (filterInactive == true) {
if (obj.isActive()) {
l.add(obj);
}
} else {
l.add(obj);
}
}
}
return l;
};
/**
* Removes a graphics object from a level.
*
* @param id String The unique identifier of the object
*/
public void deleteObject(String id) {
// gameObjects.remove(id);
removables.addLast(id);
}
/**
* Removes a graphics object from a level immediately, CAUTION.
*
* @param id String The unique identifier of the object
*/
public void deleteObjectNow(String id) {
gameObjects.remove(id);
}
/**
* Retrieves a graphics object by name.
*
* @param id String Unique id of the object
* @return reference to the requested game object, or null if not found
*/
public GameObject getObject(String id) {
return gameObjects.get(id);
}
/**
* Sets a level-wide permanent flag.
*
* @param flag String Q unique name in this level. If it exists value is overwritten.
* @param value Object Any Object can be the value of a flag!
*/
public static void setGlobalFlag(String flag, Object value) {
flags.put("/global/" + flag, value);
}
public Object setLevelFlag(String flag, Object value) {
flags.put("/" + this.level + "/" + flag, value);
return value;
}
/**
* mode can be: FLAGS_ALL (all), FLAGS_GLOBAL(global), FLAGs_LEVEL(level)
*
* @param mode can be only one of {@link #FLAGS_GLOBAL} {@link #FLAGS_ALL} or {@link #FLAGS_LEVEL }
*/
public void resetFlags(int mode) {
LinkedList delKeys = new LinkedList();
for (Map.Entry entry : Playground.flags.entrySet()) {
logger.trace(entry.getKey() + " IndexofGlobal = " + entry.getKey().indexOf("/global/"));
if ((mode == FLAGS_GLOBAL) && (entry.getKey().indexOf("/global/") != -1)) {
logger.debug("GLOBAL: scheduling for removal: " + entry.getKey());
delKeys.add(entry.getKey());
} else if ((mode == FLAGS_LEVEL) && (entry.getKey().indexOf("/global/") == -1)) {
logger.debug("LEVEL: scheduling for removal: " + entry.getKey());
delKeys.add(entry.getKey());
} else if (mode == FLAGS_ALL) {
logger.debug("ALL: scheduling for removal: " + entry.getKey());
delKeys.add(entry.getKey());
}
}
for (String str : delKeys) {
logger.trace("removing key " + str);
flags.remove(str);
}
}
/**
* Retrieves a level-wide flag by name.
*
* @param flag String Unique flag id
* @return the value associated with flag, or null if the flag does not exist.
*/
public static Object getGlobalFlag(String flag) {
return flags.get("/global/" + flag);
}
/**
* checks for existence and if not creates the new global flag with the given initial value. Returns
* the value. afterwards it is guaranteed that no priorly existing value is overridden and that it
* definitely exists (created if not present before).
*
* @param flag String name for the global flag (created if not present)
* @param value Object value to be stored (used only if flag was not present)
* @return the current value of the flag (maybe the initial one in case flag was not there before)
*/
public static Object getOrCreateGlobalFlag(String flag, Object value) {
Object tmp = getGlobalFlag(flag);
if (tmp == null) {
setGlobalFlag(flag, value);
return value;
} else {
return tmp;
}
}
public Object getLevelFlag(String flag) {
return flags.get("/" + this.level + "/" + flag);
}
public Object getOrCreateLevelFlag(String flag, Object createValue) {
Object tmp = getLevelFlag(flag);
if (tmp == null) {
return setLevelFlag(flag, createValue);
} else {
return tmp;
}
}
/**
* Reinitializes the level.
*/
public void reset() {
gameObjects.clear();
}
public boolean isPaused() {
return this.pausedFlag;
}
public void setPaused(boolean p) {
this.pausedFlag = p;
}
public void togglePause() {
pausedFlag = !pausedFlag;
}
/**
* Method meant to be filled with own code, processes Keyboard inputs.
*
* @param keyEvents all collected {@link KeyEvent}s collected since last game loop.
*/
public void processKeyEvents(Stack keyEvents) {
this.keyEvents = keyEvents;
Playground.setGlobalFlag("inputs", keyEvents);
}
public void processMouseEvents(Stack mouseEvents) {
this.mouseEvents = mouseEvents;
Playground.setGlobalFlag("inputs", mouseEvents);
}
public Stack getKeyEvents() {
return this.keyEvents;
}
public Stack getMouseEvents() {
return this.mouseEvents;
}
/**
* Method meant to be filled with own code, handles the entore game logic (collision checks, timed
* events, ...).
*
*/
public abstract void applyGameLogic();
/**
* Sets up a single level. Prepares all objects etc.
*
* @param level String a string identifying the level number etc
*/
public abstract void prepareLevel(String level);
public abstract boolean gameOver();
public abstract boolean levelFinished();
public int getSizeX() {
return canvasX;
}
public int getSizeY() {
return canvasY;
}
/**
* Calls all object update methods in level. Internal, never call directly.
*
*/
public void updateObjects() {
for (GameObject gameObject : gameObjects.values()) { // Iterator usage
if (gameObject.isActive() == true) {
gameObject.updateObject();
logger.trace("updated object " + gameObject.scol);
}
}
for (GameObject o : addables) { // Iterator usage
addObjectNow(o);
}
for (String s : removables) { // Iterator usage
deleteObjectNow(s);
}
removables.clear();
addables.clear();
}
public void setTimestep(double s) {
timeStep = s;
}
public double getTimestep() {
return timeStep;
}
/**
* set the game time value (in seconds)
*
* @param s seconds the game is running
*/
public void setGameTime(double s) {
this.gameTime = s;
}
/** returns time in seconds since level start */
public double getGameTime() {
return this.gameTime;
}
/**
* To be redefined!! Draws mainly h level background and global information like points etc.
*
* @param g2 Graphics2D abstract drawing object of java Swing, used to carry out all drawing
* operations.
*/
public abstract void redrawLevel(Graphics2D g2);
/**
* Internal, do not call directly.
*
* @param g2 Graphics2D abstract drawing object of java Swing, used to carry out all drawing
* operations.
*/
public void redraw(Graphics2D g2) {
redrawLevel(g2);
for (GameObject gameObject : gameObjects.values()) {
if (gameObject.isActive()) {
gameObject.draw(g2);
}
}
}
}