I have a function to do something on onClick event.
function onDocumentMouseUp( event ) {
createsprite(clickedposition);
}
createsprite(clickedposition) {
var sprite = JSONSPITE // this add correctly sprite to my scene;
//// here timer function 1 sec
setTimeout(function(){ remove(sprite); }, 1000);
}
Everything works correctly.
But when i click more than once, i have still my variable sprite as a last added one. (yes i know that is correct). And logically remove() have affected only that last one.
What is the correct solution to handle work with unknown amount of same variables.
Purpose it too remove each sprite after one second after click one by one in the order of creation.
How can i reach only one variable in the same function, even when there are more variables with the same name on each function init.
You have defined sprite as a global variable. It will exist not only in that function, but is created on the window object.
If you want to remove only the sprite you created in that function, you should make it a variable
var sprite = JSONSPITE; // typo?
This way, the scope of the sprite variable is just that function.
EDIT: OP has changed their question, making the previous explanation seem obsolete
If you want to create multiple sprites, and store them somewhere so you can access them before they are deleted, you might want to create an array of sprites.
sprites = [];
function onDocumentMouseUp( event ) {
createsprite(clickedposition);
}
function createsprite(clickedposition) {
sprites.push(JSONSPITE); // Adds the current sprite to the end of the array
setTimeout(function(){
var firstSprite = sprites.shift(); // Takes the first sprite out of the array
remove(firstSprite);
}, 1000);
}
Related
I'm trying to use a closure as per this answer to move a DOM element incrementally. Eventually I want to dynamically create many of these DOM elements that should be moved independently, so that's why I'm trying to define the variable within the function.
The example from the answer given is
var lightning = new Array();
lightning.push($(".lightning"));
var l0 = -210;
function thunkAdd(){
var lThis = l0;
console.log('set lThis to '+ lThis);
return function inc() {
console.log('lThis = '+ lThis);
return lThis ++;
}
lightning[0].css("left", lThis);
console.log('lightning[0] left = '+lightning[0].css("left"));
}
var incrementInterval = setInterval(thunkAdd(), 33);
first example on codepen. Looking in the console, it seems that for some reason, console.log('lightning[0] left = '+lightning[0].css("left")); is not running.
A different approach I tried is:
var lightning = new Array();
lightning.push($(".lightning"));
var l0 = -210;
var lThis = l0;
function thunkAdd(){
lThis ++;
console.log('lThis = '+ lThis);
lightning[0].css("left", lThis);
console.log('lightning[0] left = '+lightning[0].css("left"));
}
var incrementInterval = setInterval(thunkAdd, 33);
second example on codepen. That will move the image across the screen, but ideally (because the next step is to create and move many of these images dynamically) I want to define the variable lThis inside the thunkAddfunction the first time it runs and then if it is defined, increment it and use the lThis variable to move the image. How can I do this?
As already mentioned in comments code after return will not be executed, so you never change the css left property of the element, but just increment variable.
You need to move the lightning[0].css("left", lThis); inside closure that's being executed with interval.
See updated example
You may also consider using jquery's animate instead of this (you can also do this with many elements or in loop)
$(".lightning").animate({left: '2000px'}, 10000, 'linear');
Though I have experience in javascript and read articles about how to handle objects, it still confuses me sometimes as I am used to the classical object oriented behavior. So I want to share my current problem:
I want the PIXI-Sprite Object (that has properties position.x, .y and speedX , SpeedX) to have a method called "move", that changes the position according to the speed.
PIXI.Sprite.prototype.move=function()
{
this.position.x += this.speedX;
this.position.y += this.speedY;
};
var sprite = new PIXI.Sprite(picture);
sprite.position.x=0;
sprite.position.y=0;
sprite.speedX=1;
sprite.speedY=1;
When I call the method for "sprite" every frame this works fine:
sprite.move();
Now I want to have an array of functions that can be chosen individually for each sprite. So all of the functions in the array are executed every frame. So I created an array with this function:
sprite.ai=[];
sprite.ai.push(sprite.move);
When I now execute this function...
sprite.ai[0]();
...an error is thrown:
TypeError: this.position is undefined
Can you tell me why this is. I think that this is because "this" is now the array and not the sprite, but I don't know how to get the sprite object. How would be the proper way to achieve what I want?
Thanks a lot!
There’s a bind method on Functions that returns a new function with this fixed to whatever you specify:
sprite.ai.push(sprite.move.bind(sprite));
Alternatively, you can pass a function expression that makes a direct call to sprite.move() in turn:
sprite.ai.push(function () {
sprite.move();
});
Thanks a lot. This works. However -- as I'm having multiple sprites -- there is not just one Sprite object "sprite", but an array of Sprite objects "sprites". So the sprite that is created is added to that array:
var sprite = new PIXI.Sprite(tShot);
sprite.x=hero.x;
sprite.y=hero.y;
sprite.speedX = 0;
sprite.speedY = -1;
sprite.ai[0]=(function(){sprite.move()});
sprites.push(sprite);
container.addChild(sprite);
Then I call every frame:
sprites[i].ai[0]();
But now only one object is moved -- the last one that was created. The more objects exist, the faster this single object moves. So i concluded, that though every object has the function "move", it is always bound to the same object and therefore this object is moved.
When I call
sprites[i].move();
ever frame, it works how it should. Can you tell me why this is. This would help me a lot to understand the behavior of javascript.
I'm playing with animations. I'm trying to have two circles move a specified distance and then stop. The issue I'm having is with multiple intervals. I assign each interval to a unique variable, and clearInterval that variable, but the first interval continues on.
Here is the code:
function moveRight(player){
if(player==1){
currentLoc = p1Loc[0]; //global var with player's current location
intervalR1 = setInterval(function(){
p1Loc[0]+=1;
draw(); //function that redraws the canvas
if(p1Loc[0]>currentLoc+wu){ //wu is a single "width-unit"
clearInterval(intervalR1);
}
},5)
}
else{
currentLoc = p2Loc[0];
intervalR2 = setInterval(function(){
p2Loc[0]+=1;
draw();
if(p2Loc[0]>currentLoc+wu){
clearInterval(intervalR2);
}
},5)
}
}
Then, let's say I give the following instructions within a while loop:
instructions = ["moveRight(1)", "moveRight(2)"];
for(instruction in instructions){
eval(instructions[instruction]); //I know, eval(), ugh. Is just temporary
}
What ends up happening is, both players start moving right, but player 2 stops after a single wu, or width-unit while player one keeps going. If i change the instructions to only "moveRight(1);", then player one moves a single wu and stops.
What's going on here?
This is just a guess, since is a bit hard to tell what is going on with only part of the code, but could it be that you are assigning currnetLoc twice, and thus the first player's location will always be always be compared against p2Loc[0]?
So when you call moveRight(1) it sets currentLoc to p1Loc[0] then proceeds. Then immediately after you call moveRight(2) which sets currentLoc to p2Loc[0]. So now the comparison for the interval for player 1 is no longer p1Loc[0]>currentLoc+wu, but rather p2Loc[0]>currentLoc+wu. Depending on the value of p2Loc this may always be false.
This line:
currentLoc = p1Loc[0]; //global var with player's current location
is kinda scary. Don't use a global for this, especially when you re-assign its value on the second entry to the function:
currentLoc = p2Loc[0];
That's likely your problem.
If you need to keep track of a single player's position, create a player object and keep track of it in there, something like:
function Player(number) {
this.number = number
this.position = 0 //some default initial position
}
and pass this into moveRight()
I'm going to try my best to ask this question without a huge wall of code. Basically I have written a very simple math quiz game. In this game you select a difficulty, the number of questions you want, and the game starts. It asks that number of questions and then you get a score and then the game is over. However, you can restart the game. When you restart, it simply returns you to the home screen, then you can select your options again. The only problem is, we need to keep track of the number of questions remaining in the quiz, the first time around, it works well. We pass numQuestions to the game function. The second time, however, even if I pass numQuestions=10, the value remains 0 from the first time I played the game. Here is the game function:
function startGame(difficulty,numQuestions,score){
// begins game, excluded that come its just some acsii art
// asks question
var q = new question(difficulty);
$("#gameInside").html(q.string);
$("#gameInside").data('answer',q.answer);
// gives answer options
for (var ii=0;ii<=3;ii++){
$("#answers").append("<button class='answerButton'>"+q.answerArray[ii]+"</button>")
}
// starts timer
var b = document.getElementById("timer");
timer = new stopWatch(b, {delay: 100});
timer.start();
},5500)
// when answer is clicked, go here
$("#gameScreen").on("click",".answerButton",function() {
// this seems to be the problem: on the second time I play the game, numQuestions remains the value from the first game and continues to go down (-1,-2) and since my selector is (>0), the else statement fires.
numQuestions--;
var time = parseFloat($("#timer span").html());
var correct = parseFloat($("#gameInside").data('answer'));
var userAnswer = parseFloat($(this).html());
if (correct==userAnswer)
tempScore = Math.round(calculateScore(time)*100)/100;
else
tempScore = 0;
score += tempScore;
$("#score").html(Math.round(score*100)/100);
if (numQuestions > 0) {
var q = new question(difficulty);
$("#gameInside").html(q.string);
$("#gameInside").data('answer',q.answer);
$("#answers").empty();
for (var ii=0;ii<=3;ii++){
$("#answers").append("<button class='answerButton'>"+q.answerArray[ii]+"</button>")
}
timer.reset();
} else {
$("#answers").empty();
$("#gameInside").html('Game Over! Thanks for Playing!');
timer.stop();
}
});
}
any ideas? Thanks
edit:
$(".numberQButton").click(function(){
numQuestions = parseFloat($(this).html());
$("#numQuestionsScreen").hide();
$("#gameScreen").show();
$("#score").html(0);
startGame(difficulty,numQuestions,score);
});
You're problem (I think) lies in closures. When you declare a function in javascript, any accessing of a variable from outside it's own scope generates what is called a closure. In this case, numQuestions is accessed from inside your event function, creating a closure. The effect of this is that any accessing of the variable numQuestions inside your event functions references the variable as it was from the moment your javascript interpreter came across the event function itself- ie, the first time you play your game.
Have a look at these to get an idea of where it's going wrong.
It sounds like you need to instantiate a new Game object when the game is restarted.
Where do you define the on click listener? If it triggers two times, it seems like you are defining the on click listener in such way, that after you completed one game and start all over, a new listener will be registered so you got 2 in the end.
I have an animation created in Edge that I need to play 3 times and then stop on a specific frame.
I'm new to javascript and I think I need to use a variable and if/else statement, but am unsure what to use and how to write it. Any help would be much appreciated. Thank you!
Reluctantly I reply, really you need to provide some code to show your attempts. However, as this is a useful starter question I'll attempt an answer.
First thing you'll need is a global scoped variable to store the loop counter. Add something like this to your Stage.compositionComplete function.
// Add a numLoops variable to global storage
sym.setVariable("numLoops", 0);
Next at the end of your animation via the Timelines actions, create an event to capture that variable, increment, and replay the animation if applicable like so:
// capture numLoops variable and increment the counter
var numLoopsHolder = sym.getVariable("numLoops");
numLoopsHolder = numLoopsHolder + 1;
// set new numLoops variable back to global storage
sym.setVariable("numLoops", numLoopsHolder);
if (numLoopsHolder <= 2) {
// replay scene until 3 iterations are complete
sym.play(0);
}
This will get it looping 3 times, but you still need to add a stop check at the desired timeline location via:
// capture numLoops variable to check for 3 loops (ie. 0, 1, 2 = 3 loops)
var numLoopsHolder = sym.getVariable("numLoops");
if (numLoopsHolder >= 2) {
// we've completed 3 loops now stop here
sym.stop();
}
Here's a screenshot of the timeline for action event references.