This issue concerns my preloader of sprite sheets, which are split in a separate images then rotated to create required assets for the game I am writing.
This function parses an array of sheets, then for each sheet, after is loaded, splits sequence to sprite instances, then perform required rotations:
function loadRotatedSheetSequences(arrPath = LoadRotatedSheetSequences) {
console.log(`%c ...loading ${arrPath.length} rotated sheet sequences`, ENGINE.CSS);
var toLoad = [];
arrPath.forEach(function (el) {
ASSET[el.name] = new LiveSPRITE("1D", []);
toLoad.push({ srcName: el.srcName, name: el.name, count: el.count, rotate: el.rotate });
});
ENGINE.LOAD.HMRotSeq = toLoad.length;
if (ENGINE.LOAD.HMRotSeq) appendCanvas("RotSeq");
const temp = Promise.all(
toLoad.map((img) => loadImage(img, "RotSeq"))
).then(function (obj) {
obj.forEach(function (el) {
ENGINE.seqToSprite(el);
ENGINE.rotateAsset(el.name, el.rotate.first, el.rotate.last, el.rotate.step);
});
});
return temp;
}
The function works perfectly fine if rotations are not required or if the source is a single sprite. Function loadImage is defined as (some irrelevant parts are excluded for simplification):
function loadImage(srcData, counter, dir = ENGINE.SOURCE) {
//setting properties
return new Promise((resolve, reject) => {
const img = new Image();
var obj = {
img: img,
name: name,
count: count,
tag: tag,
parent: parent,
rotate: rotate,
asset: asset
};
img.onload = function () {
console.log("loaded img", img);
ENGINE.LOAD[counter]++;
ENGINE.drawLoadingGraph(counter);
resolve(obj);
};
img.onerror = (err) => reject(err);
img.crossOrigin = "Anonymous";
img.src = src;
});
}
And finally, the method responsible for rotation:
rotateAsset(assetName, startAngle, endAngle, step = 1) {
let sprites = ASSET[assetName].linear;
for (let i = 0; i < sprites.length; i++) {
console.log(".sprite", sprites[i].complete);
for (let angle = startAngle; angle <= endAngle; angle += step) {
let name = `${assetName}_${i.toString().padStart(2, "0")}_${angle}`;
ENGINE.rotateImage(sprites[i], angle, name);
}
}
},
Console states that sprites[i].complete is false at execution time, but it is complete after checking with debugger. So the root cause IMO is that the image is not completely loaded when onload triggers, and this does not prevent cutting sequence to sprites, but stops rotation, since within the rotation I ‘trim away’ blank pixels, but since image loading is not complete, they are all blank.
I tried to substitute img.onload with img.onloadend, but the latter is never triggered.
Currently, if I encounter that function wants to trim an empty image, I perform location.reload(), then in the next attempt the image is in the cache and everything works fine. Of course, this is only a provisional solution.
Is there an elegant way to assure that an image is completely loaded before fulfilling the promise, or using some other event handler?