diff --git a/html/src/main/java/com/agifans/agile/gwt/GwtAgileRunner.java b/html/src/main/java/com/agifans/agile/gwt/GwtAgileRunner.java
index 10fff31..04f0558 100644
--- a/html/src/main/java/com/agifans/agile/gwt/GwtAgileRunner.java
+++ b/html/src/main/java/com/agifans/agile/gwt/GwtAgileRunner.java
@@ -33,15 +33,6 @@ public class GwtAgileRunner extends AgileRunner {
*/
private Worker worker;
- /**
- * Indicates that the worker is currently executing the tick, i.e. a single interpretation
- * cycle. This flag exists because there are some AGI commands that wait for something to
- * happen before continuing. For example, a print window will stay up for a defined timeout
- * period or until a key is pressed. In such cases, the thread can be performing a tick
- * for the duration of what would normally be many ticks.
- */
- private boolean inTick;
-
/**
* Holds a reference to the Audio HTML element that is playing the current sound, or null
* if there is no sound being played. It is not possible in AGI to play two sounds at
@@ -102,13 +93,6 @@ public void onMessage(MessageEvent event) {
JavaScriptObject eventObject = event.getDataAsObject();
switch (getEventType(eventObject)) {
- case "TickComplete":
- // Allows the next tick to be triggered. We only allow one tick at
- // a time, otherwise the web worker would get a flood of Tick messages
- // when it is busy waiting for a key or similar.
- inTick = false;
- break;
-
case "QuitGame":
// This message is sent from the worker when the game has ended, usually
// due to the user quitting the game.
@@ -247,13 +231,9 @@ private void stopCurrentSound() {
@Override
public void animationTick() {
- if (!inTick && (worker != null)) {
- inTick = true; // NOTE: Set to false by "TickComplete" message.
-
- // Send a message to the web worker to tell it to perform an animation tick,
- // but only if it isn't already in an animation tick.
- worker.postObject("Tick", JavaScriptObject.createObject());
- }
+ // Nothing to do for GWT version. The web worker triggers itself for animation
+ // ticks, using the total ticks that is set by UI thread to determine when to
+ // run.
}
@Override
@@ -264,7 +244,6 @@ public void stop() {
stopCurrentSound();
pixelData.clearState();
variableData.clearState();
- inTick = false;
stopped = true;
}
diff --git a/html/src/main/java/com/agifans/agile/worker/AgileWebWorker.java b/html/src/main/java/com/agifans/agile/worker/AgileWebWorker.java
index 82969eb..0ce1f9d 100644
--- a/html/src/main/java/com/agifans/agile/worker/AgileWebWorker.java
+++ b/html/src/main/java/com/agifans/agile/worker/AgileWebWorker.java
@@ -78,6 +78,11 @@ public class AgileWebWorker extends DedicatedWorkerEntryPoint implements Message
*/
private OPFSGameFiles opfsGameFiles;
+ /**
+ * The total tick count at the time of the last animation tick.
+ */
+ private int lastTotalTickCount;
+
/**
* Incoming messages from the UI thread are for two purposes: One is to set things
* up, and then once both sides are up and running, the UI thread then starts sending
@@ -122,18 +127,8 @@ public void onMessage(MessageEvent event) {
interpreter = new Interpreter(
game, userInput, wavePlayer, savedGameStore,
pixelData, variableData);
- break;
-
- case "Tick":
- try {
- // Perform one animation tick.
- interpreter.animationTick();
- // Then notify the UI thread that the tick is complete.
- postObject("TickComplete", JavaScriptObject.createObject());
- } catch (QuitAction qa) {
- // The user has quit the game, so notify the UI thread of this.
- postObject("QuitGame", JavaScriptObject.createObject());
- }
+ lastTotalTickCount = variableData.getTotalTicks();
+ performAnimationTick(0);
break;
default:
@@ -141,6 +136,37 @@ public void onMessage(MessageEvent event) {
}
}
+ public void performAnimationTick(double timestamp) {
+ try {
+ int currentTotalTicks = variableData.getTotalTicks();
+ int numOfTicksToRun = (currentTotalTicks - this.lastTotalTickCount);
+ this.lastTotalTickCount = currentTotalTicks;
+
+ // Catch up with ticks, if we are behind.
+ while ((numOfTicksToRun-- > 0) && (variableData.getTotalTicks() == currentTotalTicks)) {
+ // Perform one animation tick.
+ interpreter.animationTick();
+ }
+
+ requestNextAnimationFrame();
+
+ } catch (QuitAction qa) {
+ // The user has quit the game, so notify the UI thread of this.
+ postObject("QuitGame", JavaScriptObject.createObject());
+ }
+ }
+
+ public native void exportPerformAnimationTick() /*-{
+ var that = this;
+ $self.performAnimationTick = $entry(function(timestamp) {
+ that.@com.agifans.agile.worker.AgileWebWorker::performAnimationTick(D)(timestamp);
+ });
+ }-*/;
+
+ private native void requestNextAnimationFrame()/*-{
+ $self.requestAnimationFrame($self.performAnimationTick);
+ }-*/;
+
private native String getEventType(JavaScriptObject obj)/*-{
return obj.name;
}-*/;
@@ -176,6 +202,8 @@ protected final void setOnMessage(MessageHandler messageHandler) {
@Override
public void onWorkerLoad() {
+ exportPerformAnimationTick();
+
this.scope = DedicatedWorkerGlobalScope.get();
this.opfsGameFiles = new OPFSGameFiles();
@@ -183,4 +211,8 @@ public void onWorkerLoad() {
this.setOnMessage(this);
}
+
+ private final native void logToJSConsole(String message)/*-{
+ console.log(message);
+ }-*/;
}