Zoom toward mouse (eg. Google maps)

2019-06-16 05:33发布

问题:

I've written a home-brew view_port class for a 2D strategy game. The panning (with arrow keys) and zooming (with mouse wheel) work fine, but I'd like the view to also home towards wherever the cursor is placed, as in Google Maps or Supreme Commander

I'll spare you the specifics of how the zoom is implemented and even what language I'm using: this is all irrelevant. What's important is the zoom function, which modifies the rectangle structure (x,y,w,h) that represents the view. So far the code looks like this:

void zoom(float delta, float mouse_x, float mouse_y)
{
    zoom += delta;
    view.w = window.w/zoom;
    view.h = window.h/zoom;  
    // view.x = ???
    // view.y = ???
}

Before somebody suggests it, the following will not work:

view.x = mouse_x - view.w/2;
view.y = mouse_y - view.h/2;

This picture illustrates why, as I attempt to zoom towards the smiley face:

As you can see when the object underneath the mouse is placed in the centre of the screen it stops being under the mouse, so we stop zooming towards it!

If you've got a head for maths (you'll need one) any help on this would be most appreciated!

回答1:

I managed to figure out the solution, thanks to a lot of head-scratching a lot of little picture: I'll post the algorithm here in case anybody else needs it.

Vect2f mouse_true(mouse_position.x/zoom + view.x, mouse_position.y/zoom + view.y);
Vect2f mouse_relative(window_size.x/mouse_pos.x, window_size.y/mouse_pos.y);   
view.x = mouse_true.x - view.w/mouse_relative.x;
view.y = mouse_true.y - view.h/mouse_relative.y;

This ensures that objects placed under the mouse stay under the mouse. You can check out the code over on github, and I also made a showcase demo for youtube.



回答2:

In my concept there is a camera and a screen. The camera is the moving part. The screen is the scalable part.

I made an example script including a live demo. The problem is reduced to only one dimension in order to keep it simple. https://www.khanacademy.org/cs/cam-positioning/4772921545326592

var a = (mouse.x + camera.x) / zoom;

// now increase the zoom e.g.: like that:
zoom = zoom + 1;

var newPosition = a * zoom - mouse.x;

camera.setX(newPosition);
screen.setWidth(originalWidth * zoom);

For a 2D example you can simply add the same code for the height and y positions.