How to execute variable array of object-specific functions in JavaScript - javascript

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.

Related

Increasing speed of objects over time using p5js

I am playing around with p5js and wanted to create a simple game where the main goal is to jump over objects that are incoming from the right side of the screen.
So, pretty basic idea.
Everything appears to be working so far, however, I would like to increase the speed of objects that keep incoming either over a period of time or after an X amount of objects have passed. Currently, I am storing the objects into an array and looping through them.
Speed is determined by this.speed in the Pipe() function.
In order to show you what I mean, you can check the running version here. ( I had to put all functions into one file in order for this to work online)
FOR GAME CLICK HERE
(the game is played by pressing and/or holding the UP_ARROW)
I was trying to update this.speed from the draw function, but I wasn't able to keep this.speed persistent.
Any help is appreciated.
You would probably need to make a global speed variable so that all pipes are affected accordingly.
A suggestion would be to create an interval which increments speed and then assign that to this.x within the update function of the Pipe object.
this.update = function() {
this.x -= speed;
}
https://jsbin.com/fodekizohi/1/edit?html,js,output

In a canvas, is it better to have a single context or multiples?

i'm currently developing a js app.
I'm not a js expert so i'm asking for tips.
My question is:
Is it good practice (performance-wise as well) to draw in a canvas with an array of context or it is better to have a single context with all the drawing inside?
Case 1:
for (i = 0; i < 8; i++) {
contextAr[i] = canvasAr.getContext('2d');
contextAr[i].beginPath();
contextAr[i].arc(canvasAr.width / 2, canvasAr.height / 2, ...
}
Case 2:
contextAr.beginPath();
contextAr.arc(...);
contextAr.moveTo(...);
contextAr.LineTo(...);
A simple example could be a circle divided in 4 quarters. Should i treat the draw with a single context or should i treat each pieces separately.
I think i'm not fully grasping the meaning of context though.
Is contextAr[i] = canvasAr.getContext('2d'); a redundant call?
I would not be surprise if contextAr[i] had identical elements.
Thank you.
It's rather pointless obtaining a 2D context several times from the same canvas element as the same context object will be returned.
From the standard (my emphasis) -
Return the same object as was returned the last time the method was
invoked with this same first argument.
So the common and best practice is to obtain a single reference to a context per canvas element and use that successively.

Why is there no reference on image data?

Yes, I know about .getImageData()
I mean, let's say, I have to change some pixels:
var imageData = ctx.getImageData(...);
Seems, this method give me completely new copy of "real" (hiden somewhere deep from me) image-data.
I say that, because if you create new one:
var imgData2 = ctx.getImageData(.../*same parameters as before*/);
and compare two buffers:
imageData.data.buffer === imgData2.data.buffer; //false
So, each time it create new copy from it's bitmap. Oh my Gosh, Why? Okay, go further:
/*...apply some new changes to the imageData in a loop...*/
Nothing special above. But now, it's time to put this back:
ctx.putImageData(imageData, ...);
And this one inside itself run new loop and copy my imageData.
So much extra work! Is there a way to get actual imageData and manipulate it without get/put? And if no - I'm ask again - WHY? Is it security reasons? What they afraid I can do with that pixels?
Thank you!
Short answer :
No.
Not so long Answer :
You may be able to achieve it with some hacks but that would be such a pain.
Explanations :
According to the specs, getImageData returns a TypedArray which contains the canvas' image data, not a pointer to the live imageData as a modifiable object.
To paint on a canvas, you have to use methods such as fill, stroke, drawImage or putImageData ; that would make even less sense that each time you iterate through the array, the actual canvas image get modified.
Each time you call getImageData, a new TypedArray (note that the choice of the actual type is up to the UA) is created and filled with the current data of the canvasImage. This way, you can call this method, make different alterations on the ArrayBuffer, without modifying the actual image into the canvas (so you can store it, or call the method again).
As to why the buffer of the returned ImageData is not the same on each call, I think it is because "Pixels must be returned as non-premultiplied alpha values", but for performances, they do store it as premultiplied. You can see here the de-premultiplication operation from Firefox source code, which actually fills a new Uint8ClampedArray.
Also, it avoids to check if the canvasImage as been modified since the last call, and ensure you always get its current ImageData.

three js same position (reference) for 2 Object3D()

I am trying to add 2 (or more) Meshes to the same scene, but i want all the Object3D to share the same position (but with a different rotation for each object).
I know the ".copy()" method, but in my case, there are so many objects and using a loop to change the position of all the objects (60 times per seconds) is resulting a poor performance.
So, I tried to use the same position reference for the objects:
var o=new THREE.Object3D(); // the first object
var p=new THREE.Object3D(); // the second object
o.position=p.position; // the position of the first object becomes the reference to the position of the second object
o.position==p.position; // false, but why?
But it isn't working and I don't get why!
My question is:
Is it possible to change the position reference of a THREE.Object3D()?
And if it isn't, how can I improve the performance of my scene?
Thanks in advance!
Edit: seems to works for someone (this answer is exactly what i can't do): How to set the Object3D position and rotation same as the added mesh ? [three.js]

JS getting variable inside the function

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);
}

Categories

Resources