Camera2D.ScreenToWorld() not working as expected across all mobile devices

I’m working on a puzzle game that presents a grid of objects that the player needs to click/tap on. I am using Camera2D and BoxingViewportAdapter from Monogame Extended to scale the screen so that it will display in the same way across all devices. Clicking/tapping on them works perfectly and as-expected when playing the Windows version of the game, and also works perfectly on the two phones I’ve tried. The issue is, on some friends’ phones, when wanting to test the game on their devices, they are not able to accurately touch the objects throughout the screen. Those on the bottom of the grid (aka bottom of the screen), they have to offset their touch by an entire row on the grid, tapping on an object above the one they want to select the one they want.

After further questioning it seems that at the top of the screen, the touch controls are more receptive, and grow worse as it nears the bottom. Again, this doesn’t happen on my phone or any I have the disposal to test with easily, so I’m kind of stumped. Here’s the relevant code in my Game class where I declare the Camera and ViewportAdapter and use them to draw:

public void Initialize()
{
//…
viewportAdapter = new BoxingViewportAdapter(Window, GraphicsDevice, (int)Constants.WORLD_WIDTH, (int)Constants.WORLD_HEIGHT);
camera = new Camera2D(viewportAdapter);
//…
graphics.PreferredBackBufferWidth = 480;
graphics.PreferredBackBufferHeight = 800;
graphics.ApplyChanges();
//…
}

public void Draw(GameTime gameTime)
{
//…
spriteBatch.Begin(transformMatrix: camera.GetViewMatrix());
screenManager.Draw(spriteBatch);
spriteBatch.End();
//…
}

Just a note, I have tried both camera.GetViewMatrix() and viewportAdapter.GetScaleMatrix() and neither are able to fix the touch issues on other peoples’ phones. I’ve also tried not giving any PreferredBackBufferWidth and Height. When polling for input, I am using this:

camera.ScreenToWorld(touchCollection[0].Position)

Any reason you can think of why this wouldn’t work across all devices? I greatly appreciate any help or feedback.

PS - If you want to try for yourself to see if it works for you, my latest test build is on itch.io: https://yityit2000.itch.io/bubble-pop, password is bubblepop. You’ll have to allow sources outside google play for apps to try it. No build for iOS yet.

You might need to set TouchPanel.DisplayWidth and TouchPanel.DisplayHeight to match the backbuffer. I believe this scales the touch accordingly.

Thanks, that sounds promising! I’ll try that when I get home from work. I’m assuming this doesn’t simply stretch the image to the display bounds but still takes advantage of the capabilities of the Camera2D and BoxingViewportAdapter to still display the game world appropriately?

Hello @edvora91, welcome to the forums, happy coding.

Thanks MrValentine!

I tried implementing the TouchPanel.DisplayWidth and Height yesterday into my game as follows:

graphics.PreferredBackBufferWidth = 480; graphics.PreferredBackBufferHeight = 800;
TouchPanel.DisplayWidth = graphics.PreferredBackBufferWidth;
TouchPanel.DisplayHeight = graphics.PreferredBackBufferHeight;

graphics.ApplyChanges();

My tester with the phone it doesn’t work on said the problem persists. I can try setting those variables after graphics.ApplyChanges, but I can’t remember now if I did that already or not anyway. Unfortunately I’m at work and can’t check. Other than that, can anyone think of anything else I can try? I’m officially stumped and can’t understand why I can’t get this to work.

1 Like

Maybe BoxingViewportAdapter doesn’t play nicely with the camera.
You could test this by setting the resolution exactly to the target-device’s resolution.

Thanks Finnhax, I could try that perhaps. I think they are supposed to play nice though since the docs from Monogame Extended use them together and they say it is recommended to use a viewport adapter with a camera.

http://docs.monogameextended.net/Features/Cameras/#orthographic-camera

This is what I followed.

My guess (based on previous bugs we’ve experienced) is that it’s actually MonoGame that isn’t behaving the same way on all devices.

There’s no platform specific code in Extended at all. We don’t switch code paths based on the platform or device ever. Although, we do have to rely on MonoGame doing platform specific things consistently under the hood (which unfortunately isn’t always the case).

Under the hood, the viewport adapters use the Window.ClientSizeChanged event and the GraphicsDevice.Viewport width and height. Both of these things have proven to be problematic in the past and we’ve had to implement workarounds.

My suggestion would be to add some logging to your app so that you can see what’s happening and when. Check the the Window.ClientSizeChanged event is firing when you’d expect and that the GraphicsDevice.Viewport width and height have sensible values.

Once you’ve got a handle on it you should be able to implement a workaround by calling the Reset method on the viewport adapter and / or manually fixing up the viewport values.

Your friend’s phone has a differed resolution than the other two phones,
correct?

On phones monogame tries to mimic the hardware scaler of windows phones by adjusting the Viewport. This often result in funny situations, you will find many report in this forum about inconsistencies between Preferred resolution, actual resolution and viewport pos/size.
You need to take all those into account when unprojecting a touch event into world space.

I suggest you do what you had to do anyways on the desktop when going fullscreen.
(GPUs normally don’t allow any resolution in fullscreen mode)
Iterate through the Adapter.Modes to find a resolution that best suit your game and set that resolution to PreferredBackBufferWidth/Height. Adjust your game and camera to adapt to different resolutions and aspect ratios.
Alternatively you can render everything at a fixed resolution on a rendertarget and at the end render and scale that at the native resolution.

Appreciate the help guys, thanks. Haven’t gotten to work on it very much (other than trying a different solution to my problem using ResolutionBuddy, https://github.com/dmanning23/ResolutionBuddy, which didn’t fix the problem entirely for me yet), but I’m going to take this feedback and put it towards my work the next couple days and report back with anything I’ve found or if the problem has been solved.

I think I’ve read about using a rendertarget and might look more into that option as well.

1 Like

Thought I’d provide an update on my progress for posterity.

I haven’t fully solved the issue yet, but I’m finding far more success using nkast’s final suggestion of rendering everything on a rendertarget and scaling, including keeping a consistent aspect ratio. I’m then setting the TouchPanel DisplayWidth and Height to the world size and it finally worked as expected on my friend’s phone. It’s not 100% accurate right now yet because I’m not accounting for the black bars present when accounting for a consistent aspect ratio, but I feel that this is the most progress I’ve made in a while, it’s using base Monogame tools, and it’s a solution that I feel I fully understand what’s happening and why it’s happening. I’ll keep working at it until it’s perfect though.

Thanks again for all the help everyone.

See an possible workaround in a related bug issue I created recently here.