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

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

这是透视pov:

移动相机比改变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); } 

视野可以这样计算:

 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; } 

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

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

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

距相机一定距离的Frustum的大小

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

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

 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(); } 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; } } 

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