본문 바로가기
디지털노마드

[챗GPT게임개발47] GPT-4, GPT-4o 활용해서 Unity UI Toolkit을 사용하여 자동으로 레벨 선택 항목 추가하기(1)

by 인텔리노마드라이프 2024. 6. 7.
728x90

안녕하세요. 인텔리원스튜디오(IntelliOneStudio)입니다.

오늘은 GPT-4, GPT-4o 활용해서 Unity UI Toolkit을 사용하여 자동으로 레벨 선택 항목 추가해볼께요.

[오늘의 목표] GPT-4, GPT-4o 활용해서 Unity UI Toolkit을 사용하여 자동으로 레벨 선택 항목 추가(1)
[오늘 살펴볼 UI]

 

 ChatGPT 답변 내용 중 제가 별도로 표시한 파란색 내용을 기준으로 읽으시면 좀 더 이해가 쉽게 될거예요.

 이 글은 Unity 에서 제공한 Gem Hunter Project를 활용했어요.

자동으로 메뉴 생성을 위한 스크립트 

먼저 동적으로 메뉴 생성하는 스크립트가 필요해요. 

[쉽게 설명하기 : GPT-4, GPT-4o]

코드 목적 요약

이 스크립트는 Unity에서 게임의 메인 메뉴 UI를 동적으로 구성하고, 레벨 선택 기능을 구현합니다. UXML 템플릿을 사용하여 레벨 항목을 자동으로 생성하고, 클릭 이벤트를 추가하여 사용자가 레벨을 선택하면 해당 레벨로 이동할 수 있게 합니다. 또한, 화면 전환을 위한 페이드 인/아웃 효과를 구현하여 부드러운 사용자 경험을 제공합니다.

 

using System.Collections;
using UnityEngine;
using UnityEngine.UIElements;

namespace Match3
{
    public class MainMenu : MonoBehaviour
    {
        public LevelList LevelList;
        public VisualTreeAsset LevelEntry;

        private UIDocument m_Document;
        private VisualElement m_Cover;

        private int m_TargetLevel = -1;
    
        void Start()
        {
            GameManager.Instance.MainMenuOpened();
        
            m_Document = GetComponent<UIDocument>();
            UIHandler.ApplySafeArea(m_Document.rootVisualElement);

            var container = m_Document.rootVisualElement.Q<VisualElement>("LevelSelectionContainer");
        
            for(var i = 0; i < LevelList.SceneCount; ++i)
            {
#if UNITY_EDITOR
                //in editor we check if the level is not null. This shouldn't happen in a build as the build script will
                //check
                if (LevelList.Scenes[i] == null)
                {
                    Debug.LogWarning("LevelList contains a null scene! Fix or remove the scene from the LevelList");
                    continue;
                }
#endif
            
                var newEntry = LevelEntry.Instantiate();
                var label = newEntry.Q<Label>("LevelNumber");
                label.text = (i+1).ToString();
            
                container.Add(newEntry);

                //the container is stretched, which would lead to be able to click UNDER the entry, so we grab the actual
                //level entry inside the container 
                var subEntry = newEntry.Q<VisualElement>("LevelEntry");
                var i1 = i;
                subEntry.AddManipulator(new Clickable(() =>
                {
                    m_TargetLevel = i1;
                    FadeOut();
                }));
            }

                        
            m_Cover = m_Document.rootVisualElement.Q<VisualElement>("Cover");
            m_Cover.style.opacity = 1.0f;
            m_Cover.RegisterCallback<TransitionEndEvent>(evt =>
            {
                //we're fading out
                if (m_Cover.style.opacity.value > 0.9f)
                {
                    LevelList.LoadLevel(m_TargetLevel);
                }
            });
            
            StartCoroutine(FadeIn());
        }

        IEnumerator FadeIn()
        {
            yield return null;
            yield return null;

            m_Cover.style.opacity = 0.0f;
        }

        void FadeOut()
        {
            m_Cover.style.opacity = 1.0f;
        }
    }
}

 

그리고 스크립트는 다음과 같이 설정해요.

 

LevelList : 게임 레벨 관리 및 로드 

