6

I am strugling to create a script to load multiple images for a game drawn on Canvas. The window seems to load without completing the load of all images. I've tried many ways but none of them seems to work. The function drawGameMenu() is called before the images are actually loaded and so the images are not drawn. If someone could help, I would be grateful. Here is my script, kind regards:

var imageNames = ["menuImage", "resetScoreButton", "instructionsButton", "playButton", "dialogPanel", "gamePlayImage", "exitButton", "timerPanel", "messengerPanel", "scoreBar", "yesButton", "noButton", "goButton"];
var imageFileNames = ["game_Menu", "reset_score_button", "instructions_button", "play_button", "dialog_panel", "game_play", "exit_button", "timer", "messenger_panel", "score_bar", "yes_button", "no_button", "go_button"];
var imageCollection = {};

window.addEventListener("load", function() {
    var u = imageNames.length - 1;
    for(i = 0; i <= u; i++) {
        var name = imageNames[i];
        imageCollection[name] = new Image();
        imageCollection[name].src = imageFileNames[i] + ".png";
        console.log(imageCollection[name]);
        imageCollection[name].addEventListener('load', function() {
            do {
                var x = imageCollection[name].complete;
            }
            while(x != true);
        });
    }   
    drawGameMenu();
});

I made some changes on the script and now it works on the PC browser, but not working on smartphone. The script is the following:

window.addEventListener("load", async function loadImageCollection() {
    var u = imageNames.length - 1;
    for(i = 0; i <= u; i++) {
        var name = imageNames[i];
        imageCollection[name] = new Image();
        imageCollection[name].src = imageFileNames[i] + ".png";
        do {
            await new Promise((resolve, reject) => setTimeout(resolve, 50));
            x = imageCollection[name].complete;
            console.log(x);
        }
        while(x == false);
    }   
    drawGameMenu();
});
3
  • The issue is that name, the variable is preserved by the closures, and not its 'current' content. So on every occasion when the event listeners run, name will be its last value, "goButton". The simplest fix would be wrapping the loop body into an extra function, either just as it is now, or perhaps via switching to forEach. Commented Nov 13, 2018 at 23:20
  • Try just counting the images as they are being loaded. And as soon as the number of your loaded images will be equal the number of images in the array, call your drawGameMenu function. Commented Nov 13, 2018 at 23:20
  • The var 'name' gets a new imageName for each different 'i'. I also tried first to count the images loaded to call the function drawGameMenu, but the problem is that the images are counted but they are not actually loaded. I solved the problem to load on the browser with Promises. I will post the script. Commented Nov 14, 2018 at 0:26

2 Answers 2

9

Keep it simple

Just use a simple callback and a counter to count of images as they load. Adding promises adds an additional level of complexity that is just a source of potential bugs. (the promise for each image and its callback and the need to call it on image load, and the need to handle promise.all with another callback)

const imageCollection = loadImages(
    ["menuImage", "resetScoreButton", "instructionsButton", "playButton", "dialogPanel", "gamePlayImage", "exitButton", "timerPanel", "messengerPanel", "scoreBar", "yesButton", "noButton", "goButton"],
    ["game_Menu", "reset_score_button", "instructions_button", "play_button", "dialog_panel", "game_play", "exit_button", "timer", "messenger_panel", "score_bar", "yes_button", "no_button", "go_button"],
    drawGameMenu  // this is called when all images have loaded.
);

function loadImages(names, files, onAllLoaded) {
    var i = 0, numLoading = names.length;
    const onload = () => --numLoading === 0 && onAllLoaded();
    const images = {};
    while (i < names.length) {
        const img = images[names[i]] = new Image;
        img.src = files[i++] + ".png";
        img.onload = onload;
    }   
    return images;
}
Sign up to request clarification or add additional context in comments.

4 Comments

Hello Blindman67. Thank you very much for the help. I tried your script and runs very nice. The Promise approach also runs fine on PC browser, but after compiling for an apk, it really didn't work on a smartphone with android 4.1. I will try your script also after compiling to apk. I am very new to Object Oriented Programming and so I don't understand some operations on your script. I will study it as it seems very efficient. Once again, thanks for the help!
@LuisRitoFilipe is right, we all lappreciate Your answers, but.. ten lines of additional code and a little bit of backward compatibility does not hurt ;)
There is an error in for cycle: i <= names.length. Should be <
@TsarIoann Yes indeed, how did I miss such an obvious typo. Thank you for pointing it out, I have updated answer. Just in case you are wondering at the change I favor while loops over for loops as they are cleaner.
8

With the use of promises this becomes a very easy task. I don't know if ES6 allows it, but give it a try anyways.

var jarOfPromise = [];

    for(i = 0; i <= u; i++) {

        jarOfPromise.push(
            new Promise( (resolve, reject) => {
                var name = imageNames[i];
                imageCollection[name] = new Image();
                imageCollection[name].src = imageFileNames[i] + ".png";
                console.log(imageCollection[name]);
                imageCollection[name].addEventListener('load', function() {
                    resolve(true);
                });
            })
        )

    }


    Promise.all(jarOfPromise).then( result => {
        drawGameMenu();
    });

3 Comments

I tried your script and works very nice. I have to study more the Promises as I don't understand much this approach.
Thanks, promises are wonderful if used correctly. ;). Don't forget to tag my answer as the best one :P
Yes I tagged, but it says it won't show publicly. Once again, thanks for the help, it works very nice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.