Javascript setTimeout scope referencing wrong variables - javascript

I've written a little function to loop through a sprite sheet. Within the function I have a settimeout which cycles through the frames. Upon the last frame, the timeout is cleared, the counter is set to zero - and the animation begins again.
This works fine with one animation, but when I try and call many animations - they all start but fail to loop, apart from designSprite which loops quite happily. I call the designSprite anim last....
So I'm guessing the problem is due to variables being overwritten when I call a new intance of the function - setTimeOut referencing the new variables?? I've confused myself. I've had a stab at trying to fix it, but keep failing.
Thanks,
Rob
// Arrays to hold our sprite coordinates.
var animationSprite=[{"X":"-2","Y":"-2"},........ etc etc ];
var mediaSprite=[{"X":"-2","Y":"-2"},........ etc etc ];
var filmSprite=[{"X":"-2","Y":"-2"},........ etc etc ];
var designSprite=[{"X":"-2","Y":"-2"},........ etc etc ];
// call the loopAnim function, passing in the sprite array, and id of the div
loopAnim(animationSprite ,'#animationFrame')
loopAnim(mediaSprite ,'#mediaFrame')
loopAnim(filmSprite ,'#filmFrame')
loopAnim(designSprite ,'#designFrame')
function loopAnim(sprite , frameID) {
var totalFrames = sprite.length; // count how many 'frames' are in our sprites array.
var count = 0; // set up a basic counter to count which frame we're on.
var theLoop = function(){
// Move the background position of our frame by reading the X & Y co-ordinates from the sprites array.
$(frameID).css("background-position" , sprite[count].X + "px " + sprite[count].Y + "px");
count++; // increment the frame by 1 on each loop
// if count is LESS than total number of frames, set a timeout to keep running the "theLoop" function
if (count < totalFrames){
setAnim = setTimeout(theLoop, 60);
// if count is greater than the total number of frames - clear our timeout. Reset the counter back to zero, and then run our loop function again
} else {
clearTimeout(setAnim);
count = 0;
theLoop();
}
}
theLoop();
}

setAnim looks like it wasn't declared, meaning it's a global variable. This means all your calls to loopAnim are using and overwriting the same timer ID reference.

Related

Creating a for loop that loops over and over =

So I have a weird problem (as I can do this using dummy code, but cannot make it work in my actual code) -
The concept is simple - I need a for loop that upon hitting its max "I" number reverts "I" to 0 again and creates a loop over and over -
DUMMY CODE:
for(i=0;i<10;i++){
console.log(i);
if(i === 10){
i = 0
}
}
Now for the longer code (sorry)
function reviewF(){
// add ID to each of the objects
reviews.forEach((e, i)=>{
e.id = i
})
// get the elements to be populated on page
var name = document.querySelector('p.name');
var date = document.querySelector('p.date');
var rating = document.querySelector('.rating_stars');
var review = document.querySelector('p.review_content_text');
// reverse the array - so the newest reviews are shown first (this is due to how the reviews where downloaded)
var reviewBack = reviews.slice(0).reverse();
// start the loop - go over each array - take its details and apply it to the elements
/**
* THIS IS WHAT I WOULD LIKE TO LOOP OVER FOREVER
*
* **/
for (let i = 0; i < reviewBack.length; i++) {
(function(index) {
setTimeout(function() {
// document.getElementById('reviews').classList.remove('slideOut')
name.classList.remove('slideOut')
date.classList.remove('slideOut')
rating.classList.remove('slideOut')
review.classList.remove('slideOut')
name.classList.add('slideIn')
date.classList.add('slideIn')
rating.classList.add('slideIn')
review.classList.add('slideIn')
name.innerHTML = reviewBack[i].aditional_info_name;
date.innerHTML = reviewBack[i].Date;
rating.innerHTML = '';
review.innerHTML = reviewBack[i].aditional_info_short_testimonial;
if(reviewBack[i].aditional_info_short_testimonial === 'none'){
reviewBack.innerHTML='';
}
var numberOfStars = reviewBack[i].aditional_info_rating;
for(i=0;i<numberOfStars;i++){
var star = document.createElement('p');
star.className="stars";
rating.appendChild(star);
}
setTimeout(function(){
// document.getElementById('reviews').classList.add('slideOut')
name.classList.add('slideOut')
date.classList.add('slideOut')
rating.classList.add('slideOut')
review.classList.add('slideOut')
},9600)
}, i * 10000)
})(i);
// should create a infinite loop
}
console.log('Loop A')
}
// both functions are running as they should but the time out function for the delay of the transition is not?
reviewF();
EDITS >>>>>>>>
Ok so I have found a hack and slash way to fix the issue - but its not dry code and not good code but it works.....
this might make the desiered effect easier to understand
reviewF(); // <<< this is the init function
// this init2 function for the reviews waits until the reviews have run then
// calls it again
setTimeout(function(){
reviewF();
}, reviews.length*1000)
// this version of the innit doubles the number of reviews and calls it after that amount of time
setTimeout(function(){
reviewF();
}, (reviews.length*2)*1000)
From trying a bunch of different methods to solve this issue something I noticed was when I placed a console.log('Finished') at the end of the function and called it twice in a row (trying to stack the functions running..... yes I know a horrid and blunt way to try and solve the issue but I had gotten to that point) - it called by console.log's while the function was still running (i.e. the set time out section had not finished) - could this have something to do with it.
My apologies for the rough code.
Any help here would be really great as my own attempts to solve this have fallen short and I believe I might have missed something in how the code runs?
Warm regards,
W
Why not simply nest this for loop inside a do/while?
var looping = True
do {
for(i=0;i<10;i++){
console.log(i);
}
if (someEndCondition) {
looping = False;
}
}
while (looping);
I would think that resetting your loop would be as simple as setting "i = 0" like in the dummy code. So try putting the following into your code at the end of the for loop:
if(i === 10){
i = 0;
}

