Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411588 Posts in 69386 Topics- by 58443 Members - Latest Member: Mansreign

May 06, 2024, 12:28:19 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)[JavaScript] image preload problem.
Pages: [1]
Print
Author Topic: [JavaScript] image preload problem.  (Read 2284 times)
DanFessler
Pixelhead
Level 3
******


aka Indigo


View Profile WWW
« on: May 20, 2010, 03:21:28 PM »

I'm having a problem that I can't seem to find an elegant solution for.  I'm creating a sprite class for a javascript game.  In the function to create a new sprite entity, it creates and loads a new image.  The problem i'm having is it tries to use and pull information from the image before it finishes loading causing many problems.  Is there a way to have the createsprite function wait for the image to load before moving on to the rest of the function?

one option would be to define all the images prior to creating a sprite entity, but this seems messier to me.  Anyone have an idea?


Code:
function createSprite (src,framesx,framesy) {

this.img = new Image();
this.img.src = src;

    this.x = 0;
    this.y = 0;

this.angle = 0;

this.imgWidth = this.img.width;
this.imgHeight = this.img.height;

this.frameWidth = this.imgWidth / framesx;
this.frameHeight = this.imgHeight / framesy;

this.isplaying = false;
this.playstart = 1;
this.playend = 1;

this.totalframes = framesx*framesy;
this.frame = 1;

this.framex = new Array(this.totalframes);
this.framey = new Array(this.totalframes);
i = 1;
for (var y=0; y<framesy; y++) {
for (var x=0; x<framesx; x++) {
this.framex[i] = (x * this.frameWidth);
this.framey[i] = y*this.frameHeight;
i++;
}
}


this.getInfo = function() {
return this.img.src + ", " + this.imgWidth + "x" + this.imgHeight + ", " + this.frameWidth + "x" + this.frameHeight;
    };

}
Logged

Chromanoid
Level 10
*****



View Profile
« Reply #1 on: May 20, 2010, 03:38:27 PM »

there should be an "onLoad" event handler that you can use... maybe you can add an isLoaded property to your class and set it true when the loading is finished (onLoad was executed).
« Last Edit: May 20, 2010, 03:45:12 PM by Chromanoid » Logged
Overkill
Level 3
***


Andrew G. Crowell


View Profile WWW
« Reply #2 on: May 20, 2010, 04:06:08 PM »

Yeah, Chromanoid's right, you can use an onload event which modifies the remaining sprite data when fully loaded (and keeps a flag of whether it is done loading). Just be careful, this may cause problems if you want to use the sprite itself before its data is fully initialized. If you're okay with some attributes not being known right away, like how many frames are in the file, or how big the entire spritesheet is, you should be in the clear. So just make sure not to directly change display-related things, but rather have functions that will make the request, and will be applied when the sprite is in a fully-usable state. Keep details like total frames and the like as internal attributes, which you don't need to know in order to setup animations for the sprite outside of its class. It seems frame width and height are passed into the constructor, so those would be safe to use, on the other hand.

