I'm making a game in JS and I'm fairly new to it all. I have created a main loop inside a setInterval, like this:
int = setInterval(() => {
Do game stuff, keyboard input, update sprite positions, etc...
Update the screen
},FPS_interval);
But I want this function to be able to pass control to another function that is also in a setInterval. So when I pass I want to stop the interval trigger on this main function and call the other function on a setInterval. When that function has finished I want to come back to this function, again on a setInterval. I'm trying things like this:
int = setInterval(() => {
Do game stuff, keyboard input, update sprite positions, etc...
If you die, go to game over screen gameOver();
Update the screen
},FPS_interval);
function gameOver(){
clearInterval(int);
int = setInterval(() => {
Do game over stuff
when done, return to main loop.
}, FPS_interval);
}
One issue I have is when the main loop calls the gameOver function, although the gameOver function clears the interval, the main loop continues to execute to the bottom.
Another way of looking at this is I just want to be able to pass between functions, some of them with separate loops, and keep the screen updating at regular intervals.
Is there a cleaner way? I'm sure there must be!
Probably you're looking for a semaphore variable. Try to declare one and once you get in the gameover set that semaphore and in the main set_interval execute istructions after the gameover call only if the semaphore is not setted.
Related
As part of my studies I build the game "Space Invaders" in javascript by using canvas.
Before the beginning of the game, the main page is loaded and waiting to click on new game button. When i clicked on this button, the game begins to run properly and there are no problems at all. (the game runs through a recursive function that call to functions update() and render() -see code-...)
The problem comes when during the run of the game i push this button again. What happens is that the game run faster and when i clicked on it several times the game run faster and faster...
i dont now if its because the cycle of interval was not clear itself or maybe its because run() function call itself again and cause to loop into the recursive functions.
thanks a lot.
//----------------------------------------//
//this function called when i pressed in newGame button
function startGame()
{
clearInterval(timeInterval);
run();
// run function - run the recursive function below
timeInterval = setInterval(randEnemyShots,frequencyShot);
// randEnemyShots function - choose one enemey from all enemies to shot
// frequencyShot variable - this is the frequqncy of shots
}
//----------------------------------------//
function run()
{
var loop=function(){
if(gameRuning)
{
update();
// update function - all the logic of game
render();
// render function - drawing the game
window.requestAnimationFrame(loop,canvas);
}
};
window.requestAnimationFrame(loop,canvas);
}
//-----------------------------------------------------------------------------------------------------------------------//
The problem is that when you click the 'Start' button you are calling the run() function again which is effectively doubling the speed of the game.
The run() function should be called only once in the game initialisation so that the game loop can run indefinitely.
function gameInit(){
//Initialisation code here
run(); //Start the game loop only once
}
function startGame() {
//Handle 'Start' button click
clearInterval(timeInterval);
timeInterval = setInterval(randEnemyShots,frequencyShot);
}
You can then use the gameRuning value to 'pause' the loop if you set to false.
It's better you used setTimeout (with checking) rather than setInterval. Since the behaviour and cost of setInterval usually weird.
My program has two buttons. One is for execute other program by using jquery load function. Whenever I click execute button, it runs some other program abc.php using load function for n times, with some time gap like k mins. These n and k will be filled with html inputs. Using jquery, will retrieve these and passing to that program file in url.
To call this function setTimeout was used.
Second one is for cancel execution.
Now my doubt is, suppose I want to stop that execution with cancel button. Is there any way to stop it ?
I would do this using boolean variable.
For example: Consider a method, perform logging.
fun () {
console.log("prints");
}
I would change it has
fun (isExecute) {
if (isExecute) {
console.log("prints");
}
}
Run fun (true); cancel fun (false);
Updates:
It seems you use setTimeout(), then it is too easy without above approach.
Run var inter = setTimeout(fun); cancel clearTimeout(inter);
FYI: The reason for assigning to a variable inter is then only you can clear this time interval.
set time for function:
timer = setTimeout(function(){$('#submenu').hide();},5000);
stop a function
clearTimeout(timer);
Is there anything like a "dispose" function or "thread shutdown hook" for a specific thread running via setInterval?
(function () {
var _setInterval = window.setInterval,
_clearInterval = window.clearInterval;
window.setInterval = function (fn, time) {
//Implement your hooks here, hopefully without side effects
return _setInterval(fn, time);
};
window.clearInterval = function (id) {
//Implement your hooks here, hopefully without side effects
return _clearInterval(id);
};
})()
From comments it became clear that you don't need hooking because you are in an environment that you control. In that case you can just write wrapper functions like myClearInterval etc. with same principle.
First off, as others have said, there are no threads in javascript (other than WebWorkers, but I don't think that's what you're talking about here.
All setInterval() does is call a function on a repeated basis - it isn't a thread, it isn't pre-emptive and it won't get called until all other javascript has stopped executing so the timer event can be processed. If your issue is that you want to dispose of some state when the interval is cleared so it will no longer be called, then you have two options:
1) You can use a javascript closure to store your state and when the interval is cleared, the closure will automatically be released.
2) You can create your own version of clearInterval that both clears the interval timer and cleans up your state.
The javascript closure option would look like this:
var interval;
function startMyInterval() {
// sample state variables
var state1 = 0;
var state2 = [];
var state3 = {whatever: "whatever"};
interval = setInterval(function() {
// javascript code here that can reference state1, state2 and state3
}, 1000);
}
// then some time later when you want to stop the interval, you call clearInterval
// the closure is released and all the state variables are freed automatically
clearInterval(interval);
Or, if you want to do any other things when the interval is cleared, you can make your own function for clearing the interval that will not only release the closure, but also let you run any other code.
function clearMyInterval() {
clearInterval(interval);
// do any other cleanup you want to when the interval is stopped
}
I see that others have suggested hooking/replacing window.clearInterval() with your own function, but I prefer not to do that because it is unclear if that is a supported/documented feature and some system functions (more and more of them over time) are becoming protected so they cannot be replaced.
We want to know if it is possible to have a function using jQuery to inspect a number of elements and, depending on the types assigned to them by one click, perform other functions. Basically, a function that would run forever, while the user does not refresh the page.
The idea is not to depend on events clicks to perform a function, but the classes assigned to a specific element.
For example:
$("td.gantt").each(function() {
if($(this).hasClass("oper")) {
//execute a serie of functions
}
if($(this).hasClass("preop")) {
//execute a serie of functions
}
});
The above is executed once, and we need to run all the time.
// define a function...
function ganttEach() {
$("td.gantt").each(function() {
// ...
});
}
// ...repeat it once every second
window.setInterval(ganttEach, 1000);
You can't "let it run all the time" (like, in a while(true) loop) because JavaScript is single-threaded and blocking the thread means your other code will never run. setInterval() makes sure there are necessary "gaps" for other code to execute.
setInterval() returns an ID that you can store in a variable and feed to clearInterval() at some point to make it stop again.
If you want to make sure that every new iteration of your function starts only after the previous one has really finished, use setTimeout() instead:
// define a self-repeating function...
function ganttEach() {
$("td.gantt").each(function() {
// ...
});
window.setTimeout(ganttEach, 1000); // calls itself again in one second
}
// ...initiate self-repeating function
ganttEach();
You should probably include some way to stop the endless repetition here as well, like introducing a flag that's checked before the setTimeout() call.
You can run your check every few milliseconds, say 50ms, using setInterval
window.setInterval (function () {
// do checks here
}, 50);
You might end up using a lot of CPU power if your checks are too frequent, or too complicated.
It is possible, with setInterval. My advice would be to select the element outside of the repeating function so as to minimize the overhead.
An infinite loop would lock the browser UI, as it is a single threaded environment. Set interval, however let you add actions to the UI stack which will be executed after a given period of time. You can specify this period in the second parameter of setInterval.
// select the element outside
// to minimize overhead
$gantt = $("td.gantt");
// define a repeating action
setInterval(function() {
$gantt.each(function() {
if($(this).hasClass("oper")) {
//execute a serie of functions
}
if($(this).hasClass("preop")) {
//execute a serie of functions
}
});
}, 100); // repeat interval: 100ms
I am not sure exactly what you are trying to do, but have you tried setInterval? It will keep running if that is what you really want.
window.setInterval(function () {
// add your jQuery here
}, 100);
I'm creating a content rotator in jQuery. 5 items total. Item 1 fades in, pauses 10 seconds, fades out, then item 2 fades in. Repeat.
Simple enough. Using setTimeout I can call a set of functions that create a loop and will repeat the process indefinitely.
I now want to add the ability to interrupt this rotator at any time by clicking on a navigation element to jump directly to one of the content items.
I originally started going down the path of pinging a variable constantly (say every half second) that would check to see if a navigation element was clicked and, if so, abandon the loop, then restart the loop based on the item that was clicked.
The challenge I ran into was how to actually ping a variable via a timer. The solution is to dive into JavaScript closures...which are a little over my head but definitely something I need to delve into more.
However, in the process of that, I came up with an alternative option that actually seems to be better performance-wise (theoretically, at least). I have a sample running here:
http://jsbin.com/uxupi/14
(It's using console.log so have fireBug running)
Sample script:
$(document).ready(function(){
var loopCount = 0;
$('p#hello').click(function(){
loopCount++;
doThatThing(loopCount);
})
function doThatOtherThing(currentLoopCount) {
console.log('doThatOtherThing-'+currentLoopCount);
if(currentLoopCount==loopCount){
setTimeout(function(){doThatThing(currentLoopCount)},5000)
}
}
function doThatThing(currentLoopCount) {
console.log('doThatThing-'+currentLoopCount);
if(currentLoopCount==loopCount){
setTimeout(function(){doThatOtherThing(currentLoopCount)},5000);
}
}
})
The logic being that every click of the trigger element will kick off the loop passing into itself a variable equal to the current value of the global variable. That variable gets passed back and forth between the functions in the loop.
Each click of the trigger also increments the global variable so that subsequent calls of the loop have a unique local variable.
Then, within the loop, before the next step of each loop is called, it checks to see if the variable it has still matches the global variable. If not, it knows that a new loop has already been activated so it just ends the existing loop.
Thoughts on this? Valid solution? Better options? Caveats? Dangers?
UPDATE:
I'm using John's suggestion below via the clearTimeout option.
However, I can't quite get it to work. The logic is as such:
var slideNumber = 0;
var timeout = null;
function startLoop(slideNumber) {
//... code is here to do stuff here to set up the slide based on slideNumber...
slideFadeIn()
}
function continueCheck() {
if (timeout != null) {
// cancel the scheduled task.
clearTimeout(timeout);
timeout = null;
return false;
} else {
return true;
}
};
function slideFadeIn() {
if (continueCheck){
// a new loop hasn't been called yet so proceed...
$mySlide.fadeIn(fade, function() {
timeout = setTimeout(slideFadeOut,display);
});
}
};
function slideFadeOut() {
if (continueCheck){
// a new loop hasn't been called yet so proceed...
slideNumber=slideNumber+1;
$mySlide.fadeOut(fade, function() {
//... code is here to check if I'm on the last slide and reset to #1...
timeout = setTimeout(function(){startLoop(slideNumber)},100);
});
}
};
startLoop(slideNumber);
The above kicks of the looping.
I then have navigation items that, when clicked, I want the above loop to stop, then restart with a new beginning slide:
$(myNav).click(function(){
clearTimeout(timeout);
timeout = null;
startLoop(thisItem);
})
If I comment out 'startLoop...' from the click event, it, indeed, stops the initial loop. However, if I leave that last line in, it doesn't actually stop the initial loop. Why? What happens is that both loops seem to run in parallel for a period.
So, when I click my navigation, clearTimeout is called, which clears it.
What you should do is save the handle returned by setTimeout and clear it with clearTimeout to interrupt the rotator.
var timeout = null;
function doThatThing() {
/* Do that thing. */
// Schedule next call.
timeout = setTimeout(doThatOtherThing, 5000);
}
function doThatOtherThing() {
/* Do that other thing. */
// Schedule next call.
timeout = setTimeout(doThatThing, 5000);
}
function interruptThings() {
if (timeout != null) {
// Never mind, cancel the scheduled task.
clearTimeout(timeout);
timeout = null;
}
}
When a navigation element is clicked simply call interruptThings(). The nice part is that it will take effect immediately and you don't need to do any polling or anything else complicated.