Matter.js: Method to count how many times that an object has rotated?

I am creating a project in which a body is picked up and thrown by the user (with a mouse constraint). The body is set so that it can pivot about the constrain point. I need to find out, from the moment that it is let go, how many times it fully rotates (+-360 degrees) before landing. Reading the documentation, the only thing that I could find regarding the rotation was Matter.Body.rotate() which actually just sets the rotation of a body instead of recording it. How should I go about this?
Basically: How can I count an objects rotations?
This worked for me tbh:
var rad = 6.28;
var nrad = -6.28;
Events.on(engine, "tick", function () {
if(boxA.angle > rad){
rad+=6.28;
nrad+=6.28;
hrt +=1;
//hrt is the rotation c0unter
}
if (boxA.angle < nrad){
nrad-=6.28;
rad-=6.28;
hrt +=1;
}
rnum.innerHTML = "Spins: " + hrt;
fnum.innerHTML = fcounter; });

setInterval() speeds up when using multiple from object method

I have been having problems with my setIntervals(). I know these issues appear a lot but I can't seem to work out what the exact problem with my implementation is. Every time I instantiate a new Obstacle() it clears the set interval used to rotate the instance of the obstacle, and the next instantiation of the obstacle seem to rotate twice as fast! I'm sure it's to do with scope but I'm a relative beginner so I'm not quite sure what's going on here. Any more info can be provided.
var obstacleCount = 1;
function Obstacle(){
this.angle = 0;
this.id = obstacleCount;
this.elPrefix = "cookie-";
this.el = '.' + this.elPrefix + this.id;
$('#game-wrapper').append('<div class="' + this.elPrefix + this.id + '"></div>');
obstacleCount += 1;
}
var intervals = new Array();
Obstacle.prototype.roll = function() {
self = this;
intervals[self.id] = setInterval(function(){
self.angle -= 3;
$(self.el).rotate(self.angle);
}, 5);
$(self.el).animate({
right: 1000
}, 4000, 'linear', function(){
$(self.el).remove();
clearInterval(intervals[self.id]);
});
};
var obstacles = new Array();
setInterval(function(){
obstacleID = obstacleCount;
obstacles[obstacleID] = new Obstacle();
obstacles[obstacleID].roll();
}, 1000);
In most games there is a single update loop that handles all of the update logic for your game. I would recommend using a single interval in which all objects are updated instead of giving each object it's own scheduled update via setInterval. You gain a few advantages from the update loop method:
Don't have to keep track of intervals.
Since since setInterval is not consistant with timing (it fires when the main script is finished executing and has some extra time before the next go around, but only if it's interval time is up. This means you cannot completely rely on it's timing being what you asked it to be.) you are better off having all your objects updated at the time so you are as consistant as you can be.
General pseudo code to get you started:
initialize objects
add all objects to an array
setInterval(updateObjects, 30);
updateObjects(){
for each object in array
object.roll();
}

