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;
}
}
我使用 Unity 开发了一个 Android 游戏。最后我遇到了下一个问题:
我游戏的每个关卡在屏幕两侧都有严格的边框(如方框)。我一直在用 方面 9:16(图 1) 开发游戏。当我在我的 phone(它是 9:19.5)上构建它和 运行 时,我发现 关卡的最左边和最右边的部分在屏幕之外 (图2).
我该如何解决这个问题,让游戏适合所有纵横比?
我尝试过不同的解决方案,但没有一个让我满意。我非常绝望,我已经同意将它从 9:16 缩小,以便它适合屏幕的宽度,并在顶部和底部添加黑条 (图片。 3)。高度在我的游戏中不是那么重要,但宽度是至关重要的。 或者有更好的解决办法吗?
更新 2:
我的项目设计(有点灰盒):
所以,我找到了实现目标的方法。 我在场景中添加了一个空的游戏对象,并将所有关卡结构添加到它,并添加了两个黑条(作为简单的立方体)高于和低于水平。通过这种方法,我可以缩放该父游戏对象,以便所有关卡结构 按比例缩放 。 我所要做的就是创建一个脚本,根据屏幕的宽度缩放父游戏对象。
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;
}
}