Using physical pixels when devicePixelRatio!==1

I’m trying to use the physical pixels instead of CSS pixels for a better resolution. I can do this by calling melonjs.video.renderer.resize(document.clientWidthwindow.devicePixelRatio,document.clientHeightwindow.devicePixelRatio). However, this screws up the mouse events triggering on the entities on screen. I’m currently using a kludge where I have a handler in the game state that calls this adjustPixels function at the end of the pointer event handler functions. However, it doesn’t always work (especially for pointermove), besides being very hacky. How can I fix this?

adjustPointer(pointer:melonjs.Pointer){
	//fix problem with device pixel ratio
	pointer.gameScreenX*=window.devicePixelRatio;
	pointer.gameScreenY*=window.devicePixelRatio;
	let local=melonjs.input.globalToLocal(pointer.gameScreenX,pointer.gameScreenY);
	pointer.gameLocalX=local.x;
	pointer.gameLocalY=local.y;
	let world=(melonjs.game.viewport as melonjs.Camera2d).localToWorld(local.x,local.y);
	pointer.gameWorldX=world.x as number;
	pointer.gameWorldY=world.y as number;
}

Why don’t you use Pointer.client[X/Y] (melonJS: Pointer) those are the mouse/pointer coordinates sent by the browser/system event ? this should be what you are looking for ?

Else normally the whole Pointer implementation is made so that you don’t have to worry about scaled resolution vs internal resolution and all corresponding pixel “transformation”. What is your use case where this is not accurate enough for you ? (just our of curiosity)

Actually the main problem that I’m facing is that the pointer events don’t get fired on the sprites unless I do that hackery. Seems to be because the pointer coordinates are in CSS pixels and the location of sprites on screen are in canvas (physical) pixels. Even with the hackery sometimes pointermove is not called.

Or am I doing it wrong? Is there some other proper way to increase the resolution to 1:1 with physical pixels other than calling melonjs.video.renderer.resize?

Have you tried playing with the scaling options to scale the display right away ? or do you need to change the resolution (canvas size, or aspect ratio) during the game ?

Im king of struggling to understand your use case to be honest :stuck_out_tongue: maybe if you could provide a better description of what you are trying to do ?

Hi Olivier,

Basically the problem is that the resolution looks crappy and pixelated on my phone when I do not resize the canvas to the physical pixel size.

Here is the canvas without any resizing due to devicePixelRatio:

Here is the canvas when I resize it to widthdevicePixelRatio and heightdevicePixelRatio:

This is when I tried to call init with scale:1/window.devicePixelRatio which does not make any difference from not scaling:

I’m using flex scale mode. Basically I just want the screen to display as much of the map as the physical pixels allow with no scaling.

The problem that happens when I resize it to multiply the dimensions by the devicePixelRatio is that the pointer events on the sprites stop working. My way of trying to solve this was to handle pointer events globally and call my adjustPointer function at the end of the event handler. However, that only works inconsistently some of the time (notably, pointermove sometimes doesn’t get called on the sprites), besides the fact that it’s obviously a kludge.

Is there some way to have the pointer events translated between CSS pixels and physical pixels, when the canvas size is resized to be based on physical pixels instead of CSS pixels, so that the event handlers of the sprites (which have screen coordinates based on canvas pixels) get called?

Sorry if I didn’t explain it very well.

wait so what you want is the flex resize option, have you tried that one ? (even maybe flex-height specifically)

No, it didn’t help because flex still doesn’t make the resolution according to physical pixels (let’s say devicePixelRatio is 3, the CSS pixel width is 100, then the canvas width should be resized to 300 but in flex, the canvas width is still 100).

I’ve temporarily solved the events firing by making my minimap floating and setting the width and height to the entire screen (then I calculate the coordinates manually in the event handler). And I’m still using the adjustPixels function. Also not a very good solution.

I think the problem is in dispatchEvent because it doesn’t seem to allow for a canvas width / height that is different from its width and height in CSS pixels.