유니티 화면 비율 고정 처리...19
화면 조정 시 위치 바뀌는 버그 수정 시도
이전에 발생한 버그를 수정하기 위해 코드를 이것저것 수정해보고 있었는데, 일단 의심되는 건 WinProc을 교체하려고 했으나 교체되지 않고 기존 것에 추가로 적용이 되는 게 아닐까 하는 생각이 든다.
그래서 변경 전 크기, 위치와 변경 후 크기, 위치가 각각 전달되면서 문제가 되는 게 아닐까 싶다.
관련해서 서브 클래싱에 대한 정보를 찾게 되었는데 내용은 다음과 같다.
창 프로시저 사용 - Win32 apps | Microsoft Docs
창 프로시저 사용 - Win32 apps
이 섹션에서는 창 프로시저와 관련된 다음 작업을 수행하는 방법을 설명합니다.
docs.microsoft.com
서브클래싱
서브클래싱이란 쉽게 말해 윈도우 메세지를 가로채오는 것을 말한다.EDIT BOX → WM_KEYDOWN이런식으로 돌아가는데 내가 WM_KEYDOWN 메세지가 발생했을 때 다른 기능을 수행하고싶다하면EIDT BOX WM_KEYDOWN
egloos.zum.com
이것들을 확인해본 결과 WM_SIZE에 대한 처리를 새로운 WIN_PROC에서 받아서 수정한 뒤 기존 처리를 위해 전달하는 것으로 보인다.
정확하게 동작하고 있는지 확인하기 위해 WM_SIZE인 경우 메시지를 전달하는 대신 바로 종료하도록 한다.
그런데 빌드 후 실행한 결과 기존과 동일하게 사이즈가 변경되고 있는 것을 확인할 수 있었다.
이 처리가 교체되는 게 아닌가 싶어서 모든 경우에 기존 함수를 호출하지 않도록 한 경우 모든 메시지가 막히며 조작 자체가 불가능하게 되었다.
일단 마지막 시도로 Rect의 left와 top은 그대로 두고 크기만 바꿔서 right, bottom을 업데이트해주도록 했다.
winProc
IntPtr wndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
// Check message type.
// We are only interested in resize events, so ignore everything else.
if (msg == WM_SIZING)
{
// Get window size struct.
RECT rc = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT));
// Calculate window border width and height.
RECT windowRect = new RECT();
GetWindowRect(unityHWnd, ref windowRect);
RECT clientRect = new RECT();
GetClientRect(unityHWnd, ref clientRect);
int borderWidth = windowRect.Right - windowRect.Left - (clientRect.Right - clientRect.Left);
int borderHeight = windowRect.Bottom - windowRect.Top - (clientRect.Bottom - clientRect.Top);
// Remove borders (including window title bar) before applying aspect ratio.
rc.Right -= borderWidth;
rc.Bottom -= borderHeight;
// Clamp window size.
int newWidth = Mathf.Clamp(rc.Right - rc.Left, minWidthPixel, maxWidthPixel);
int newHeight = Mathf.Clamp(rc.Bottom - rc.Top, minHeightPixel, maxHeightPixel);
// Resize according to aspect ratio and resize direction.
switch (wParam.ToInt32())
{
case WMSZ_LEFT:
//rc.Left = rc.Right - newWidth;
//rc.Bottom = rc.Top + Mathf.RoundToInt(newWidth / aspect);
//break;
case WMSZ_RIGHT:
newHeight = Mathf.RoundToInt(newWidth / aspect);
//rc.Right = rc.Left + newWidth;
//rc.Bottom = rc.Top + Mathf.RoundToInt(newWidth / aspect);
break;
case WMSZ_TOP:
//rc.Top = rc.Bottom - newHeight;
//rc.Right = rc.Left + Mathf.RoundToInt(newHeight * aspect);
//break;
case WMSZ_BOTTOM:
newWidth = Mathf.RoundToInt(newHeight * aspect);
//rc.Bottom = rc.Top + newHeight;
//rc.Right = rc.Left + Mathf.RoundToInt(newHeight * aspect);
break;
case WMSZ_RIGHT + WMSZ_BOTTOM:
//rc.Right = rc.Left + newWidth;
//rc.Bottom = rc.Top + Mathf.RoundToInt(newWidth / aspect);
//break;
case WMSZ_RIGHT + WMSZ_TOP:
//rc.Right = rc.Left + newWidth;
//rc.Top = rc.Bottom - Mathf.RoundToInt(newWidth / aspect);
//break;
case WMSZ_LEFT + WMSZ_BOTTOM:
//rc.Left = rc.Right - newWidth;
//rc.Bottom = rc.Top + Mathf.RoundToInt(newWidth / aspect);
//break;
case WMSZ_LEFT + WMSZ_TOP:
newHeight = Mathf.RoundToInt(newWidth / aspect);
//rc.Left = rc.Right - newWidth;
//rc.Top = rc.Bottom - Mathf.RoundToInt(newWidth / aspect);
break;
}
// Save actual Unity game area resolution.
// This does not include borders.
//setWidth = rc.Right - rc.Left;
//setHeight = rc.Bottom - rc.Top;
rc.Right = rc.Left + newWidth + borderWidth;
rc.Bottom = rc.Top + newHeight + borderHeight;
// Add back borders.
//rc.Right += borderWidth;
//rc.Bottom += borderHeight;
// Trigger resolution change event.
resolutionChangedEvent.Invoke(newWidth, newHeight, Screen.fullScreen);
// Write back changed window parameters.
Marshal.StructureToPtr(rc, lParam, true);
}
// Call original WindowProc function.
return CallWindowProc(oldWndProcPtr, hWnd, msg, wParam, lParam);
}
실행결과
일단 원하는 대로 떨리지 않고 적절하게 크기가 바뀌는 것을 확인했다.
그런데 최소, 최대 크기 설정에서 가로, 세로가 적절하지 않은 것 같으니 기존 동작을 확인해서 그대로 동작할 수 있도록 수정해 봐야겠다.