如何通过缩放视野来始终保持2个对象在视图中? (或z和y轴)

问题描述 投票:6回答:5

我正在为2名玩家制作一个小街机射击游戏,并且需要让屏幕聚焦于2个玩家,我让相机在X轴的玩家中心移动,但是我认为当2玩家靠得更近,相机也越来越近了。

这是透视pov:

c# unity3d
5个回答
13
投票

移动相机比改变fov更好。计算相机距离的公式是

cameraDistance = (distanceBetweenPlayers / 2 / aspectRatio) / Tan(fieldOfView / 2);

请注意,玩家出现在视口的边缘,因此可以添加一些小的边距。这是我的脚本:

public Transform player1;
public Transform player2;

private const float DISTANCE_MARGIN = 1.0f;

private Vector3 middlePoint;
private float distanceFromMiddlePoint;
private float distanceBetweenPlayers;
private float cameraDistance;
private float aspectRatio;
private float fov;
private float tanFov;

void Start() {
    aspectRatio = Screen.width / Screen.height;
    tanFov = Mathf.Tan(Mathf.Deg2Rad * Camera.main.fieldOfView / 2.0f);
}

void Update () {
    // Position the camera in the center.
    Vector3 newCameraPos = Camera.main.transform.position;
    newCameraPos.x = middlePoint.x;
    Camera.main.transform.position = newCameraPos;

    // Find the middle point between players.
    Vector3 vectorBetweenPlayers = player2.position - player1.position;
    middlePoint = player1.position + 0.5f * vectorBetweenPlayers;

    // Calculate the new distance.
    distanceBetweenPlayers = vectorBetweenPlayers.magnitude;
    cameraDistance = (distanceBetweenPlayers / 2.0f / aspectRatio) / tanFov;

    // Set camera to new position.
    Vector3 dir = (Camera.main.transform.position - middlePoint).normalized;
    Camera.main.transform.position = middlePoint + dir * (cameraDistance + DISTANCE_MARGIN);
}

2
投票

视野可以这样计算:

FOV = 2 * arctan((0.5 * distanceBetweenPlayers) / (distanceFromMiddlePoint * aspectRatio));

请注意,这给出了FOV,其中玩家位于视口的边缘。可以增加小幅度。我想自己尝试一下,这是我的脚本:

public Transform player1;
public Transform player2;

private const float FOV_MARGIN = 15.0f;

private Vector3 middlePoint;
private float distanceFromMiddlePoint;
private float distanceBetweenPlayers;
private float aspectRatio;

void Start () {
    aspectRatio = Screen.width / Screen.height;
}

void Update () {
    // Find the middle point between players.
    middlePoint = player1.position + 0.5f * (player2.position - player1.position);

    // Position the camera in the center.
    Vector3 newCameraPos = Camera.main.transform.position;
    newCameraPos.x = middlePoint.x;
    Camera.main.transform.position = newCameraPos;

    // Calculate the new FOV.
    distanceBetweenPlayers = (player2.position - player1.position).magnitude;
    distanceFromMiddlePoint = (Camera.main.transform.position - middlePoint).magnitude;
    Camera.main.fieldOfView = 2.0f * Mathf.Rad2Deg * Mathf.Atan((0.5f * distanceBetweenPlayers) / (distanceFromMiddlePoint * aspectRatio));

    // Add small margin so the players are not on the viewport border.
    Camera.main.fieldOfView += FOV_MARGIN;
}

如果视野变大,我建议移动相机,因为视角会因较大的视野而扭曲。


1
投票

jparimaa的回答对我有很大的帮助,但是对于我来说,它对于狭窄的屏幕(例如手机肖像模式)并不起作用。这是因为它只考虑了高度计算,导致两个玩家在垂直靠近时远离屏幕水平。

我更新它以正确计算高度和宽度情况下的相机距离。计算来自Unity docs(与jparimaa相同):

The Size of the Frustum at a Given Distance from the Camera

另请注意:Camera.fieldOfView是垂直视野

我最终得到了以下适用于我的情况的代码:多个太空船带有3D透视摄像头,可在2D(x-z)平面上控制:

using UnityEngine;

public class MeleeCamera : MonoBehaviour
{
    public Transform[] targets;
    public float padding = 15f; // amount to pad in world units from screen edge

    Camera _camera;
    void Awake()
    {
        _camera = GetComponent<Camera>();
    }

    private void LateUpdate() // using LateUpdate() to ensure camera moves after everything else has
    {
        Bounds bounds = FindBounds();

        // Calculate distance to keep bounds visible. Calculations from:
        //     "The Size of the Frustum at a Given Distance from the Camera": https://docs.unity3d.com/Manual/FrustumSizeAtDistance.html
        //     note: Camera.fieldOfView is the *vertical* field of view: https://docs.unity3d.com/ScriptReference/Camera-fieldOfView.html
        float desiredFrustumWidth = bounds.size.x + 2 * padding;
        float desiredFrustumHeight = bounds.size.z + 2 * padding;

        float distanceToFitHeight = desiredFrustumHeight * 0.5f / Mathf.Tan(_camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
        float distanceToFitWidth = desiredFrustumWidth * 0.5f / Mathf.Tan(_camera.fieldOfView * _camera.aspect * 0.5f * Mathf.Deg2Rad);

        float resultDistance = Mathf.Max(distanceToFitWidth, distanceToFitHeight);

        // Set camera to center of bounds at exact distance to ensure targets are visible and padded from edge of screen 
        _camera.transform.position = bounds.center + Vector3.up * resultDistance;
    }

    private Bounds FindBounds()
    {
        if (targets.Length == 0)
        {
            return new Bounds();
        }

        Bounds bounds = new Bounds(targets[0].position, Vector3.zero);
        foreach (Transform target in targets)
        {
            if (target.gameObject.activeSelf) // if target not active
            {
                bounds.Encapsulate(target.position);
            }
        }

        return bounds;
    }
}

0
投票

为您的相机提供一系列缩放级别。使用两个字符之间的距离作为比率,以确定沿缩放范围的距离。


0
投票

只是为了补充@nokola的答案,(我还不能发表评论......)看起来他的相机只能超过物体,所以不要这样做:

_camera.transform.position = bounds.center + Vector3.up * resultDistance;

你可能会这样做:

_camera.transform.position = bounds.center + -_camera.transform.forward * resultDistance;

现在它应该适用于任何旋转相机。 (对我来说它至少做了)

© www.soinside.com 2019 - 2024. All rights reserved.