click button sevral times make the game run faster and faster - javascript - javascript

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.

Related

Javascript setInterval functions passing control to each other

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.

requestAnimationFrame runs twice as fast after cancelAnimtionFrame

I've been staring at my code for so long but i don't seem to understand what is happening.
Whenever the game ends, I do a cancelAnimationFrame to stop the game. Then I boot up the menu again.
Now the problem is that when I call requestAnimationFrame again, it seems like the code is calling it two times (the game runs doubly fast).
The following is my code:
This is the startup:
var areaJogo = {
beginGame: function(type) {
//...
this.myReq = requestAnimationFrame(updateArea);
//...
}
}
And this is the main function(for animation):
function updateArea(){
areaJogo.myReq=requestAnimationFrame(updateArea);
//....
if(/*conditionLoseGame*/) {
stop();
}
}
function stop() {
cancelAnimationFrame(areaJogo.myReq);
areaJogo.myReq=undefined;
}
Mind you these are the only times requestAnimationFrame and cancelAnimationFrame are used in the code. Thanks!
I have found the problem.
The reason why it was being called is because I had done a button in JavaScript to start the game.
To do this, I had to do a addeventlistener whenever I booted the menu. What I did wrong was forgetting to do cleareventlistener upon clicking the button.

Javascript e event resetting for Canvas Game

I'm currently building a Tron canvas game based on this code.
it works kinda good, but if I restart the game, two values are getting passed via e.which.
Try to show main code:
function loadGame() {
var e;
document.onkeydown=function(event){e=event};
function intervall() {
function check() {
//Function for drawing Tron
}
var key = e.which;
if(key == 87) { //W and so one
check();
}
}
var timer = setInterval(intervall,900)
}
If I lose, and call loadGame() again, it works great.
It does not if I call loadGame() while Game is still running.
I uploaded a live demo here:
http://wernersbacher.de/tron.html
Thanks for any help!
You're getting two values because when you restart the game, the old interval loop is still running when you start a new one.
I see you're trying to stop the old loop here:
if(hard) {
clearInterval(timer);
}
However, because the variable 'timer' was declared in a different invocation of the loadGame function, this newly invoked loadGame function has no access to it.
You can see this in action by logging the variable to the console from the new loadGame invocation:
function loadGame(hard) {
if(hard) {
console.log(timer);
}
You'll see it returns undefined.
If any of this sounds confusing to you, you might want to learn more about Function scope.
A solution is to declare the 'time' variable outside the loadGame function, in the global scope:
var time;
function loadGame(hard) {
/* the rest of your code */
timer = setInterval(intervall,9)
}
That way, the new instance of the loadGame function which is called when you press the 'Load game' button has access to the old timer and can stop it before starting a new one.
Incidentally, completely reloading everything, including creating a new canvas element and destroying the old one, seems a bit unnecessary. Why not simply clear() the canvas and reset the player position to the start position? You don't even need to restart the timer using that method.

Javascript code execution pausing issue

I'm making a little game, and i was making a character death sequence when I ran into this problem. The
eloop(setInterval(e_seq,100)
plays the ending sequence. After that, I want execution to stop for a second before displaying the score and stuff.
But the current sleep method i'm using pauses the entire execution, including the loop, while I want the loop to be completed before pausing the game for a second.
The place where sleep is called: (inside the main gameloop)
eloop=setInterval(e_seq,100);
sleep(1000);
The sleep method:
function sleep(msec)
{
var time= new Date().getTime();
while(time+msec>= new Date().getTime())
{}
}
any solutions?
PS: calling sleep at the end of the gameloop (inside an if condition checker) was pausing the execution before the gameloop began for some reason....
I think you probably want something more along the lines of
setTimeout(function () { e_seq(); }, 1000);
This would wait one second and then execute the e_seq() function, which I think is the purpose of your code, although it's open to a little interpretation...
Did you try just the setInterval?
setInterval(function(){ ... }, 3000);
i have tried something
var looper;
var looptime = 2000;
var doloop = function(){
console.log("doing this")
}
function begin(callthis){
looper = setInterval(callthis,looptime);
}
function pause(callthis,sleeptime){
clearInterval(looper);
setTimeout(function(){
looper = setInterval(callthis,looptime);
},sleeptime)
}
using like:
begin(doloop);
and pause with
pause(doloop,10000);
You need a callback when using "sleep" functionality. The sleep concept does not exist in JavaScript.
You should not use a busy-loop as you do as that will hold off any other processes as well as JavaScript is single threaded (incl. DOM updates). Use a timer instead but as timers are asynchronous you will have to use the mentioned callback.
It's not so complicated -
Modify the sleep method like this:
function sleep(timeout, callback) {
setTimout(callback, timeout); // or just call this directly...
}
(as you can see it's a bit excess with the wrapper so I would recommend just calling the setTimeout() directly).
Now you can implement your score screen into a function:
function showScores() {
...
}
Then when you want to delay a second before showing the score screen do:
sleep(1000, showScores);
or simply:
setTimeout(showScores, 1000);
Note that the rest of your code will continue after calling this method so make sure all code resides in functions so you can use them as callbacks.

Watching setTimeout loops so that only one is running at a time

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.

Categories