package Core; //Game.java - driving force behind the game. name may change. //Samantha Petro //created: 28 April 2008 //last modified: 30 May 2008 import entities.EntityManager; import graphicsManager.ImageManager; import gridboard.GridBoard; import inputOutputManager.Configuration; import inputOutputManager.ValueManager; import java.awt.Graphics2D; import java.awt.event.ActionEvent; //generic event the swing timer uses import java.awt.event.ActionListener; import javax.swing.JPanel; import javax.swing.Timer; //swing timer import sound.SoundManager; import utilities.Flag; import utilities.MessageSystem; @SuppressWarnings("serial") public class Game extends JPanel implements ActionListener, MessageSystem { private static final int TIMER_PERIOD = 100; // #ms to fire off the swing timer private static int counter; //increments every TIMER_PERIOD to help entities know when to move private static final int PWIDTH = 800; // size of this panel private static final int PHEIGHT = 800; //gameplay values private boolean pause = false; public boolean isPaused() { return pause; } // private boolean //managers private ImageManager imageMgr; private EntityManager entityMgr; private ValueManager valueMgr; private GridBoard gridBoard; private SoundManager soundMgr; private static Game game = null; public static Game getInstance() { if (game == null) game = new Game(); return game; } //-------- CONSTRUCTOR ----------// /** Singleton. * Sets up the basic graphics environment and initializes the managers. Also * starts the Swing timer. * @param */ private Game() { // TODO: add manager initializations imageMgr = new ImageManager(); entityMgr = EntityManager.getInstance(); valueMgr = ValueManager.getInstance(); gridBoard = GridBoard.getInstance(); soundMgr = SoundManager.getInstance(); //initialize counters counter = 0; new Timer(TIMER_PERIOD, this).start(); // start the Swing timer } /** * Initializes the game */ public void initialize() { //TODO initialize managers imageMgr.initialize(this, "../images/", PWIDTH, PHEIGHT); entityMgr.initialize(); valueMgr.initialize(); gridBoard.initialize(); soundMgr.initialize(); // load config file Configuration.loadConfigFile(); //initialize the state engine StateMainScreen sms = new StateMainScreen(); currentState = sms.getInstance(); previousState = sms.getInstance(); //start the first state currentState.Enter(game); } //------- TIMER FUNCTIONS -------// private boolean incrementCounter = false; public void startCounter() { incrementCounter = true; } public void stopCounter() { incrementCounter = false; } //timer only pauses when AI /** * This function is called every time the JVM picks up a timer event (triggered * by the Swing timer). It is used to take stress off the CPU, speed up game time, * and to allow the game to have control of when updates and draws occur. * @param e an ActionEvent picked up when the Swing timer fires off an event */ public void actionPerformed(ActionEvent e) { //execute current state game.update(); //this event is fired off using the swing timer if (incrementCounter) { //timer does not increment during pauses or loading, only gameplay counter++; } // TODO Swing timer actions //call a redraw imageMgr.update(); } /**returns the current counter. * the counter cannot be altered by any class other than Game * @return the current counter value */ public static int getCounterTime() { return counter;} //------- STATE FUNCTIONS ------// //states are stuck here so the window events can control the state changes //also makes it easier to figure out where things are. private State currentState; private State previousState; /** * changes the state of the game state machine * @param newstate instance of the new state. never use a new modifier. * always use getInstance() for the new state. this way the function is * safe and never gets a null instance */ public void changeState(State newstate) { //keep a record of the previous state previousState = currentState; //call the exit method of the existing state currentState.Exit(game); //change state to the new state currentState = newstate; //call the entry method of the new state currentState.Enter(game); } /** * reverts to the previous state. use with caution. */ public void revertToPrevious() { //this if statement should never be reached if (previousState == null) { System.out.println("Previous state is null. cannot revert."); return; } else if (previousState == currentState) { System.out.println("Current and previous state the same. Ignoring reversion."); return; } changeState(previousState); } //TODO: make these queries! public void loadLevel(String file, String levelToLoad) { //TODO temp loader. change to query later imageMgr.loadLevel(file); // TODO remove temp level load valueMgr.loadLevel(levelToLoad); } //---------- MAIN GAME ------------- // /** Main game loop. * may be changed into an initialize() and run() loop to * encapsulate this stuff or just to make main cleaner. * @param args */ public static void main(String[] args) { game = new Game(); game.initialize(); } public void update() { if (currentState != null) currentState.Execute(game); //TODO update managers //imageMgr is updated separately to control the draw. } public void updateDuringPlay(){ entityMgr.update(); gridBoard.update(); } public void unloadAfterPlay(){ entityMgr.unload(); soundMgr.unload(); imageMgr.unload(); } public Object query(short destination, short messageToSend, Object dataToSend) { if(destination == Flag.GAME){ // TODO Fill in these functions/states!!! switch(messageToSend){ case Flag.G_LOAD_FAILURE: case Flag.G_NO_MORE_LIVES: StateOutOfLives sool = new StateOutOfLives(); changeState(sool.getInstance()); return null; case Flag.G_PAUSE: soundMgr.query(Flag.SOUND, Flag.S_PAUSE_LOOP, null); stopCounter(); pause = true; return null; case Flag.G_UNPAUSE: soundMgr.query(Flag.SOUND, Flag.S_RESUME_LOOP, null); startCounter(); pause = false; return null; case Flag.G_VICTORY: StateVictory sv = new StateVictory(); changeState(sv.getInstance()); return null; case Flag.G_GET_STATE: return currentState; //state-based flags case Flag.G_STATE_DRAW: if (currentState != null) currentState.drawStateGraphics((Graphics2D)dataToSend); return null; case Flag.G_UPDATE: updateDuringPlay(); return null; case Flag.G_UNLOAD: unloadAfterPlay(); return null; default: return Flag.BAD_FLAG; } }else{ // TODO for each new manager, add the destination within this switch statement switch(destination){ case Flag.ENTITY: return entityMgr.query(destination, messageToSend, dataToSend); case Flag.VALUE: return valueMgr.query(destination, messageToSend, dataToSend); case Flag.IMAGE: return imageMgr.query(destination, messageToSend, dataToSend); case Flag.GRIDBOARD: return gridBoard.query(destination, messageToSend, dataToSend); case Flag.SOUND: return soundMgr.query(destination, messageToSend, dataToSend); default: return Flag.BAD_FLAG; } } } }