Reputation: 3025
EDIT: The kind people of this site linked me to a QA that seems related to the problem described below.
JavaScript closure inside loops – simple practical example
While I appreciate the prompt response, and I can understand the need to prevent duplicate content, it leaves me in a pickle - I'm not savvy enough to understand how to repurpose the linked answers to solve my particular problem.
I've modified the question to be more specific - please consider helping me rectify my inexperience this time, instead of leaving me to fend for myself.
Working on an application (read: game), and ran into what I'm sure is a common problem. I have a list of assets that will be loaded asynchronously, each of which needs to reference a specific object once created.
See code below. When an image loads, it should create a Kinetic.Image
object and associate it back to the this.enemies[n]
that has the correct image URL. this.enemies
is cardinal, the assets/objects need to stay in that order - so I can't just push the objects to an array as they're created. The list is also variable-length, so I can't just hard-code things out. I even tried referencing the i
from the loop in an act of desperation, and (not surprisingly) it doesn't work.
I tried googling things like "asynchronous assignment", without much success. Here's the question - when 2.png
loads and creates its object, how do I use closure to assign it back to the object containing asset: "2.png"
? I understand that the linked question is related, but it says nothing about how to execute it when dealing with async loading.
Here's the code:
var Battle = {
...
start: function(){
this.enemies = [
{ asset: "1.png" },
{ asset: "2.png" },
{ asset: "3.png" }
];
for(i in this.enemies){
var eImg = new Image();
eImg.onload = function(){
Battle.enemies[i].obj = new Kinetic.Image({
image: eImg,
x: 40, y: 40
});
};
eImg.src = "/game/assets/battle/"+this.enemies[i].asset;
}
}
};
Upvotes: 0
Views: 49
Reputation: 16109
This is basically what they are suggesting:
function makeCallback(enemy, eImg) {
enemy.obj = new Kinetic.Image({
image: eImg,
x: 40, y: 40
});
}
var Battle = {
...
start: function(){
this.enemies = [
{ asset: "1.png" },
{ asset: "2.png" },
{ asset: "3.png" }
];
for(i in this.enemies){
var eImg = new Image();
eImg.onload = makeCallback(this.enemies[i], eImg);
eImg.src = "/game/assets/battle/"+this.enemies[i].asset;
}
}
};
With your code, when the function is executed, i
is whatever its value is at that time, not at the time the function was defined. Use a function to isolate enemy and eImg and close them inside the function object.
Upvotes: 1