Another way, possibly more elegant, around the onload is to just wait until EVERY sprite has finished loading its image before starting your game (setTimeout and check every sprite's loading status so often -- probably in 1/10ths of a second intervals). This way the game doesn't start until everything's ready. When all sprites are loaded, you know you're ready to rock.

When I made an isometric tile-based game in Javascript, I remember that I actually passed a known width and height in as parameters to my sprite constructors, so I could use info right away. I also preloaded all the game resources when the page was first loaded, which meant there was no real waits on the images either (because there were enough interfaces between the start of the webapp and the actual game part). Not the most elegant though. However, I think I would prefer onload now.

I am not aware of many other solutions to this problem.
« Last Edit: May 20, 2010, 06:09:44 PM by Overkill » Logged

BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« Reply #3 on: May 20, 2010, 05:01:26 PM »

I think it'd be much easier to, for instance, deny use of the sprite until isLoaded is true. This is kind of the reason for the access[get]/mutate[set] concept.  Durr...?

So pseudo-code:
Code:
SpriteObject Draw Function:
    if isLoaded is true
        Allow sprite drawing operations
end function
(I really don't think it's necessary to supply pseudo-code for that, but I've never tried writing it before, so it sounded fun!)
Logged

Overkill
Level 3
***


Andrew G. Crowell


View Profile WWW
« Reply #4 on: May 20, 2010, 06:04:35 PM »

I think it'd be much easier to, for instance, deny use of the sprite until isLoaded is true. This is kind of the reason for the access[get]/mutate[set] concept.  Durr...?
Hmm... Much easier than what? That was already one of my suggestions. At least, I thought it was! I made it so the script wouldn't die or completely ignore modifications if it wasn't finished loading, but rather defer them until it was finally possible to display the changes. Perhaps I've miscommunicated that though.

Code:
SpriteObject Draw Function:
    if isLoaded is true
        Allow sprite drawing operations
end function
(I really don't think it's necessary to supply pseudo-code for that, but I've never tried writing it before, so it sounded fun!)

Heh, pseudocode can be fun, but I don't know if it's very accurate here. This is Javascript, so his sprite is fairly likely to not actually have a draw routine, just HTML attributes that get modified by events (possibly with an update/refresh function that changes the element attributes after the sprite gets modified).
« Last Edit: May 20, 2010, 06:18:23 PM by Overkill » Logged

DanFessler
Pixelhead
Level 3
******


aka Indigo


View Profile WWW
« Reply #5 on: May 20, 2010, 06:26:43 PM »

This is actually written with HTML5's canvas, so there is a draw routine.. but my problem is much more basic than that.  I can't seem to understand how the "onload" event should be used.

I've tried the following code, yet the alert never pops up on my page.  What am I doing wrong?


Code:
function createSprite (src) {

this.img = new Image();
this.img.src = src;

this.img.onLoad = function() {
alert("hello");
}
}
Logged

Overkill
Level 3
***


Andrew G. Crowell


View Profile WWW
« Reply #6 on: May 20, 2010, 07:03:22 PM »

This is actually written with HTML5's canvas, so there is a draw routine.. but my problem is much more basic than that.  I can't seem to understand how the "onload" event should be used.

I've tried the following code, yet the alert never pops up on my page.  What am I doing wrong?


Code:
function createSprite (src) {

this.img = new Image();
this.img.src = src;

this.img.onLoad = function() {
alert("hello");
}
}

I see. Maybe I shouldn't have been so quick to jump to conclusions. I admit I haven't used HTML5 features yet, since they're still relatively new. Eventually I'll sit down and learn how to use the <canvas> tag though.

Anyways, that aside, I think your only problem with that code is that you have written "onLoad" instead of "onload". Remember that Javascript is case-sensitive. Unfortunately, it isn't an error to misspell things here either, since you're setting a property on an object, which if it doesn't exist will be created for you.

If it still doesn't work after correcting the case there, I found this article which talks about order mattering too. I'm not entire sure of this, but I guess if the load occurs very quickly (or the image is in cache), it may not call the onload function if it happens to be set after the image was already fetched.
« Last Edit: May 20, 2010, 07:13:35 PM by Overkill » Logged

BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« Reply #7 on: May 20, 2010, 08:46:40 PM »

@Overkill

I was replying to your suggestion to prevent images from drawing until all were drawn. Kind of emphasizing/elaborating/agreeing with your other idea.  Grin
Logged

Overkill
Level 3
***


Andrew G. Crowell


View Profile WWW
« Reply #8 on: May 20, 2010, 09:07:10 PM »

@Overkill

I was replying to your suggestion to prevent images from drawing until all were drawn. Kind of emphasizing/elaborating/agreeing with your other idea.  Grin
Oh okay. That "durr" smiley made me think there was some sort of large nasty sarcasm associated with that at first. My mistake!

Anyways, I tend to brain-dump when I give solutions to things because there's often a plenty of different alternatives to take, with programming design situations, and they all seem to pop into my head at the same time. Anyways, I think I've done enough derail for now, hehe.
Logged

DanFessler
Pixelhead
Level 3
******


aka Indigo


View Profile WWW
« Reply #9 on: May 21, 2010, 12:10:36 AM »

Thanks for the help guys. I was able to get it running using the onload.  I also applied the isloaded conditional statement to the drawsprite routine

you can test it here:
http://danfessler.com/html5

if your curious how the function looks...
Code:
function createSprite (src,framesx,framesy) {

this.img = new Image();
this.img.src = src;

var temp = this
temp.isloaded = false;

this.img.onload = function() {

temp.x = 0;
temp.y = 0;

temp.angle = 0;

temp.imgWidth = temp.img.width;
temp.imgHeight = temp.img.height;

temp.frameWidth = temp.imgWidth / framesx;
temp.frameHeight = temp.imgHeight / framesy;

temp.isplaying = false;
temp.playstart = 1;
temp.playend = 1;

temp.totalframes = framesx*framesy;
temp.frame = 1;

temp.framex = new Array(temp.totalframes);
temp.framey = new Array(temp.totalframes);
i = 1;
for (var y=0; y<framesy; y++) {
for (var x=0; x<framesx; x++) {
temp.framex[i] = (x * temp.frameWidth);
temp.framey[i] = y*temp.frameHeight;
i++;
}
}


temp.getInfo = function() {
return temp.img.src + ", " + temp.imgWidth + "x" + temp.imgHeight + ", " + temp.frameWidth + "x" + temp.frameHeight;
alert("hello")
}

temp.isloaded = true;
//alert(temp.img.src + ": " + temp.img.width + "x" + temp.img.height);

}
}
Logged

Chromanoid
Level 10
*****



View Profile
« Reply #10 on: May 21, 2010, 03:57:47 AM »

i am not sure, but i think you should assign the src after setting the handler. there could be a situation where the loading is faster than the jump to the next command - and your loader is never called.
Logged
Skofo
Level 10
*****



View Profile
« Reply #11 on: May 21, 2010, 08:39:17 AM »


Neato! Smiley
Logged

If you wish to make a video game from scratch, you must first invent the universe.
salade
Level 4
****



View Profile
« Reply #12 on: May 21, 2010, 03:46:10 PM »


Another way, possibly more elegant, around the onload is to just wait until EVERY sprite has finished loading its image before starting your game (setTimeout and check every sprite's loading status so often -- probably in 1/10ths of a second intervals). This way the game doesn't start until everything's ready. When all sprites are loaded, you know you're ready to rock.

.

I am not aware of many other solutions to this problem.

One potential implementation that could be killer would be to get sprites through ajax methods, rather then trying to manage it all on the page load. Of course, then you would be on your way to a full blown web app engine.
I'd be interested to see if anyone can find an example of a game which has taken advantage of the XMLHttpRequest object for resource loading.

Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic