[👾Project: PokeIdle] #1 투명 창 만들기

2025. 8. 19. 00:24·도토리도굴단/Project: HoP 개발일지

포켓몬을 좋아하는 남자친구와 함께 기획한 개인 소장용 포켓몬 방치형 수집게임 개발일지!


📖 오늘의 학습 정리  📖

  • 투명창 만들기 
    1. 투명화 세팅
    2. 클릭 가능하도록

 투명창 만들기 

1. 투명화 세팅

1단계: 투명하게 그리기

Unity의 Main Camera 설정에서 Background의 Alpha(투명도)를 0으로 세팅하기

 

2단계: 투명한 캔버스 달라고 요청하기

▼ 전체 코드 (OverlayController.cs)

더보기
using UnityEngine;
using System;
using System.Runtime.InteropServices;

public class OverlayController : MonoBehaviour
{
    [Header("창 설정")]
    [SerializeField] private bool isAlwaysOnTop = true;
    
    // 윈도우 설정
    [DllImport("user32.dll")]
    private static extern IntPtr GetActiveWindow();

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    
    [DllImport("user32.dll")]
    static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

    [DllImport("dwmapi.dll")]
    private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
    
    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
    private const int SW_MINIMIZE = 6;

    // 창의 확장 스타일 제어
    const int GWL_EXSTYLE = -20;
    const int WS_EX_LAYERED = 0x80000;
    const int WS_EX_TRANSPARENT = 0x20;
    
    // 창 스타일 제어
    const int GWL_STYLE = -16;
    const int WS_POPUP = unchecked((int)0x80000000);
    const int WS_VISIBLE = 0x10000000;
    
    static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
    static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
    const uint SWP_NOSIZE = 0x0001;
    const uint SWP_NOMOVE = 0x0002;
    
    private IntPtr hWnd;
    private bool isClickThrough = false;

    struct MARGINS
    {
        public int cxLeftWidth;
        public int cxRightWidth;
        public int cyTopHeight;
        public int cyBottomHeight;
    }

    private void Start()
    {
        #if !UNITY_EDITOR && UNITY_STANDALONE_WIN
        hWnd = GetActiveWindow();
        SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED);

        SetWindowLong(hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
        MARGINS margins = new MARGINS { cxLeftWidth = -1 };
        DwmExtendFrameIntoClientArea(hWnd, ref margins);
        
        SetAlwaysOnTop(isAlwaysOnTop);
        #endif
    }
    
    private void Update()
    {
        // 왼쪽 Ctrl 키를 누르면 클릭 통과 모드 On/Off 토글
        if (Input.GetKeyDown(KeyCode.LeftControl))
        {
            ToggleClickThrough();
        }
    }
    
