I am programming an OOP 2d canvas game, and I am seeing some weird behaviour with my code. When inside "e", the workspace, there is two or more of the same object but nothing else, ctx.resetTransform
somehow does not work, but the moment I create a new object of a different type in console, ie. e.create('bullet')
, the bug goes away. Does anyone know why that is?
var c = document.querySelector("canvas");
ctx = c.getContext("2d", {alpha: false});
const objs = {
flower: {
name: "flower",
rot: 45,
vel: {x: 0, y: 0},
pos: {x: 50, y: 100},
size: {x: 100, y: 100},
sprite: [
[0.4, 0.5, 0.2, 0.5, "green"],
[0.3, 0.1, 0.4, 0.4, "pink"],
],
},
bullet: {
name: "bullet",
rot: 0,
vel: {x: 0, y: 0},
pos: {x: 50, y: 100},
size: {x: 5, y: 10},
sprite: [[0, 0, 1, 1, "black"]],
},
};
var e = [];
e.create = function (cr) {
crr = structuredClone(objs[cr]);
e[e.length] = crr;
return crr;
};
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function render() {
ctx.clearRect(0, 0, c.width, c.height);
for (i = 0; i < e.length; i++) {
var obj = e[i];
for (ii = 0; ii < obj.sprite.length; ii++) {
ctx.resetTransform();
ctx.translate(
obj.pos.x + obj.size.x,
obj.pos.y + obj.size.y
);
ctx.rotate((obj.rot / 180) * Math.PI);
ctx.translate(
-(obj.pos.x + obj.size.x),
-(obj.pos.y + obj.size.y)
);
ctx.fillStyle = obj.sprite[ii][4];
ctx.fillRect(
obj.pos.x +
obj.sprite[ii][0] * obj.size.x -
obj.size.x / 2,
obj.pos.y +
obj.sprite[ii][1] * obj.size.y -
obj.size.y / 2,
obj.sprite[ii][2] * obj.size.x,
obj.sprite[ii][3] * obj.size.y
);
}
}
}
setInterval(() => {
render();
}, 50);
setInterval(() => {
e[0].pos.x = Math.random() * c.width;
}, 50);
e.create("flower");
e.create("flower");
<canvas height="1080" width="1920"></canvas>
2
Answers
The issue with
ctx.resetTransform()
in your 2D canvas game seems to be unusual. Normally, this function should reset the current transform to the identity matrix regardless of the objects in the workspace. However, based on your description, it appears that there is a specific behavior that depends on the state or composition of youre
array.It’s not obvious but with the CanvasRenderingContext2D’s
resetTransform()
method the point of time actually calling it is important. To cite the mdn web docs :So the remedy is pretty easy – move
ctx.resetTransform();
from the beginning to the end of your for-loop – otherwise it might result in the ‘ghosting images’ you’ve experienced.