Hello again,
I have run into a bug with my internal game loop, and while I've already come up with a couple of ways I could fix it, I'd still like some advice on the
cleanest way to go about it.
For the curious, a WIP of the engine mechanics I'm working on can be seen here:
http://rokiyo.net/games/cetacea/Story%20Engine.html
@TheMadExile, I would really appreciate your thoughts on the below, though I also welcome any advice anyone else has to offer too.
Issue summary
To start an internal game loop at around 30 ticks per second, I run the following code within
StoryInit (because it seems to be one of the last things executed during story loading):
<<run window.tickTimer = window.setInterval(window.gametick, 33)>>
When calling
UI.restart(), the restart is performed without a page load, which means the above timer is not cleared. This causes two primary issues:
- Multiple timers running at once, all of them calling window.gametick more often than expected.
- window.gametick getting called during story initialization, before specific story variables and DOM elements have started existing.
Potential solutions
I can think of several ways to address some of these issues (though none of them strike me as ideal):
- A singleton-style approach: <<run window.tickTimer = window.tickTimer || window.setInterval(window.gametick, 33)>>
- Hook into an Engine.restart() to clear the interval, possibly by rebuilding a custom UI.restart() dialog via the API to call some cleanup code if the user confirms the restart (e.g. clearInterval(window.tickTimer)).
- Wrap window.gametick in a try/catch block to silently discard any errors that occur from it running on load.
- Something involving the options parameter on UI.restart()? I don't understand the documentation within Dialog.addClickHandler() enough to know if I've missed something obvious here.
Conclusion
So yeah, there are a few ways to go about it, but all of them strike me as a little bit "hacky". I'd really appreciate a second opinion on a better approach to this.
The other thought on my mind is... If intervals aren't being cleared during
Engine.restart(), does that mean all the other stuff I'm attaching to
window isn't getting cleaned up either? I mean, I guess it all gets overwritten when the story JavaScript gets rerun, but I'm wondering if it would be cleaner to have some kind of
shutdown task object that only gets called during a restart?
Comments
1. Story Javascript area:
2. StoryInit passage ... anytime you don't want the contents of the gametick function to be executed simply set the setup.initialising variable to true.
note: rename the variable to anything that makes sense to you.
I've narrowed the specific error down to variables() getting reinitialised almost immediately after the user clicks on restart. Enough time is passing between that and the Story Javascript getting rerun that setup.gametick is getting called while variables() is empty and while setup.initialising is still false.
That being said, I have moved all my stuff over from window to setup and started using the code to only create the interval if it doesn't already exist, so thanks for those tips.
For the time being, I'm just wrapping my gametick inside a try/catch and discarding the errors, but I'm still on the hunt for a more elegant solution than that.
It really doesn't matter which you use, however, since you are performing an assignment, I'd use <<set>> there, rather than <<run>>—if for no other reason than semantics.
Also, is there some particular reason you're doing that in the StoryInit special passage, rather than the Story JavaScript, which is where I'd expect to see something like that defined?
(emphasis mine) That is incorrect. The dialog created by UI.restart() calls Engine.restart(), which—aside from various bookkeeping—does reload the page, by calling window.location.reload().
You're not clobbering the window.location API are you?
Just to ensure it happens dead last, after everything else has been initialised. StoryInit appears to get processed after the Story JavaScript, and my game tick makes use of story variables via a call to variables().
No, I was just misunderstanding what I was looking at, my apologies. I did realise a page reload was occuring when I was trying out greyelf's suggestion earlier, but forgot to mention it when I responded.
Based on comments from you and greyelf, I have boiled down my root cause to this:
Is the crux of my issue just that I'm directly referencing and manipulating story variables via JavaScript? Or am I just making too big a deal out of an edge case and should just let exception handling take care of it?
May we see its code?
This just the gametick function, let me know if you want to see the code for other functions called by it.