본문 바로가기
GPT 게임만들기/ChueokUI_Project

[ChatGPT][ChueokUI] 04_MainScene_Title 구성

by OhEasy 2025. 3. 4.
728x90

https://525easy.tistory.com/81

 

[ChatGPT] 03_Scene 제작 및 MainScene_Title 오브젝트 구성

https://525easy.tistory.com/80이전 글에서 이어서 시작.0. 금일 목표GPT가 만들어준 폴더 구조에 따라 필요한 Scene의 제작을 진행어디까지 되나 확인하기 위해 일부 UI도 요청.1. Scene 제작Assets폴더 내 Scene

525easy.tistory.com

 

  • 이전 글에서 이어서 시작
  • 오브젝트들을 제작했기 때문에 UI의 배치가 필요하다.
  • 이전 글의 경우 사진을 많이 넣어서 기본 모드로 작성하였으나 이번 글은 마크다운으로 작성한다.
    • 마크다운으로 하는 이유는 이전 글처럼 계층 구조를 출력하거나 수치값이 주를 이루기 때문이다.

0. 금일 목표

  • GPT는 Unity와 연동 되어있지 않다. 그럼에도 불구하고 UI를 구성할 수 있는가를 확인한다.
  • 모바일의 경우에는 펀치홀이나 노치, 기종마다 다른 해상도 비율로 인해 대응이 필요하다.
    • 우선은 PC 기반으로 작업한 뒤 Android 기기에 대한 대응도 가능한지 추 후에 확인하도록 한다.

1. UI 배치

  • 질문은 다음과 같이 진행했다.
UI를 배치하고 싶은데 각 컴포넌트들의 속성값들을 알려줘. 예를 들면 Background Image의 Rect Transform 정보들 같은 거 말이야
  • 어느정도 유니티 에디터를 써봤기 때문에 저렇게 질문했다. 완전 아무것도 모르는 사람이라면 다르게 질문할 것 같긴하다.
  • 완전 모르는 사람이라고 가정하면 아래와 같지 않을까?
1. UI가 이상해 어떻게 바꿔?
2. 모든 것들이 가운데에 몰려있어
  • 생각보다 답변은 그럴싸하게 나왔다.
  • UI 배치의 경우 아직은 사람이 UGUI라던가 UI Toolkit을 사용하는 것이 좋을 것 같다.
  • 답변은 아래와 같이 전달 되었다.

1.  Canvas  
    저장 위치: Assets/Scripts/UI/ (Canvas는 씬에 기본적으로 생성되는 UI 루트 오브젝트)  
    Render Mode: Screen Space - Overlay  
    Canvas Scaler:
     UI Scale Mode: Scale With Screen Size
     Reference Resolution: 1920 x 1080
     Screen Match Mode: Match Width or Height (Match: 0.5)
    Graphic Raycaster: 기본 설정 사용
  • 생각보다 많이 그럴싸했다. 하지만 Canvas 외에는 좀 부족한 부분들이 있었다.