    /// <summary>
    /// 클릭 통과 상태 설정/해제
    /// </summary>
    public void SetClickThrough(bool isTransparent)
    {
        isClickThrough = isTransparent;
        #if !UNITY_EDITOR && UNITY_STANDALONE_WIN
        int extendedStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
        if (isTransparent)
        {
            SetWindowLong(hWnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
        }
        else
        {
            SetWindowLong(hWnd, GWL_EXSTYLE, extendedStyle & ~WS_EX_TRANSPARENT);
        }
        #endif
    }
    
    public void ToggleClickThrough()
    {
        SetClickThrough(!isClickThrough);
    }
    
    /// <summary>
    /// '항상 위' 상태를 설정하거나 해제
    /// </summary>
    /// <param name="isTopmost">true이면 항상 위, false이면 해제</param>
    public void SetAlwaysOnTop(bool isTopmost)
    {
        isAlwaysOnTop = isTopmost;
        #if !UNITY_EDITOR && UNITY_STANDALONE_WIN
        IntPtr flag = isTopmost ? HWND_TOPMOST : HWND_NOTOPMOST;
        SetWindowPos(hWnd, flag, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
        #endif
    }

    /// <summary>
    /// 창 최소화
    /// </summary>
    public void MinimizeWindow()
    {
        #if !UNITY_EDITOR && UNITY_STANDALONE_WIN
        ShowWindow(hWnd, SW_MINIMIZE);
        #endif
    }
}

 

  • GetActiveWindow(): 먼저 Windows에게 우리가 제어하고 싶은 창이 무엇인지 알려줘야 한다. 이 함수로 우리 게임 창의 고유 ID(hWnd)를 얻어온다.
  • SetWindowLong(..., WS_POPUP): 그 다음, "이 창의 기본 스타일을 바꿔줘" 라고 요청한다. WS_POPUP 스타일을 적용해서 제목 표시줄, 테두리 등 창의 기본 장식을 모두 제거한다.
  • DwmExtendFrameIntoClientArea(...): 이 함수는 Windows의 '바탕 화면 창 관리자(DWM)'에게 명령을 내린다.
    • 명령 내용: "이 창의 프레임(테두리) 부분을 창 내부 영역까지 전부 확장해줘!"
    • MARGINS { cxLeftWidth = -1 }: 이 값은 "모든 방향으로 무한히 확장해줘" 라는 의미의 특별한 신호

 

계속 Build and Run을 통해서 확인해봤는데, Edit > Project Setting > Player에서 꼭 Use DXGI flip model swapchain for D3D11 체크박스를 꺼주어야 한다.

DXGI Flip Model 스왑체인(“Use DXGI flip model swapchain for D3D11”)을 켜면, Unity가 만드는 윈도우가 ‘레이어드(투명창) 방식’과 충돌해서 알파가 합성에 쓰이지 못하고 검정으로 떨어진다고 한다. Flip Model 방식은 DXGI가 버퍼를 뒤집어(DWM에 직접 넘겨) 합성하기 때문에 지연/전력/성능에 유리하고, 이 방식을 끄면 Blt Model 방식으로 간다는데.. 뭐라는지 모르겠고 아무튼 꺼야지 투명창이 된다. 


2. 클릭 통과 구현

 

  • GetWindowLong(..., GWL_EXSTYLE): Windows 창에는 기본 스타일 외에 '확장 스타일'이라는 추가 속성들이 있음. 먼저 이 함수로 "현재 이 창의 확장 스타일 목록을 전부 알려줘" 라고 요청함.
  • WS_EX_TRANSPARENT: 이 스타일이 적용된 창은 모든 마우스 이벤트를 무시하고, 자기 바로 아래에 있는 창이나 바탕화면으로 그대로 전달함.
  • SetWindowLong(...)으로 스타일 토글하기: Update() 함수에서 Ctrl 키를 감지하여, 이 WS_EX_TRANSPARENT flag를 제어하도록 설정함.
    • 클릭 통과 켜기: 기존스타일 | WS_EX_TRANSPARENT
      • | (OR) 연산은 기존 스타일 목록에 새로운 스타일을 추가하는 역할을 합니다.
    • 클릭 통과 끄기: 기존스타일 & ~WS_EX_TRANSPARENT
      • ~는 비트를 반전시키고 & (AND) 연산은 특정 스타일만 정확하게 제거하는 역할을 합니다.

 

 


🌱 내일 할 일 🌱

  • 기본 AI 움직임 구현

 

 

'도토리도굴단 > Project: HoP 개발일지' 카테고리의 다른 글

[🖥️Project: HoP] #5 무한 점프 시스템  (0) 2025.12.13
[🖥️Project: HoP] #4 Windows Low-Level Hook과 전역 입력 감지  (0) 2025.12.11
[🖥️Project: HoP] #3 애니메이션 시스템과 O(1) 최적화  (0) 2025.12.08
[🖥️Project: HoP] #2 위치 저장과 멀티 모니터  (0) 2025.12.08
[🖥️Project: HoP] #1 투명 윈도우와 위젯 시스템 구축  (0) 2025.12.04
'도토리도굴단/Project: HoP 개발일지' 카테고리의 다른 글
  • [🖥️Project: HoP] #4 Windows Low-Level Hook과 전역 입력 감지
  • [🖥️Project: HoP] #3 애니메이션 시스템과 O(1) 최적화
  • [🖥️Project: HoP] #2 위치 저장과 멀티 모니터
  • [🖥️Project: HoP] #1 투명 윈도우와 위젯 시스템 구축
happy124219
happy124219
happylaboratory 님의 블로그 입니다.
  • happy124219
    윤아 실험실
    happy124219
  • 전체
    오늘
    어제
    • 분류 전체보기 (116)
      • 공부방 (103)
        • Unity UI (2)
        • C# 알고리즘 (3)
        • C# 에러발생 로그 (7)
        • 내일배움캠프 Unity 9기 TIL (91)
      • 도토리도굴단 (9)
        • Project: HSR 개발일지 (3)
        • Project: HoP 개발일지 (6)
      • 개인 프로젝트 (1)
        • Project: BloomFolk (1)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    게임개발
    도망공부일지
    Unity게임개발
    스파르타내일배움캠프
    유니티트랙후기
    유니티
    c#문법
    스파르타내일배움캠프TIL
    도망개발일지
    내일배움캠프후기
    내일배움캠프
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
happy124219
[👾Project: PokeIdle] #1 투명 창 만들기
상단으로

티스토리툴바