일지

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

niamdank 2021. 11. 17. 23:48

화면 조정 시 위치 바뀌는 버그 수정 시도

이전에 발생한 버그를 수정하기 위해 코드를 이것저것 수정해보고 있었는데, 일단 의심되는 건 WinProc을 교체하려고 했으나 교체되지 않고 기존 것에 추가로 적용이 되는 게 아닐까 하는 생각이 든다.

 

그래서 변경 전 크기, 위치와 변경 후 크기, 위치가 각각 전달되면서 문제가 되는 게 아닐까 싶다.

 

관련해서 서브 클래싱에 대한 정보를 찾게 되었는데 내용은 다음과 같다.

 

창 프로시저 사용 - Win32 apps | Microsoft Docs

 

창 프로시저 사용 - Win32 apps

이 섹션에서는 창 프로시저와 관련된 다음 작업을 수행하는 방법을 설명합니다.

docs.microsoft.com

 

베이비들의 블로그 (zum.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);
    }

 

실행결과

 

일단 원하는 대로 떨리지 않고 적절하게 크기가 바뀌는 것을 확인했다.

 

그런데 최소, 최대 크기 설정에서 가로, 세로가 적절하지 않은 것 같으니 기존 동작을 확인해서 그대로 동작할 수 있도록 수정해 봐야겠다.