3.  TitleText  
    컴포넌트: TextMeshProUGUI (Canvas 하위, 제목 텍스트)  
    Rect Transform:

    ```
     Anchor Min: (0.5, 1)
     Anchor Max: (0.5, 1)
     Pivot: (0.5, 1)
     Position: (0, -100, 0)
     Width: 1200
     Height: 200
     폰트 설정: 큰 사이즈, Bold, 색상은 타이틀 분위기에 맞게 (예: 흰색 또는 금색) 
  • 코드블럭으로 작성하다보니 탭으로 구분했으나 순서 목록으로 작성해준다.
  • 위와 같이 답변해 주었는데 사실 폰트 설정의 경우 TextMeshProUGUI에서 하는 것이다.
  • 또한 유니티 에디터만 켰다면 컴포넌트에 보이는 글씨는 TextMeshPro - Text (UI)로 되어있다.
  • 어찌 되었던 최초 계층 구조로 작성해준 오브젝트 중 모든 UI 관련 오브젝트들의 속성값들을 답변해 주었다.
  • Canvas의 설정을 보면 1920 x 1080 기준으로 제작 되고 있다. 하지만 막상 배치하니 맞지 않았다.
UI를 확인하니 해상도인 1920 x 1080에 적합하지 않아보이는데 수정해줘
  • 위와 같은 질문을 하였다. 질문한 첫번째 이유는 특정 버튼이 화면 밖을 벗어나서 질문한 것이었다.
  • 이를 파악하지 못한 것인지 전체 UI들의 새로운 값들을 답변 받았다.
  • 해당 버튼들은 사실 사람이 하면 손으로 딸깍 하면 끝나는 부분이다. 하지만 GPT가 해결을 하는지 보기 위해 계속 질문을 했다.
  • 4번정도 추가 질문을 하였고 질문은 다음과 같다.
1.  ExitButton 얘는 바닥에 너무 딱 붙는 것 아닌가?
2.  (0, -400, 0)으로 조정하였을 때 StartButton과 OptionButton의 위치도 다시 설정해줘
3.  높이가 100이라 너무 딱 붙어있는데? 몇으로 수정하는게 좋을까
4.  exit Button은 -400으로 유지해야 해  
  • 사람이 했으면 금방 끝날 일이긴 하다.
  • 지금은 PC로 제작하고 있어서 큰 문제는 없어보이긴 하다. 모바일도 가능하게 할 때 어떻게 변할지는 아직 알 수 없다.
  • 두번째 적합하지 않다고 느낀 UI의 수정을 지시했다.
OptionsPanel의 경우 지금 800x600사이즈로 설정 되어 있어 외부의 다른 ㅡUI를 선택할 수 있는데 방지할 수 있는 방법을 알려줘
  • OptionsPanel은 옵션을 Scene가 아닌 UI로 처리하는 과정(이전 글)에서 생성 된 오브젝트이다.
  • 위 과정까지의 경우 ExitButton이 클릭이 가능한 상태였기 때문에 위와 같은 질문을 하였고 답변은 다음과 같다.
외부 UI 요소가 선택되지 않도록 하기 위해 OptionsPanel을 모달 창처럼 처리하는 방법이 있습니다. 아래 방법들을 고려해보세요:
1.  전체 화면 블로커(Overlay) 추가:  
    OptionsPanel의 배경에 전체 화면을 덮는 반투명 또는 투명한 Image 또는 Panel을 추가하여, 이 오브젝트가 Raycast를 차단하도록 설정합니다. 이 블로커는 사용자가 OptionsPanel 외부를 클릭할 경우에도 이벤트를 가로채어 하위 UI에 도달하지 않도록 합니다.
2.  Canvas Group 사용:  
    OptionsPanel에 Canvas Group 컴포넌트를 추가하고, "Blocks Raycasts" 옵션을 활성화하면 해당 패널 및 그 자식들이 모두 클릭 이벤트를 차단하게 할 수 있습니다. 만약 OptionsPanel 외부의 UI와 겹치는 경우, OptionsPanel을 부모로 하는 모달 창 형태로 구성하고, 그 부모 오브젝트에 전체 화면 블로커를 포함시키는 방식이 좋습니다.
3.  Modal 창 구조:  
    OptionsPanel을 모달 창으로 만들 때, 일반적으로 아래와 같은 계층 구조로 구성합니다.
4.  OptionsModal (전체 화면 블로커 포함, 활성화 시 전체 화면을 덮음)  
    ├── BlockerPanel (Image 컴포넌트, 전체 화면, 반투명, Raycast Block 활성화)  
    └── OptionsPanel (실제 옵션 UI, BlockerPanel 위에 배치)  
    이렇게 하면 OptionsModal이 활성화된 동안 다른 UI 요소에 대한 클릭이 전혀 전달되지 않습니다.
이 방법들을 적용하면 OptionsPanel 외부의 UI 선택을 방지할 수 있습니다.
  • Modal이 적합하여 3번을 선택했다.
    • 1번과 2번의 경우 자식 오브젝트가 전체 화면을 덮어야 하는 상황이다.
    • 하지만 OptionPanel 자체의 사이즈를 작게 제시하였기 때문에 화면을 덮는 자식 오브젝트의 수치는 추가 질문이 발생한다.
    • 어찌저찌 수치를 얻더라도 그게 진짜 덮는지는 모호한 상황으로 몇번의 추가 질문이 더 발생할 수 있다 생각했다.
    • 또한 모바일 대응 시 펀치홀 대응을 위해 SafeArea라는 것들을 사용한 적이 있는데 그 구조상 라운드 처리 된 부분이 이상하게 보일 수 있을 것 같다 판단 되었다.
OptionsModal (GameObject, 활성화 시 전체 화면 모달)  
│  
├── BlockerPanel (Image, 전체 화면, 반투명, Raycast Target 활성)  
│  
└── OptionsPanel (Panel, 중앙 위치, 옵션 UI 포함)  
├── LanguageDropdown (TMP\_Dropdown)  
├── VolumeSlider (Slider)  
└── CloseButton (Button)  
└── TMP\_Text ("Close")
  • 위와 같은 계층구조를 전달 받았다. 어찌 되었던 OptionPanel 자체의 위치가 변동되었다.
  • OptionButton자체가 MainMenuController라는 클래스의 OnOptionButton이라는 함수를 사용하고 있었기에 다음과 같은 질문을 진행하였다.
MainMenuController class는 수정할 필요가 없나? 없다면 GameObject optionsPanel에 어떤 오브젝트를 넣어야 하는지 알려줘
  • MainMenuController의 GameObject optionPanel에는 OptionPanel이 할당 되어 있는데 해당 오브젝트를 비활성화 시키면 BlockerPanel이 활성화 되어있기 때문에 이후 진행이 불가능하기 때문이다.
  • 나름 잘 답변을 해주었고 오브젝트들을 둘러보다 사운드에 관련 된 오브젝트가 이상한 것을 발견하여 다음과 같은 질문을 했다.
AudioManager 이 class는 어떤 역할을 하지? 현재는 Audio Source 컴포넌트만 추가 되어 있어. Scene이 변경되거나 할 때도 BGM이 재생되고 있어야 할 것 같은데? 그리고 지금은 AudioSource가 1개만 있기 때문에 BGM이 나오고 있을 때 SFX을 재생 시키고자 하면 BGM이 끊기는 현상이 발생할 것 같은데? 수정 된 구조를 보내줘
  • 이 때 채팅방의 GPT 답변이 오지 않았다. 3번 같은 질문을 했는데 답변이 안오고 로딩만 계속 되고 있었다.
답이 왜 안오나
  • 라는 질문을 마지막으로 답변이 도착했다.
다음은 AudioManager 클래스를 수정한 예시입니다. 이 클래스는 씬 전환 시에도 BGM이 유지되고, 동시에 SFX를 재생할 때 BGM이 끊기지 않도록 두 개의 AudioSource를 관리합니다.

저장 경로: Assets/Scripts/Managers/AudioManager.cs
  • 이전에 스크립트 관련 내용은 저장 경로까지 출력시켜달라는 것을 기억하고 있었다.
  • 답변과 스크립트를 받았으나 AudioManager의 경우 Awake 이벤트 함수가 실행되고있었다.
  • 당연히 문제는 아닐 것 같으나 AudioManager는 Singleton을 상속받고 Singleton의 경우 GPT가 수정하며 Awake 함수가 정의되지 않은 상태였다.
Singleton에는 Awake가 정의 되어 있지 않다.  
using UnityEngine;

public class Singleton : MonoBehaviour where T : MonoBehaviour  
{  
private static T instance;  
private static readonly object lockObj = new object();  
private static bool applicationIsQuitting = false;

public static T Instance
{
    get
    {
        if (applicationIsQuitting)
        {
            Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
                "' already destroyed on application quit. Won't create again - returning null.");
            return null;
        }

        lock (lockObj)
        {
            if (instance == null)
            {
                instance = (T)FindObjectOfType(typeof(T));

                if (FindObjectsOfType(typeof(T)).Length > 1)
                {
                    Debug.LogError("[Singleton] More than one instance of " + typeof(T) + " found. Please ensure only one exists.");
                    return instance;
                }

                if (instance == null)
                {
                    GameObject singletonObject = new GameObject();
                    instance = singletonObject.AddComponent<T>();
                    singletonObject.name = "(Singleton) " + typeof(T).ToString();
                    DontDestroyOnLoad(singletonObject);
                }
            }
            return instance;
        }
    }
}

protected virtual void OnDestroy()
{
    applicationIsQuitting = true;
}
}
  • 위는 GPT가 제시한 싱글톤이다. Cursor Ai는 스크립트 파일을 첨부하는 것이 가능하다. 하지만 GPT는 진행되고 있는 모습을 알 수 없기 때문에 코드를 직접적으로 전달해주었다.
  • 이후 스크립트의 충돌 없이 정상 작동하는지 확인을 해봐야 했다.
  • 최초 실행되는 곳이고 해당 Scene에 존재하는 Class 중 CSVReader를 통해 CSV 데이터를 로드하는 부분이 존재했다.
  • CSV 데이터를 로드를 해야하는데 파일이 없으니 당연히 작동하지 않을 것이다.
이제 정상적인 작동을 하는지 테스트를 해보려 하는데 CSV 데이터가 없다. 지금 필요한 데이터들이 무엇이 있나
  • 답변을 통해 테스트용 CSV 데이터를 전달 받을 수 있었다.
  • 플레이를 해보니 에러가 발생하지 않는 것을 확인했다.
  • 하지만 ExitButton을 눌렀을 때 게임이 종료되지 않고 있었다.
  • MainMenuController에는 게임을 종료하는 OnExitButtonClicked()가 있었고 Application.Quit();을 통해 종료를 시도하고 있었다.
  • 하지만 해당 함수는 에디터 환경에서는 동작하지 않고 빌드된 환경에서만 동작한다.
유니티 에디터 환경에서는 Appication.Quit()이 동작하지 않는 것 같는데 맞나?
  • 위 답변을 통해 아래와 같은 스크립트를 얻을 수 있었다.
public void OnExitButtonClicked()  
{  
#if UNITY\_EDITOR  
EditorApplication.isPlaying = false;  
#else  
Application.Quit();  
#endif  
}
  • 에러가 없는 것은 확인이 되었다. 이제 실질적인 게임 진행 부분을 만들어야 한다.
728x90

댓글