Orthographic 2d camera Google-maps like zoom system

Hi guys,

I am implementing a zoom system in the game to be a bit google-maps like. i.e. if you zoom in, the worldspace is being locked in position under the mouse pointer, exactly like google maps does.

I think i am fairly close to a script that handles that, but somehow something still fails in the camera position. The zoom itself back and forward with the mouse wheel works smoothly, but this “lock on pointer” effect keeps on failing. This is how i did so far, i am sooo stupid it’s some small thing related to the coordinates spaces, but somehow i can’t nail it.

//zoom in the map
    public void ZoomIn(){
        zoomIn = true;

        oldNormalizedScale = (targetOrtho - orthographicSizeMin) / (orthographicSizeMax- orthographicSizeMin);

        targetOrtho = Mathf.Clamp(mainCamera.orthographicSize-zoomSpeed, orthographicSizeMin, orthographicSizeMax );

        normalizedScale = (targetOrtho - orthographicSizeMin) / (orthographicSizeMax- orthographicSizeMin);

        minX = (1f-normalizedScale)*lowerLeft.x;
        minY = (1f-normalizedScale)*lowerLeft.y;
        maxX = (1f-normalizedScale)*upperRight.x;
        maxY = (1f-normalizedScale)*upperRight.y;

        maxLowerLeft = new Vector2 (minX, minY);
        maxUpperRight = new Vector2 (maxX, maxY);

        if (normalizedScale > 0) {

            Vector3 mousePos = mainCamera.ScreenToWorldPoint (Input.mousePosition);

            float scaleFactor = (oldNormalizedScale/normalizedScale);

//calculate the difference between the current zoom level mouse-cameraCenter vector and the same vector scaled according to the new zoom level
            offsetCamera = (mousePos - mainCamera.transform.position)-(mousePos - mainCamera.transform.position) / scaleFactor;

            moveCameraTo = new Vector3 (Mathf.Clamp (mainCamera.transform.position.x + offsetCamera.x, maxLowerLeft.x, maxUpperRight.x), Mathf.Clamp (mainCamera.transform.position.y + offsetCamera.y, maxLowerLeft.y, maxUpperRight.y), mainCamera.transform.position.z);

            mainCamera.transform.position = moveCameraTo;

        }
    }

It just doesn’t work, the camera moves a bit, probably also in the right direction, but somehow not as it should (i.e. the map still moves under the pointer and is not locked there).

Any help would be absolutely welcome!
Cheers,
H

1 Like

I modified line 26, and the algo is now “close” to working, but still the “locking” of the world space point is far from perfect, it’s almost there but not fully there.

I am wondering if it might be some approximation problem, but i can’t see any part of the code where something so “relevant” might be happening as the data stays in float format all along the code.

Again, any help or idea would be very welcome!

1 Like

And as usual, the solution was much simpler than expected. And as usual i would headbutt the wall for how much time I spent on a simple issue. Here’s the working zoom version (the camera scaling is done in the Update call). The problem was just that i was extracting the scaling factor out of the normalized sizes instead than (much easier) out of the real current scale/post zoom scale.

//zoom in the map
    public void ZoomIn(){
        zoomIn = true;

        //determine the zooming in target size (already clamped)
        targetOrtho = Mathf.Clamp(mainCamera.orthographicSize-zoomSpeed, (float)orthographicSizeMin, (float)orthographicSizeMax );

        //determine the new normalized scale
        normalizedScale = (targetOrtho - orthographicSizeMin) / (orthographicSizeMax- orthographicSizeMin);

        //update the dragging speed according to scale
        draggingSpeed = minScaleSpeed+(maxScaleSpeed-minScaleSpeed)*normalizedScale;

        minX = (1f-normalizedScale)*lowerLeft.x;
        minY = (1f-normalizedScale)*lowerLeft.y;
        maxX = (1f-normalizedScale)*upperRight.x;
        maxY = (1f-normalizedScale)*upperRight.y;

        maxLowerLeft = new Vector2 (minX, minY);
        maxUpperRight = new Vector2 (maxX, maxY);

        Vector3 mousePos = mainCamera.ScreenToWorldPoint (Input.mousePosition);
        offsetCamera = (mousePos - mainCamera.transform.position)-((mousePos - mainCamera.transform.position) / (mainCamera.orthographicSize/targetOrtho));
        mainCamera.transform.position = new Vector3 (Mathf.Clamp (mainCamera.transform.position.x + offsetCamera.x, maxLowerLeft.x, maxUpperRight.x), Mathf.Clamp (mainCamera.transform.position.y + offsetCamera.y, maxLowerLeft.y, maxUpperRight.y), mainCamera.transform.position.z);

    }
1 Like

Thanks DrHogan! This wasn’t the code I needed, but reading your post allowed me to understand the concept perfectly and implement what I did need! Cheers!

1 Like

Hi guys, is something like this possible with perspective projection and incorporated orbit and pan?