Unity,Android:如何正确设置游戏的aspect/scale

Unity, Android: how to set the aspect/scale of the game properly

我使用 Unity 开发了一个 Android 游戏。最后我遇到了下一个问题:

我游戏的每个关卡在屏幕两侧都有严格的边框(如方框)。我一直在用 方面 9:16(图 1) 开发游戏。当我在我的 phone(它是 9:19.5)上构建它和 运行 时,我发现 关卡的最左边和最右边的部分在屏幕之外 (图2).

我该如何解决这个问题,让游戏适合所有纵横比?

我尝试过不同的解决方案,但没有一个让我满意。我非常绝望,我已经同意将它从 9:16 缩小,以便它适合屏幕的宽度,并在顶部和底部添加黑条 (图片。 3)。高度在我的游戏中不是那么重要,但宽度是至关重要的。 或者有更好的解决办法吗?

更新 2: 我的项目设计(有点灰盒): 这是 FINE 在播放模式下不同方面的外观: 下面是它在播放模式下的不同方面 POORLY 的样子:

所以,我找到了实现目标的方法。 我在场景中添加了一个空的游戏对象,并将所有关卡结构添加到它,并添加了两个黑条(作为简单的立方体)高于和低于水平。通过这种方法,我可以缩放该父游戏对象,以便所有关卡结构 按比例缩放 。 我所要做的就是创建一个脚本,根据屏幕的宽度缩放父游戏对象。

Unity 的相机假定游戏将以横向进行。因此,无论宽高比如何,垂直呈现的游戏世界的数量在任何屏幕上都将始终相同。如果你限制你的游戏只能在移动平台上玩,并且只能在纵向模式下玩,那么你会想要强制 Unity 做相反的事情。您希望相机始终呈现相同的宽度,并根据宽高比显示可变的高度。 (有用的提示:使用您期望的最小纵横比进行开发,例如 4:5,而不是 9:16。在游戏视图顶部的下拉菜单中配置您要测试的所有纵横比或分辨率. 在这些之间切换以进行测试,并允许您的 UI 和游戏视图向外扩展以获得更高的宽高比。否则您的 UI 可能会 运行 在较小的宽高比​​上。请参阅我的 post 在 CanvasScaler here.)

无论如何,要更改默认相机行为,您需要向相机添加脚本。应该这样做:

编辑: 我修改了组件以处理透视相机和正交相机。根据您的游戏,您似乎正在或应该正在使用正交相机,而我之前的回答并未处理。此外,组件上没有更多属性。只需连接到相机,然后照常使用相机的属性。此外,它现在可以处理视口,因此它可以与不占据整个屏幕的相机一起使用。

存在 1 个已知问题。使用正交相机,如果您尝试将视口调整为大于整个屏幕尺寸,Unity 内部的某些东西会重置投影矩阵并覆盖该组件的行为。要修复,只需切换组件,或重新加载场景或编辑器,任何触发组件再次执行其操作的东西。

using UnityEngine;

[ExecuteAlways]
[RequireComponent(typeof(Camera))]
public class HorizontallyAlignedCamera : MonoBehaviour
{
    private Camera _camera;
    private float _aspectRatio;
    private float _fieldOfView;
    private bool _isOrthographic;
    private float _orthographicSize;

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

    private void OnEnable()
    {
        CachePropertiesAndRecalculate();
    }

    private void LateUpdate()
    {
        if(CameraPropertyHasChanged())
            CachePropertiesAndRecalculate();
    }

    private void OnDisable()
    {
        _camera.ResetProjectionMatrix();
    }

    private bool CameraPropertyHasChanged()
    {
        bool hasChanged = (_aspectRatio != _camera.aspect
            || _fieldOfView != _camera.fieldOfView
            || _isOrthographic != _camera.orthographic
            || _orthographicSize != _camera.orthographicSize);

        return hasChanged;
    }

    private void CacheCameraProperties()
    {
        _aspectRatio = _camera.aspect;
        _fieldOfView = _camera.fieldOfView;
        _isOrthographic = _camera.orthographic;
        _orthographicSize = _camera.orthographicSize;
    }

    private void CachePropertiesAndRecalculate()
    {
        CacheCameraProperties();

        if(_camera.orthographic)
            RecalculateOrthographicMatrix();
        else
            RecalculatePerspectiveMatrix();
    }

    private void RecalculatePerspectiveMatrix()
    {
        float near = _camera.nearClipPlane;
        float nearx2 = near * 2.0f;
        float far = _camera.farClipPlane;
        float halfFovRad = _camera.fieldOfView * 0.5f * Mathf.Deg2Rad;

        // This is what aligns the camera horizontally.
        float width = nearx2 * Mathf.Tan(halfFovRad);
        float height = width / _camera.aspect;

        // This is the default behavior.
        //float height = nearx2 * Mathf.Tan(halfFovRad);
        //float width = height * _camera.aspect;

        float a = nearx2 / width;
        float b = nearx2 / height;
        float c = -(far + near) / (far - near);
        float d = -(nearx2 * far) / (far - near);

        Matrix4x4 newProjectionMatrix = new Matrix4x4(
            new Vector4(a, 0.0f, 0.0f, 0.0f),
            new Vector4(0.0f, b, 0.0f, 0.0f),
            new Vector4(0.0f, 0.0f, c, -1.0f),
            new Vector4(0.0f, 0.0f, d, 0.0f));

        _camera.projectionMatrix = newProjectionMatrix;
    }

    private void RecalculateOrthographicMatrix()
    {
        // This is what aligns the camera horizontally.
        float width = 2.0f * _camera.orthographicSize;
        float height = width / _camera.aspect;

        // This is the default behavior.
        //float height = 2.0f * _camera.orthographicSize;
        //float width = height * _camera.aspect;

        float near = _camera.nearClipPlane;
        float far = _camera.farClipPlane;
        float a = 2.0f / width;
        float b = 2.0f / height;
        float c = -2.0f / (far - near);
        float d = -(far + near) / (far - near);

        Matrix4x4 newProjectionMatrix = new Matrix4x4(
            new Vector4(a, 0.0f, 0.0f, 0.0f),
            new Vector4(0.0f, b, 0.0f, 0.0f),
            new Vector4(0.0f, 0.0f, c, 0.0f),
            new Vector4(0.0f, 0.0f, d, 1.0f));

        _camera.projectionMatrix = newProjectionMatrix;
    }
}