Assuming I have some arbitrary game object, is there a way to transform object’s position to canvas pixel space? In otherwords, how would I get the x,y pixel I would need to click on to click on the origin of the object?
Hi @HyPeRbLaH,
If the size of the viewport of your camera is the same as the size of the canvas, this would be a way:
// this === scene
var gameObjectCanvasX = gameObject.x - this.cameras.main.scrollX * gameObject.scrollFactorX;
var gameObjectCanvasY = gameObject.y - this.cameras.main.scrollY * gameObject.scrollFactorY;
Regards.
Thanks @jjcapellan. Unfortunately my camera viewport will not be the same size as the viewport.
Then, you need to add the camera position:
// this === scene
var cam = this.cameras.main;
var gameObjectCanvasX = gameObject.x - cam.scrollX * gameObject.scrollFactorX + cam.x;
var gameObjectCanvasY = gameObject.y - cam.scrollY * gameObject.scrollFactorY + cam.y;
What ended up working for me is as follows:
// obj is our game object
var mat = obj.getWorldTransformMatrix();
// Get world position;
var x = mat.getX(0, 0);
var y = mat.getY(0, 0);
// Convert world position into canvas pixel space
var cam = this.scene.scene.cameras.main;
var displayScale = cam.scaleManager.displayScale;
mat = cam.matrix;
let tx = mat.getX(x - camera.scrollX, y - camera.scrollY) / displayScale.x;
let ty = mat.getY(x - camera.scrollX, y - camera.scrollY) / displayScale.y;
x = Math.round(tx);
y = Math.round(ty);
This seems to handle a bunch of cases like deep hierarchies, rotations, scaled and rotated cameras, scale manager scaling, etc…
Probably this can be a more accurate solution:
function GetCanvasPoint(camera: Camera, x: number, y: number, output?: Vector2) {
if (output === undefined) {
output = new Vector2();
}
const cameraMatrix = (camera as any).matrix.matrix;
const mva = cameraMatrix[0];
const mvb = cameraMatrix[1];
const mvc = cameraMatrix[2];
const mvd = cameraMatrix[3];
const mve = cameraMatrix[4];
const mvf = cameraMatrix[5];
const determinant = (mva * mvd) - (mvb * mvc);
if (!determinant) {
output.x = x;
output.y = y;
return output;
}
const res = camera.resolution;
const sx = (mva * x + mvc * y + mve) / res;
const sy = (mvb * x + mvd * y + mvf) / res;
const c = Math.cos((camera as any).rotation);
const s = Math.sin((camera as any).rotation);
const zoom = camera.zoom;
const scrollX = camera.scrollX;
const scrollY = camera.scrollY;
output.x = sx - (scrollX * c - scrollY * s) * zoom;
output.y = sy - (scrollX * s + scrollY * c) * zoom;
return output;
}
Thanks for this. However I found that the displayScale. bit was throwing my result out. I don’t understand how it works, but when I took out /displayScale.x and /displayScale.y the result i got was correct.
Cheers
Martin