이제 스크립트에 LevelList 를 설정해요. LevelList는 아래와 같아요.

 

아래 스크립트를 통해 Unity 프로젝트에서 레벨을 효과적으로 관리해요. 

자세한 내용은 다음 시간에 살펴볼께요.

using UnityEngine;
using UnityEngine.SceneManagement;

#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.SceneManagement;
#endif

namespace Match3
{
    [CreateAssetMenu]
    public class LevelList : ScriptableObject
    {
#if UNITY_EDITOR
        public SceneAsset[] Scenes;
#endif

        [HideInInspector] public int[] SceneList;

        public int SceneCount
        {
            get
            {
#if UNITY_EDITOR
                return Scenes.Length;
#else
            return SceneList.Length;
#endif
            }
        }

        public void LoadLevel(int levelNumber)
        {
#if UNITY_EDITOR
            //in editor we directly load the scene
            EditorSceneManager.LoadSceneInPlayMode(AssetDatabase.GetAssetPath(Scenes[levelNumber]),
                new LoadSceneParameters(LoadSceneMode.Single));
#else
    //in build we load through the normal scene manager as the pre build script will have filled the build setting properly
            SceneManager.LoadScene(SceneList[levelNumber], LoadSceneMode.Single);
#endif
        }
    }

#if UNITY_EDITOR
    class BuildLevelList : IPreprocessBuildWithReport
    {
        public int callbackOrder => 0;

        public void OnPreprocessBuild(BuildReport report)
        {
            try
            {
                var levelListAssets = AssetDatabase.FindAssets("t:LevelList");

                if (levelListAssets.Length == 0)
                {
                    throw new BuildFailedException("Couldn't find a level list, aborting the build");
                }

                var levelList =
                    AssetDatabase.LoadAssetAtPath<LevelList>(AssetDatabase.GUIDToAssetPath(levelListAssets[0]));

                if (levelList.Scenes.Length == 0)
                {
                    throw new BuildFailedException("Level list scenes array is empty, aborting the build");
                }

                var buildLevels = EditorBuildSettings.scenes;
                var levels = new int[levelList.Scenes.Length];

                bool buildListChange = false;

                for (int i = 0; i < levelList.Scenes.Length; ++i)
                {
                    var sceneAsset = levelList.Scenes[i];
                    var scenePath = AssetDatabase.GetAssetPath(sceneAsset);

                    if (sceneAsset == null)
                    {
                        throw new BuildFailedException("The level list contains a null scene, fix before rebuilding");
                    }

                    var idx = Array.FindIndex(buildLevels, scene => scene.path == scenePath);

                    if (idx == -1)
                    {
                        idx = buildLevels.Length - 1;
                        ArrayUtility.Add(ref buildLevels, new EditorBuildSettingsScene(scenePath, true));
                        buildListChange = true;
                    }
                    else if (!buildLevels[idx].enabled)
                    {
                        buildLevels[idx].enabled = true;
                        buildListChange = true;
                    }

                    levels[i] = idx;
                }

                bool levelListChanged = false;
                for (int i = 0; i < levels.Length; ++i)
                {
                    if (i >= levelList.SceneList.Length || levels[i] != levelList.SceneList[i])
                    {
                        levelListChanged = true;
                        break;
                    }
                }

                if (levelListChanged)
                {
                    levelList.SceneList = levels;
                    EditorUtility.SetDirty(levelList);
                    AssetDatabase.SaveAssetIfDirty(levelList);
                }

                if (levelListChanged || buildListChange)
                {
                    EditorBuildSettings.scenes = buildLevels;
                    EditorUtility.DisplayDialog("Build Stopped",
                        "The scene list from the build had to be changed to match the list in the LevelList assets.\n" +
                        "the scene list have now been fixed, Please restart the build.", "OK");

                    throw new BuildFailedException("Level List had to be rebuilt, restart the build");
                }
            }
            catch (Exception e)
            {
                throw new BuildFailedException($"Exception during prebuild {e.Message}");
            }
        }
    }
#endif
}

 

지금까지,

언제나 성장하는 인텔리원스튜디오(IntelliOneStudio)입니다.

감사합니다.

 

 

728x90