在 Unity 的缩放功能中将相机移动到适当的位置

Moving camera to proper position in Zoom function in Unity

您好,我有一个问题希望有人能帮助我解决。我已经在别处问过但无济于事,但这似乎是一个标准问题,所以我不确定为什么我没有得到答案。

它基本上设置了镜像 Google 地图缩放的缩放功能。比如,相机将 in/out 缩放到鼠标所在的位置。我知道这可能会被问到很多,但我认为自从我在自己的研究中发现的 4-6 年前的问题以来,Unity 的新输入系统改变了一些东西。

无论如何,我已经设置了一个父游戏对象,它包含将出现在我的场景中的所有 2D 精灵和一个正交相机。我可以通过代码设置正交大小以更改为缩放,但是它将相机移动到我遇到问题的正确位置。

这是我的第一次尝试:

public Zoom(float direction, Vector2 mousePosition) {
    // zoom calcs
    float rate 1 + direction * Time.deltaTime;
    float targetOrtho = Mathf.MoveTowards(mainCam.orthographicSize, mainCam.orthoGraphicSize/rate, 0.1f);

    // move calcs
    mousePosition = mainCam.ScreenToWorldPoint(mousePosition);
    Vector2 deltaPosition = previousPosition - mousePosition;
    
    // move and zoom    
    transform.position += new Vector3(deltaPosition.x, deltaPosition.y, 0);
    // zoomLevels are a generic struct that holds the max/min values.
    SetZoomLevel(Mathf.Clamp(targetOrthoSize, zoomLevels.min, zoomLevels.max));

    previousPosition = mousePosition;
}

此函数通过我的输入控制器调用,通过 Unity 的输入系统事件激活。当鼠标滚轮滚动时,缩放函数被赋予一个归一化值 direction(1 或 -1)和当前值 mousePosition。完成计算后,mousePosition 存储在 previousPosition.

该代码确实有效——只是它非常不稳定。这当然会发生,因为没有 Time.deltaTime 应用于相机移动,LateUpdate 中也没有;两者都有助于平滑运动。除了在前一种情况下,将 Time.deltaTime 乘以 new Vector3(deltaPosition.x, deltaPosition.y, 0) 似乎会导致缩放发生在相机的中心而不是鼠标位置。当我将变焦设置为 LateUpdate 时,它会在相机移动时产生很酷但不想要的振动效果。

所以,经过一些思考和阅读,我认为最好计算鼠标位置和相机中心点之间的差异,然后乘以一个比例因子,即相机的正交尺寸 * 2 (可能是...??)。因此我在这里更新了代码:


    public void Zoom(float direction, Vector2 mousePosition)
    {
        // zoom
        float rate = 1 + direction * Time.unscaledDeltaTime * zoomSpeed;
        float orthoTarget = Mathf.MoveTowards(mainCam.orthographicSize, mainCam.orthographicSize * rate, maxZoomDelta);
    
        SetZoomLevel(Mathf.Clamp(orthoTarget, zoomLevels.min, zoomLevels.max));
    
        // movement
        if (mainCam.orthographicSize < zoomLevels.max && mainCam.orthographicSize > zoomLevels.min)
        {
            mousePosition = mainCam.ScreenToWorldPoint(mousePosition);
            Vector2 offset = (mousePosition - new Vector2(transform.position.x, transform.position.y)) / (mainCam.orthographicSize * 2);
    
            // panPositions are the same generic struct holding min/max values
            offset.x = Mathf.Clamp(offset.x, panPositions.min.x, panPositions.max.x);
            offset.y = Mathf.Clamp(offset.y, panPositions.min.y, panPositions.max.y);
    
            transform.position += new Vector3(offset.x, offset.y, 0) * Time.deltaTime;
        }
     }

这似乎 有点 接近我想要实现的目标,但相机仍然在其中心点附近放大并缩小 一些 点...我有点迷失在这里我错过了什么。

是否有人能够帮助指导我思考我需要做什么才能在鼠标当前所在的位置创建平滑缩放 in/out?非常感谢并感谢您阅读本文。

好的,如果有人遇到过同样的问题,我已经知道了。它一个标准问题,一旦你掌握了数学知识就很容易解决。

基本上,这是缩放和平移相机的问题。你可以先做一个或另一个——没关系;结果是一样的。想象一下您的屏幕是这样的:

绿框是您的相机视口,箭头是您的光标。放大时,正交尺寸变小并围绕其锚点(通常为 P1(0,0))缩小。这是问题的缩放方面,下图很好地解释了它:

所以,现在我们要将相机位置移动到新位置:

那么我们该怎么做呢?这只是获取从旧相机位置 (P1(0, 0)) 到新相机位置 (P2(x,y)) 的距离的问题。基本上,我们只想要这个:

我找到上图中箭头长度的解决方案基本上是从光标位置的长度减去旧相机位置(oldLength)光标位置的长度到新的相机位置(newLength)。

但是您如何找到 newLength?好吧,因为我们知道长度会根据相机视口的大小进行缩放,所以 newLength 将是 oldLength / scaleFactoroldLength * scaleFactor,具体取决于您是要放大还是缩小,分别。比例因子可以是任何你想要的(缩放 in/out 2, 4, 1.4...等等)。

从那里开始,只需从 oldLength 中减去 newLength 并加上当前相机位置的差异即可。伪代码如下:

(请注意,我将 'newLength' 更改为 'length',将 'oldLength' 更改为 'scaledLength')

// make sure you're working in world space
mousePosition = camera.ScreenToWorldPoint(mousePosition);

length = mousePosition - currentCameraPosition;
scaledLength = length / scaleFactor // to zoom in, otherwise its length * scaleFactor
deltaLength = length - scaledLength;

// change position
cameraPosition = currentCameraPosition - deltaLength;
// do zoom
camera.orthographicSize /= scaleFactor  // to zoom in, otherwise orthographic size *= scaleFactor

非常适合我。感谢那些在不和谐编码社区中帮助过我的人!