summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNao Pross <naopross@thearcway.org>2018-11-21 12:16:51 +0100
committerNao Pross <naopross@thearcway.org>2018-11-21 12:16:51 +0100
commit18077719f32071e614d3b4d01134d501796f571d (patch)
tree0148efb3f4bfea3c5951e9ca564faceff8208b3b
parentGeneralize to use only Scenes, attempt to implement pause (diff)
downloadSubconscious-java-18077719f32071e614d3b4d01134d501796f571d.tar.gz
Subconscious-java-18077719f32071e614d3b4d01134d501796f571d.zip
Fix InvalidStateException at scene loading, add Scene.requestScene()
The internal game state management has also been changed for the new scene management in the graphics
-rw-r--r--src/subconscious/Game.java57
-rw-r--r--src/subconscious/graphics/GameWindow.java79
-rw-r--r--src/subconscious/graphics/MapScene.java37
-rw-r--r--src/subconscious/graphics/MenuScene.java3
-rw-r--r--src/subconscious/graphics/PauseScene.java6
-rw-r--r--src/subconscious/graphics/Scene.java43
6 files changed, 138 insertions, 87 deletions
diff --git a/src/subconscious/Game.java b/src/subconscious/Game.java
index a6d42be..2361dd0 100644
--- a/src/subconscious/Game.java
+++ b/src/subconscious/Game.java
@@ -13,7 +13,7 @@ import java.util.concurrent.locks.Condition;
public class Game {
public enum State {
// main menu
- MENU,
+ MAIN_MENU,
// where actors can move freely
WORLD,
// where actors are constrained in the tiles
@@ -22,11 +22,12 @@ public class Game {
PAUSE, CLOSING,
}
- private State state = State.MENU;
+ private State state = State.MAIN_MENU;
private State lastState;
- private final Lock stateLock = new ReentrantLock();
- private Condition stateChanged;
+ // private final Lock stateLock = new ReentrantLock();
+ // private Condition stateChanged;
+ private boolean stateChanged;
private boolean running = true;
private boolean gameOver = false;
@@ -40,7 +41,7 @@ public class Game {
public Game() {
// set up stateLock
- stateChanged = stateLock.newCondition();
+ // stateChanged = stateLock.newCondition();
// TODO: this will be replaced with a dynamic mechanism based
// on the progress within the game
@@ -61,38 +62,45 @@ public class Game {
/* methods to manage the state */
public void setState(State state) {
- stateLock.lock();
- this.stateChanged.signal();
- stateLock.unlock();
+ // stateLock.lock();
+ // this.stateChanged.signal();
+ // stateLock.unlock();
+ this.stateChanged = true;
+ this.lastState = this.state;
this.state = state;
}
public State getState() {
+ this.stateChanged = false;
return this.state;
}
- public State waitStateChange() {
- stateLock.lock();
- try {
- stateChanged.await();
- } catch (InterruptedException ex) {
- ex.printStackTrace();
- } finally {
- stateLock.unlock();
- }
-
- return this.state;
+ public State getLastState() {
+ return this.lastState;
}
- public void togglePause() {
- if (this.isPaused())
- this.resume();
- else
- this.pause();
+ public boolean stateChanged() {
+ return this.stateChanged;
}
+ // public State waitStateChange() {
+ // stateLock.lock();
+ // try {
+ // stateChanged.await();
+ // } catch (InterruptedException ex) {
+ // ex.printStackTrace();
+ // } finally {
+ // stateLock.unlock();
+ // }
+
+ // return this.state;
+ // }
+
public void pause() {
+ if (this.state == State.PAUSE)
+ return;
+
this.lastState = this.state;
this.setState(State.PAUSE);
}
@@ -116,6 +124,7 @@ public class Game {
}
public void quit() {
+ // TODO: change to MAIN_MENU?
this.setState(State.CLOSING);
this.running = false;
}
diff --git a/src/subconscious/graphics/GameWindow.java b/src/subconscious/graphics/GameWindow.java
index da69d40..8f24dac 100644
--- a/src/subconscious/graphics/GameWindow.java
+++ b/src/subconscious/graphics/GameWindow.java
@@ -32,7 +32,7 @@ public class GameWindow extends JFrame implements WindowListener {
// stack of loaded scenes in the background that are paused
private Stack<SimpleEntry<Scene, Thread>> loadedScenes = new Stack<>();
- private Game game;
+ private volatile Game game;
// TODO: remove map editor, start directly on Battle mode
public GameWindow(Game g) {
@@ -66,33 +66,39 @@ public class GameWindow extends JFrame implements WindowListener {
this.loadScene(new MenuScene(this.game, "mainmenu"));
while (this.game.isRunning()) {
- Game.State newState = this.game.waitStateChange();
-
- switch (newState) {
- case MENU:
- // unload all scenes to get the first one => menu
- this.unloadAllScenes();
- break;
-
- // TODO: rewrite the following part
- case BATTLE:
- this.loadScene(new BattleScene(this.game, "battle1"));
- break;
-
- case PAUSE:
- this.loadScene(new PauseScene(this.game, "pause"));
- try {
- this.sceneThread.join();
- } catch (InterruptedException ex) {
- ex.printStackTrace();
- }
- this.unloadScene();
- break;
+ // check if the scene has requested a new scene
+ if (this.scene.isRequestingScene()) {
+ this.loadScene(this.scene.getRequestedScene());
}
+
+ // check for game state change
+ if (this.game.stateChanged()) {
+ // Game.State newState = this.game.waitStateChange();
+ Game.State newState = this.game.getState();
+ Game.State lastState = this.game.getLastState();
+
+ if (lastState == newState) {
+ throw new IllegalStateException();
+ }
- }
+ // if unpaused unload PauseScene
+ if (lastState == Game.State.PAUSE) {
+ this.unloadScene();
+ }
- this.quit();
+ // MAIN_MENU is always the first scene
+ if (newState == Game.State.MAIN_MENU) {
+ this.unloadAllScenes();
+ }
+ // if paused load new PauseScene
+ else if (newState == Game.State.PAUSE) {
+ this.loadScene(new PauseScene(this.game, "pause"));
+ }
+ else if (newState == Game.State.CLOSING) {
+ this.quit();
+ }
+ }
+ }
}
private void loadScene(Scene scene) {
@@ -122,15 +128,16 @@ public class GameWindow extends JFrame implements WindowListener {
}
private void unloadAllScenes() {
- unloadScenes(this.loadedScenes.size() -1);
- }
-
- private void unloadScenes(int count) {
- for (int i = 0; i < count; i++) {
+ while (!this.loadedScenes.empty())
this.unloadScene();
- }
}
+ // private void unloadScenes(int count) {
+ // for (int i = 0; i < count; i++) {
+ // this.unloadScene();
+ // }
+ // }
+
private void unloadScene() {
// close old scene
this.scene.stop();
@@ -144,11 +151,8 @@ public class GameWindow extends JFrame implements WindowListener {
// remove card from UI
this.root.remove(scene);
- // TODO: this should probably be an error
if (this.loadedScenes.empty()) {
- this.scene = null;
- this.sceneThread = null;
- return;
+ throw new IllegalStateException();
}
// load the last scene
@@ -164,6 +168,8 @@ public class GameWindow extends JFrame implements WindowListener {
this.unloadAllScenes();
this.setVisible(false);
this.dispose();
+
+ System.exit(0);
}
/* window listener */
@@ -175,7 +181,8 @@ public class GameWindow extends JFrame implements WindowListener {
@Override
public void windowDeactivated(WindowEvent e) {
- this.game.pause();
+ if (this.game.getState() != Game.State.MAIN_MENU)
+ this.game.pause();
}
@Override public void windowDeiconified(WindowEvent e) {}
diff --git a/src/subconscious/graphics/MapScene.java b/src/subconscious/graphics/MapScene.java
index 87a6012..ed58506 100644
--- a/src/subconscious/graphics/MapScene.java
+++ b/src/subconscious/graphics/MapScene.java
@@ -228,22 +228,27 @@ public abstract class MapScene extends Scene {
int keyCode = e.getKeyCode();
switch (keyCode) {
- case KeyEvent.VK_UP:
- this.pan.y += 10;
- break;
- case KeyEvent.VK_DOWN:
- this.pan.y -= 10;
- break;
- case KeyEvent.VK_LEFT:
- this.pan.x += 10;
- break;
- case KeyEvent.VK_RIGHT:
- this.pan.x -= 10;
- break;
-
- case KeyEvent.VK_ESCAPE:
- this.game.pause();
- break;
+ case KeyEvent.VK_UP:
+ this.pan.y += 10;
+ break;
+ case KeyEvent.VK_DOWN:
+ this.pan.y -= 10;
+ break;
+ case KeyEvent.VK_LEFT:
+ this.pan.x += 10;
+ break;
+ case KeyEvent.VK_RIGHT:
+ this.pan.x -= 10;
+ break;
+
+ case KeyEvent.VK_ESCAPE:
+ this.game.pause();
+ break;
+
+ // TODO: remove
+ case KeyEvent.VK_Q:
+ this.game.setState(Game.State.MAIN_MENU);
+ break;
}
}
diff --git a/src/subconscious/graphics/MenuScene.java b/src/subconscious/graphics/MenuScene.java
index 9c57ca6..ac38d10 100644
--- a/src/subconscious/graphics/MenuScene.java
+++ b/src/subconscious/graphics/MenuScene.java
@@ -54,7 +54,6 @@ public class MenuScene extends Scene implements ActionListener {
if (e.getActionCommand().startsWith("btn")) {
if (e.getActionCommand().equals("btn-exit")) {
this.game.quit();
- this.stop();
return;
}
@@ -63,6 +62,8 @@ public class MenuScene extends Scene implements ActionListener {
// this.loadScene(new MapEditorScene());
} else if (e.getActionCommand().equals("btn-battle")) {
this.game.start();
+ // TODO: change
+ this.requestScene(new BattleScene(this.game, "demobattle"));
}
}
diff --git a/src/subconscious/graphics/PauseScene.java b/src/subconscious/graphics/PauseScene.java
index 6365514..2b5f411 100644
--- a/src/subconscious/graphics/PauseScene.java
+++ b/src/subconscious/graphics/PauseScene.java
@@ -27,16 +27,16 @@ public class PauseScene extends Scene {
}
protected void update(long deltaNanoTime) {
+
}
@Override
- public void keyReleased(KeyEvent e) {
- super.keyReleased(e);
+ public void keyPressed(KeyEvent e) {
+ super.keyPressed(e);
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
this.game.resume();
- this.stop();
}
}
} \ No newline at end of file
diff --git a/src/subconscious/graphics/Scene.java b/src/subconscious/graphics/Scene.java
index 4132ded..7b54a1a 100644
--- a/src/subconscious/graphics/Scene.java
+++ b/src/subconscious/graphics/Scene.java
@@ -45,12 +45,15 @@ public abstract class Scene extends JPanel
// Game is never be cached in the local thread
protected volatile Game game;
+ // TODO: this could become a Queue of scenes to load
+ protected Scene requestedScene = null;
+
protected volatile boolean running;
protected volatile boolean threadPaused;
protected Object pauseLock;
+ protected volatile Dimension canvasSize;
protected BufferStrategy buffer;
- protected Dimension canvasSize;
protected Canvas canvas;
// TODO: make accessible from user settings
@@ -93,6 +96,26 @@ public abstract class Scene extends JPanel
protected abstract void update(long deltaNanoTime);
protected abstract void render(Graphics2D g);
+ /* request scenes */
+ protected void requestScene(Scene sc) {
+ if (this.requestedScene != null)
+ throw new UnsupportedOperationException("only one scene can be requested at once");
+
+ this.requestedScene = sc;
+ }
+
+ public boolean isRequestingScene() {
+ return this.requestedScene != null;
+ }
+
+ public Scene getRequestedScene() {
+ Scene requested = this.requestedScene;
+ this.requestedScene = null;
+
+ return requested;
+ }
+
+ /* runnable implementation */
public void run() {
long beginLoopTime;
long endLoopTime;
@@ -109,9 +132,15 @@ public abstract class Scene extends JPanel
while (!this.canvas.isDisplayable() && running);
// initialize canvas buffer
- this.canvas.createBufferStrategy(2);
- this.buffer = this.canvas.getBufferStrategy();
- this.canvas.requestFocus();
+ // the condition checks because the while above can be interrupted by
+ // changing this.running
+ // TODO: this is because of the MenuScene which hides the canvas
+ // when the scene will be fixed this if can be removed
+ if (this.canvas.isDisplayable()) {
+ this.canvas.createBufferStrategy(2);
+ this.buffer = this.canvas.getBufferStrategy();
+ this.canvas.requestFocus();
+ }
while (running) {
beginLoopTime = System.nanoTime();
@@ -122,9 +151,9 @@ public abstract class Scene extends JPanel
this.render(g);
g.dispose();
// repeat if the rendering buffer contents were restored
- } while (this.buffer.contentsRestored());
+ } while (this.buffer.contentsRestored() && running);
// repeat if the drawing buffer contents were lost
- } while (this.buffer.contentsLost());
+ } while (this.buffer.contentsLost() && running);
try {
this.buffer.show();
@@ -192,7 +221,7 @@ public abstract class Scene extends JPanel
// WARNING: does not always work
// TODO: why doesn't this always work?
public synchronized void updateCanvasSize() {
- this.canvasSize = this.getParent().getSize();
+ this.canvasSize = this.getParent().getParent().getSize();
}
// this one always works