1
\$\begingroup\$

I have been at this game of trial-and-error for days now. I cannot find a consistent method to calculate the respective mouse position in my game world after the calculations are done to stretch the game's render view to the current resolution. I've seen other, similar questions and answers on this site, but after looking at them long and hard, I can't translate the answers to my project.

I'm using XNA. First, I render everything to a RenderTarget2D at a resolution of 800x600. Then I render said RenderTarget to the screen by calculating it's size and location through a method that returns a Rectangle:

public Rectangle CalculateRenderTargetPosition()
    {
        Rectangle rec;
        Single preferredAspect = Globals.RenderSize.Width / (Single)Globals.RenderSize.Height;
        Single outputAspect = Globals.WindowSize.Width / (Single)Globals.WindowSize.Height;
        if (outputAspect <= preferredAspect)
        {
            // output is taller than it is wider, bars on top/bottom
            Int32 presentHeight = (Int32)((Globals.WindowSize.Width / preferredAspect) + 0.5f);
            Int32 barHeight = (Globals.WindowSize.Height - presentHeight) / 2;
            rec = new Rectangle(0, barHeight, Globals.WindowSize.Width, presentHeight);
        }
        else
        {
            // output is wider than it is tall, bars left/right
            Int32 presentWidth = (Int32)((Globals.WindowSize.Height * preferredAspect) + 0.5f);
            Int32 barWidth = (Globals.WindowSize.Width - presentWidth) / 2;
            rec = new Rectangle(barWidth, 0, presentWidth, Globals.WindowSize.Height);
        }
        return rec;
    }

The Camera's position is rendered during rendering to the RenderTarget2D through a Matrix in the SpriteBatch.Draw method, so there's nothing weird going on there. The Camera itself works fine at any resolution.

After days of guesswork, this is the closest method I've got:

Rectangle r = Globals.Draw.CalculateRenderTargetPosition();
MouseState ms = Mouse.GetState();

Single aspect = Globals.WindowSize.Width / (Single)Globals.WindowSize.Height;
Single pmx = (ms.X - r.X);
Single pmy = (ms.Y - r.Y);
Single mx = (pmx == 0 ? pmx : pmx / aspect);
Single my = (pmy == 0 ? pmy : pmy / aspect);
Vector2 pos = Vector2.Transform(new Vector2(mx, my),
    Matrix.Invert(Globals.Camera.GetViewMatrix()));
Globals.RelativeMousePosition = new Vector2(pos.X, pos.Y);

Even if this is almost close enough, it's still off. I don't know if there's some magical Matrix method I don't know about or if I just suck at math.

\$\endgroup\$
1
  • \$\begingroup\$ I've been using this for years: mouseWorldPos = Vector2.Transform(mousePos, Matrix.Invert(view)); As long as view is the same matrix supplied during rendering you should be good too go. \$\endgroup\$ Aug 15, 2017 at 9:23

1 Answer 1

1
\$\begingroup\$

Well, after even more searching, tinkering, guessing, repeat, I've mostly (not 100% perfect but close enough to work with) got the mouse translation working.

Rectangle r = Globals.Draw.CalculateRenderTargetPosition();
MouseState ms = Mouse.GetState();
Matrix cam = Globals.Camera.GetViewMatrix();

Single aspect = Globals.WindowSize.Width / (Single)Globals.WindowSize.Height;
Vector2 pos = Vector2.Transform(new Vector2(
        Extra.SafeDivision((ms.X - r.X), aspect) * Extra.SafeDivision(1, Globals.Camera.Zoom),
        Extra.SafeDivision((ms.Y - r.Y), aspect) * Extra.SafeDivision(1, Globals.Camera.Zoom)), 
    Matrix.Invert(cam));
this.Position = new Vector2((Single)Math.Round(pos.X), (Single)Math.Round(pos.Y));

This isn't flawless, it's still off, but only a little bit, the code thinks the mouse is actually a few more pixels ahead of the real cursor's X/Y positions. But I decided to just hide the real cursor and render an in-game one, works fine and you can't even tell the difference. I'm not going to mark this as solved, because it's wrong, but it's still a close-enough answer.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .