일지

유니티 화면 비율 고정 처리...10

niamdank 2021. 10. 5. 18:43

화면 비율 고정 처리 동작 안 하는 경우 확인

비율 처리가 동작하지 않는 경우에 대한 처리를 확인하기 위해 코드를 조금 정리해서 상태에 따라 값을 출력하도록 했다.

 

ResolutionController.cs

using System;
using System.Collections;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;

public class ResolutionController : MonoBehaviour
{
    public float AspectX { get; set; } = 16;
    public float AspectY { get; set; } = 9;

	public Text m_debugText;

	#region ENUMERATIONS
	private enum Cursors
	{
		IDC_ARROW = 32512,
		IDC_SIZENESW = 32643,
		IDC_SIZENS = 32645,
		IDC_SIZENWSE = 32642,
		IDC_SIZEWE = 32644,
	}

	private enum UpdateState
	{
		Waiting,
		Changing,
		Updating,
	}
	#endregion

	#region WINAPI_DLL
	[StructLayout(LayoutKind.Sequential)]
	public struct POINT
	{
		public Int32 x;
		public Int32 y;
	}

	private const int VK_LBUTTON = 0x01;
	private const ushort KEY_HOLD = 0x8000;

	[DllImport("user32.dll")]
	private static extern IntPtr GetCursor();

	[DllImport("user32.dll")]
	private static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);

	[DllImport("user32.dll")]
	private static extern ushort GetAsyncKeyState(ushort vKey);
	#endregion

	#region WINAPI_VARIABLES
	private IntPtr CursorNESW { get; set; }
	private IntPtr CursorNS { get; set; }
	private IntPtr CursorNWSE { get; set; }
	private IntPtr CursorWE { get; set; }
	#endregion

	private float m_aspectRatio;

	private int m_screenSizeX;
	private int m_screenSizeY;

	private UpdateState m_updateState;

	private void Start()
	{
        m_aspectRatio = AspectX / AspectY;

        m_screenSizeX = Screen.width;
        m_screenSizeY = Screen.height;

		Initialize();
	}

	private void Initialize()
	{
		CursorNESW = LoadCursor(IntPtr.Zero, (int)Cursors.IDC_SIZENESW);
		CursorNS = LoadCursor(IntPtr.Zero, (int)Cursors.IDC_SIZENS);
		CursorNWSE = LoadCursor(IntPtr.Zero, (int)Cursors.IDC_SIZENWSE);
		CursorWE = LoadCursor(IntPtr.Zero, (int)Cursors.IDC_SIZEWE);

		m_updateState = UpdateState.Waiting;

		m_debugText.text = $"Update State : {m_updateState}";
	}

	private void Update()
	{
		IntPtr hCursor = GetCursor();
		
		if (m_updateState == UpdateState.Waiting && IsChanging(hCursor) && IsMouseButtonClicked())
		{
			m_updateState = UpdateState.Changing;
			m_debugText.text = $"Update State : {m_updateState}";
		}
		else if(m_updateState == UpdateState.Changing && !IsMouseButtonClicked())
		{
			StartCoroutine(SetFixedResolution());
		}
	}

	private IEnumerator SetFixedResolution()
	{
		m_updateState = UpdateState.Updating;
		m_debugText.text = $"Update State : {m_updateState}";
		int newScreenSizeX = Screen.width;
		int newScreenSizeY = Screen.height;

		if (newScreenSizeX != m_screenSizeX && newScreenSizeY != m_screenSizeY)
		{
			if (Mathf.Abs(newScreenSizeX - m_screenSizeX) > Mathf.Abs(newScreenSizeY - m_screenSizeY))
			{
				newScreenSizeY = Mathf.FloorToInt(newScreenSizeX / m_aspectRatio);
			}
			else
			{
				newScreenSizeX = Mathf.FloorToInt(newScreenSizeY * m_aspectRatio);
			}
		}
		else if (newScreenSizeX != m_screenSizeX)
		{
			newScreenSizeY = Mathf.FloorToInt(newScreenSizeX / m_aspectRatio);
		}
		else
		{
			newScreenSizeX = Mathf.FloorToInt(newScreenSizeY * m_aspectRatio);
		}

		m_screenSizeX = newScreenSizeX;
		m_screenSizeY = newScreenSizeY;

		Screen.SetResolution(m_screenSizeX, m_screenSizeY, false);

		yield return null;

		m_updateState = UpdateState.Waiting;
		m_debugText.text = $"Update State : {m_updateState}";
	}

	private bool IsChanging(IntPtr hCursor)
	{
		if (hCursor == CursorNESW) return true;
		if (hCursor == CursorNS) return true;
		if (hCursor == CursorNWSE) return true;
		if (hCursor == CursorWE) return true;
		return false;
	}

	private bool IsMouseButtonClicked()
	{
		return (GetAsyncKeyState(VK_LBUTTON) & KEY_HOLD) != 0;
	}
}

 

빌드 후 실행 결과는 다음과 같다.

상태 변경 테스트

 

아마 변경 과정에 SetResolution이 씹히고 있는 게 아닐까 한다.

 

생각해 볼 수 있는 처리 방법으로는 변경 후 대기 시간을 조금 늘려주거나 확실히 변경될 수 있도록 여러 번 과정을 반복시키는 방법이 있을 것 같다.