解决Unity正交视图大小随窗口变化问题
2025-01-26 07:07:30
正交视图大小随窗口变化问题
正交投影视图(Orthographic projection view)在游戏开发中常用于2D游戏,其特点是平行线在投影后依然平行,物体大小不随距离改变。当游戏窗口尺寸改变时,正交视图内的物体大小可能会出现变化,这通常是由多种原因造成的。本文将讨论此类问题的产生原因,并提供几种有效的解决方法。
问题根源
问题的核心在于,游戏内的物体渲染是基于特定视图大小计算的,当窗口尺寸改变,而视图大小没有随之调整时,渲染系统会根据新的窗口尺寸缩放游戏内容,这导致了物体看起来变大或变小。
在提供的代码示例中,直接修改了窗口的像素高度,却没有对正交摄像机的投影范围进行同步调整。例如,窗口高度增加时,如果正交摄像机的显示范围维持不变,相当于游戏内容被“放大”到新的窗口大小,所以对象看起来变大了。相反,窗口高度降低则会导致内容看起来变小。
解决方法
这里将介绍几种不同的解决方式,让你的游戏对象大小保持不变。
方案一:调整正交摄像机大小
最直接的方式是在每次窗口尺寸变化时,同步调整正交摄像机的可视范围。摄像机的orthographicSize
属性(例如,在 Unity 中)控制着摄像机的垂直可视范围,因此当窗口的纵横比改变时,就需要调整此值,以保证游戏内容比例正确,看起来没有被拉伸或挤压。
操作步骤:
- 获取当前窗口的纵横比。
- 根据新的纵横比,计算需要调整的正交摄像机尺寸。
- 更新摄像机的
orthographicSize
属性。
示例代码(C# Unity):
using UnityEngine;
public class CameraSizeAdjuster : MonoBehaviour
{
public Camera orthographicCamera;
private void Start()
{
AdjustCameraSize();
}
void Update()
{
//检查窗口大小是否改变。
if(Screen.width!= _lastWidth || Screen.height!= _lastHeight){
AdjustCameraSize();
_lastWidth = Screen.width;
_lastHeight=Screen.height;
}
}
int _lastWidth=0;
int _lastHeight=0;
void AdjustCameraSize()
{
if (orthographicCamera == null) return;
float targetAspect = (float)Screen.width / Screen.height;
float originalAspect =(float)orthographicCamera.pixelWidth/orthographicCamera.pixelHeight;
if(targetAspect != originalAspect){
orthographicCamera.orthographicSize =orthographicCamera.orthographicSize *(originalAspect / targetAspect) ;
}
}
}
此代码段中,AdjustCameraSize
函数计算了当前的屏幕纵横比和摄像机的像素纵横比,如果纵横比不同,会按比例缩放正交摄像机大小。
方案二:使用固定的渲染分辨率
这种方案下,游戏的渲染尺寸始终保持一致。例如,可以将游戏渲染到固定的纹理,然后将其缩放到屏幕尺寸。即使窗口尺寸改变,渲染纹理的分辨率始终不变,确保了正交投影视图下对象的大小不变化。
操作步骤:
- 创建一个渲染纹理(Render Texture)。
- 配置摄像机将渲染输出到此纹理。
- 将纹理绘制到屏幕。
- 调整绘制时使用的缩放比例来适配不同大小的窗口。
示例代码 (使用RenderTexture and Screen Overlay 方式):
using UnityEngine;
using UnityEngine.UI;
public class FixedResolutionRenderer : MonoBehaviour
{
public int fixedWidth = 800;
public int fixedHeight = 600;
public RawImage rawImage; // Reference to UI Raw Image
public Camera renderCamera;
private RenderTexture renderTexture;
void Start()
{
CreateRenderTexture();
UpdateRawImageRect();
// 设置相机目标纹理
renderCamera.targetTexture = renderTexture;
}
private void CreateRenderTexture() {
if (renderTexture != null) renderTexture.Release();
renderTexture=new RenderTexture(fixedWidth,fixedHeight,0);
}
void Update()
{
if(rawImage!= null ) {
float aspectRatio=(float)Screen.width / Screen.height;
RectTransform transform = rawImage.GetComponent<RectTransform>();
// 根据纵横比适配显示比例
if( aspectRatio >= (float)fixedWidth / fixedHeight ){
float targetHeight= Screen.height;
float targetWidth = Screen.height * ((float)fixedWidth/fixedHeight) ;
transform.sizeDelta=new Vector2(targetWidth,targetHeight);
}else
{
float targetWidth = Screen.width;
float targetHeight = Screen.width *( (float)fixedHeight /fixedWidth) ;
transform.sizeDelta=new Vector2(targetWidth,targetHeight);
}
}
}
//将RenderTexture 纹理 更新到RawImage上
private void UpdateRawImageRect() {
if (renderTexture==null) {return ; }
rawImage.texture = renderTexture;
}
}
该示例创建了一个指定大小的渲染纹理,并让摄像机渲染到此纹理,接着它将这个纹理放到UI RawImage 控件上,然后适配UI 元素大小使其自适应屏幕。
方案三:结合 Canvas Scaler 组件使用 (Unity)
如果使用的是 Unity 的 UI 系统,Canvas Scaler 组件提供了一种非常便利的解决屏幕缩放的方法。该组件可以根据窗口大小自动缩放 UI 元素。
操作步骤:
- 在 Canvas 组件中添加 Canvas Scaler 组件。
- 设置
UI Scale Mode
为Scale With Screen Size
。 - 配置
Reference Resolution
以指定设计分辨率。
通过合理配置 Match
和其他选项,可以让 UI 和场景元素一起按需缩放。
安全建议
- 定期备份你的项目,防止代码改动出现意外情况。
- 逐步测试每一个修改,确认每个解决方案是否符合预期。
- 在部署前,尽可能在不同分辨率下进行测试。
选择哪种解决方案取决于项目需求,对技术点的熟悉程度,以及团队的工作习惯,请综合考量。正确理解这些方案的原理,将帮助你更加高效的进行游戏开发。