728x90
안녕하세요. 인텔리원스튜디오(IntelliOneStudio)입니다.
오늘은 GPT-4, GPT-4o 활용해서 Unity UI Toolkit을 사용하여 자동으로 레벨 선택 항목 추가해볼께요.
[오늘의 목표] GPT-4, GPT-4o 활용해서 Unity UI Toolkit을 사용하여 자동으로 레벨 선택 항목 추가(1)
※ 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