0

I have a game loop and it basically is this: function game(){init();setInterval(draw, 30);} but when a player wins I want to call Win() which clears the interval and restart. What's the best way to tackle this in javascript? Since the setInterval() is asynch I've already fallen out of game() by this point. So do I add a busy loop: function game(){while(1){init();setInterval(draw, 30);while(!Win);}}? There's no good way to sleep() currently is there? Is there a way to call game() inside Win() without making the call stack of arbitrary size? What's the best way to handle this situation?

6
  • You can set the timer to a variable such as var timer = setInterval(...) then clear the timer by calling clearInterval(timer). However, in my opinion, anytime you're using a timer you should consider the possibility that there's another way to accomplish your goal. Commented Mar 13, 2016 at 6:48
  • Can't you call win() from wherever you handle your game's logic? draw() looks like the place, but the name doesn't imply it Commented Mar 13, 2016 at 6:49
  • you could use delay(milliseconds) Commented Mar 13, 2016 at 6:56
  • @JSelser you're right it is in draw(). The logic was light enough I didn't bother with anything else. In the real code game() is actually called init() as well but I was just throwing up a minimal example. But my question about the call stack enters at this point. Doesn't it grow, and can I avoid that? Commented Mar 13, 2016 at 7:05
  • @nateyolles I'm clearing in Win() but your comment doesn't really address the question. How would you reboot after such a clear without growing call stack or busy looping? Commented Mar 13, 2016 at 7:06

1 Answer 1

3

You can use named interval:

var time;
function game(){
     init();
     time = setInterval(function (){
          draw();
     }, 30);
}

win(){
    if(time){
        clearInterval(time); // clear the interval
        game(); // start the game again.
    }
}

Now you have to call this win function, whenever user wins and start the game.

Sign up to request clarification or add additional context in comments.

14 Comments

@Black ensure that you're only calling win when appropriate; you're keeping a closure reference to win within draw, and calling win with a predicate. Your stack will increase by whatever win( ) will increase it by, but your actual callstack is going to be drained at the bottom of draw, and a new one will take over, in the new interval period. JS game-engine or otherwise polling loops are'nt easy to initially grasp. But think of it like an implicit sleep at the bottom of draw, where the callstack is gone and the browser gets the thread for render/IO work, then gives you a new stack.
@Black your busy loop will actually lock the thread, and thus never give it back to the browser, and thus never allow you to render (or enter input, or even allow you to refresh the page in certain browsers). Rely on the implicit sleep and the callback. Ideally with requestAnimationFrame rather than setTimeout || setInterval, but let the stack drain, quickly and without trying to keep the thread locked, nonetheless.
@Black theoretically, yes... ...you may have several frames that go by, in that case, where the game should already be over. And you'll need a global shouldReboot that gets set to true or whathaveyou, if you're relying on the checkReboot. A better solution might be to do something like var pid = setInterval(tick, 1000/60); function tick () { var isOver = draw(); if (isOver) { win(pid); } } And not each interval. That'd be a wrong way of thinking about it. The call-stack exists until there are no more synchronous calls on the stack. set(Interval|Timeout), AJAX, Promises... async
@Black when the host environment decides it (the browser's tab-manager, or whatever is hosting the JS machine) it starts up the execution context for whatever stack of synchronous calls has been scheduled next. If you had previously fired a timeout, then it will call the function that was registered in that timeout, and it will run until the stack has been exhausted; at that point, the thread reverts back to the host for all of the browser/server/app-container stuff. The host will then set off the next registered stack in JS, et cetera.
@Black assume next is the name of the function in my setInterval example (it’s been taken out given a name, and passed as a reference): game->pid=setInterval(next) ... ... next()->over=draw() === false ... ... next()->over=draw() === false ... ... next()->over=draw() === true win()->clearInterval(pid); restart()->game() Each ... ... is the exhaustion of synchronous calls, and the eventual rescheduling of another entry, into next
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.