-
유니티 화면 비율 고정 처리...19일지 2021. 11. 17. 23:48
화면 조정 시 위치 바뀌는 버그 수정 시도
이전에 발생한 버그를 수정하기 위해 코드를 이것저것 수정해보고 있었는데, 일단 의심되는 건 WinProc을 교체하려고 했으나 교체되지 않고 기존 것에 추가로 적용이 되는 게 아닐까 하는 생각이 든다.
그래서 변경 전 크기, 위치와 변경 후 크기, 위치가 각각 전달되면서 문제가 되는 게 아닐까 싶다.
관련해서 서브 클래싱에 대한 정보를 찾게 되었는데 내용은 다음과 같다.
창 프로시저 사용 - Win32 apps | Microsoft Docs
이것들을 확인해본 결과 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); }
실행결과
일단 원하는 대로 떨리지 않고 적절하게 크기가 바뀌는 것을 확인했다.
그런데 최소, 최대 크기 설정에서 가로, 세로가 적절하지 않은 것 같으니 기존 동작을 확인해서 그대로 동작할 수 있도록 수정해 봐야겠다.