JavaScript - Timer Initiation

I'm trying to make my enemy fire every second. Right now - it's every frame.
Within my enemy object, I have a piece of code that is initiated when the player is within range:
this.shotBullet = false;
var object = this;
object.Fire();
This is the enemy fire function:
this.Fire = function(){
console.debug("Firing | Shot: " + this.shotBullet);
if(!this.shotBullet){
if(this.weapon == "pistol")
PistolEnemy(this);
this.shotBullet = true;
}
};
And my PistolEnemy function:
PistolEnemy = function(operator){
var user = operator;
console.debug("user:" + user.tag);
var bulletDamage = 1;
var bulletSpeed = 20;
var b = new Rectangle( user.x + (user.width / 2) - 4, user.y + (user.height / 2) - 4, 8, 8);
var velocityInstance = new Vector2(0, 0);
velocityInstance.x = Math.cos(user.rotation) * bulletSpeed;
velocityInstance.y = Math.sin(user.rotation) * bulletSpeed;
var bulletInstance = new Bullet(velocityInstance, b, "Enemy", bulletDamage, "blue");
/*audioPistol.volume = 0.5;
audioPistol.currentTime = 0;
audioPistol.play();*/
user.bullets.push(bulletInstance);
user.shotBullet = true;
};
I've tried playing around with the 'setInterval', but it doesn't work well. Most of the times, it waits for a second, then sprays a load of bullets.
All I want it for a enemy bullet to initiate every second.
Thanks
var triggerID = window.setInterval(function(){firing_clock()},1000);
function firing_clock()
{
// this will execute once per second....sort of
}
Mozilla window.setInteral doc
So, one thing you should known is if your browser gets busy it will get 'late'. Mozilla used to have an extra non-standard parameter detailing "actual lateness", but it no longer does - but the point was that you are asking the browser to try to do something once per second, but if it gets busy it will get behind or skip a few rounds (how the browser handles it differs by browser).
Ideally what you would do here is register your enemy object with a list that firing_clock() would work through to dispatch firing commands to all live enemies. This cuts overhead by only using one global timer, rather than one timer per object on screen.
Try this with just one hard-coded enemy and see how it works. If it still doesn't work, then it's a bigger problem as there is no javascript "guaranteed accurate timer" that I'm aware of.
But it should work, so long as things don't get too intense on the client's CPU, and having one global timer for ship firing should allow you to have a good number of ships firing away without too much ill effect.

I would like to move an element to the left using loop

I bet I've got elementary question, but I couldn't solve it for two nights.
I've got 1 "ul" element and I just want it to move any amount of pixels every e.g. 2 sec to the left. I want him to move like this step by step and then come back to the original position and start moving again.
I've been stucked, my script only moves it to the final position and finish.
window.onload = function moveUl(){
var eUl = document.getElementById('change');
var eLi = eUl.getElementsByTagName('li');
x = -300;
function move(){
for(i=0;i< eLi.length;i++){
eUl.style.marginLeft = i*x+'px';
}
}
setInterval(move,1000);
}
This is the simpliest I can think of. I know this script executes whole loop after 1 sec, but I try to do something like this : Move this element to the left, wait, move more to left and so on.
Do you mean something like this?
window.onload = function moveUl()
{
var eUl = document.getElementById('change');
var eLi = eUl.getElementsByTagName('li');
var delta = 0;
function move()
{
for(i=0;i< eLi.length;i++)
eUl.style.marginLeft = (-300*i+delta)+'px';
delta -= 100; // Prepares for the next step
if ( delta == -1000 )
delta = 0; // Resets after 10 steps
}
setInterval(move,1000);
}
If you want it to slide, you have to timeout per iteration. Try writing a function that does a single shift, then calling this function every 10 ms. You can also look into a Javascript library like jQuery that provides a nice API for doing the moving.
Is the problem you can't go back from where you started?
Why not just add a new for loop in move
for(i=eLi.length; i>0 ;i--){
eUl.style.marginLeft = i*x+'px';
}
Do you also want it to loop for ever ie start -> left -> start -> left and again?

Categories