[2025/06/04]TIL

오수호·2025년 6월 4일

TIL

목록 보기
25/60

오늘 배운 내용

  1. 유니티 커스텀 에디터

커스텀 에디터 사용방법

전제 ) Editor폴더안에 스크립트가 존재해야한다.
이는 유니티의 예약폴더시스템인데, Resouces폴더와 같은 느낌이다.

  1. MonoBehaviour를 Editor로 수정

2.클래스의 위에 [CustomEditor(typeof('Class이름'))] 즉, 커스텀 에디터를 적용할 클래스

  1. var 식별자 = target as '클래스이름'

위 단계가 모두 기본 전제에 가깝다고 볼 수 있다.

예시 1)

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(GameManager))]
public class GameManagerEditor : Editor
{
    public override void OnInspectorGUI()
    {
        var manager = target as GameManager;

        EditorGUILayout.ObjectField("스크립트", MonoScript.FromMonoBehaviour((MonoBehaviour)manager), typeof(GameManager),
            false);
        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("적 생성"))
        {
            manager.SpawnEnemy();
        }

        if (GUILayout.Button("적 제거"))
        {
            var enemies = GameObject.FindGameObjectsWithTag("Enemy");
            foreach (var enemy in enemies)
            {
                DestroyImmediate(enemy);
            }
        }
        EditorGUILayout.EndHorizontal();
        
        
        
        
    }
    
    
    
}

예시 2)

using UnityEditor;
using UnityEngine;

public class ItemCreator : EditorWindow
{
    private string itemName = "New Item";
    private ItemType itemType = ItemType.Weapon;
    private int quantity = 1;
    private bool isMultiple = false;
    
    [MenuItem("Window/Item Creator")]
    private static void ShowWindow()
    {
        GetWindow<ItemCreator>("아이템 생성");
    }

    private void OnGUI()
    {
        itemName = EditorGUILayout.TextField("아이템 명",itemName);
        itemType = (ItemType)EditorGUILayout.EnumPopup("아이템 종류", itemType);
        quantity = EditorGUILayout.IntField("수량", quantity);
        isMultiple = EditorGUILayout.Toggle("복수 여부", isMultiple);

        if (GUILayout.Button("아이템 생성"))
        {
            ItemData data = ScriptableObject.CreateInstance<ItemData>();
            data.itemName = itemName;
            data.itemType = itemType;
            data.quantity = quantity;
            data.isMultiple = isMultiple;
            AssetDatabase.CreateAsset(data, $"Assets/02_Scripts/Items/{itemName}.asset");
            AssetDatabase.SaveAssets();
        }


    }
    
    
}

예시 3)

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(PlayerStats))]
public class PlayerStatsEditor : Editor
{
    public override void OnInspectorGUI()
    {
        var playerStats = (PlayerStats)target;
        EditorGUILayout.Space();
        EditorGUILayout.HelpBox("주인공 캐릭터 스텟", MessageType.Info);
        EditorGUILayout.Space();
        playerStats.hp = EditorGUILayout.IntField("생명", playerStats.hp);
        playerStats.mp = EditorGUILayout.IntSlider("Mp", playerStats.mp,0,100);
        
        EditorGUILayout.BeginHorizontal();

        if (GUILayout.Button(playerStats.isGodMode? "일반모드로 전환" : "무적모드로 전환"))
        {
            playerStats.isGodMode = !playerStats.isGodMode;
        }

        if (GUILayout.Button("데이터 초기화"))
        {
            playerStats.InitPlayerData();
        }
        
        EditorGUILayout.EndHorizontal();
    }
    
    
}

예시 2번의 경우 스크립터블 오브젝트를 쉽게 만들 수 있는 커스텀 에디터이기 때문에 잘 기억해놓자.

  1. https://school.programmers.co.kr/learn/courses/30/lessons/172928?language=csharp 코딩 테스트 문제. 공원산책

공원 산책 문제 풀이


using System.Collections.Generic;
using System;

public class Solution {
    public int[] solution(string[] park, string[] routes) 
    {
        int[]currentPoint = new int[]{0,0};
        Dictionary<(int,int),bool> maze = new Dictionary<(int,int),bool>();
        
        for(int i = 0; i < park.Length; i++)
        {
            for(int j=0; j < park[i].Length; j++)
            {
                switch(park[i][j])
                {
                    case 'S':
                        currentPoint = new int[]{i,j};
                        maze.Add((i,j),true);
                        break;
                    case 'O':
                        maze.Add((i,j),true);
                        break;
                    case 'X':
                        maze.Add((i,j),false);
                        break;
                        
                }
            }
        }
        
        for(int i = 0; i < routes.Length; i++)
        {
            string move = routes[i].Replace(" ",string.Empty);
            int repeat = int.Parse(move[1].ToString());
            int[] totalMove = new int[2];
            int[] direction = new int[2];
            switch(move[0])
            {   
                case 'S':
                    totalMove = new []{repeat,0};
                    direction = new []{1,0};
                    break;
                case 'N':
                    totalMove = new []{-repeat,0};
                    direction = new []{-1,0};
                    break;
                case 'E':
                    totalMove = new []{0,repeat};
                    direction = new []{0,1};
                    break;
                case 'W':
                    totalMove = new []{0,-repeat};
                    direction = new []{0,-1};
                    break;
            }
            
            if(maze.ContainsKey((currentPoint[0]+totalMove[0],currentPoint[1]+totalMove[1])) && maze[(currentPoint[0]+totalMove[0],currentPoint[1]+totalMove[1])])
            {
                
                bool isObstacle  = false;
                int[]tempPoint=new[]{0,0};
                for(int k = 1; k < repeat+1; k++)
                {
                   tempPoint =new int[]{currentPoint[0]+direction[0]*k,currentPoint[1]+direction[1]*k};
                    if(!maze[(tempPoint[0],tempPoint[1])])
                    {
                        isObstacle = true;
                    }
                }
                if(!isObstacle)
                {
                    currentPoint = tempPoint;
                }
                
                
            }
            
        }
        
        return currentPoint;
            
    }
        

}

어려웠던 점

처음에 문제풀이의 방향을 잘못잡은게 가장 큰 문제였다.
Dictionary에 모든 배열의 값을 넣어놓고 하나씩 찾아가게 만드려 했는데, int[]는 참조값이라 동일한 value가 내부에 있어도 동일하다고 판단하지 않는다. 따라서 튜플로 이를 수정하였다.
이차원 배열을 쓸 일이 잘 없어서 자꾸 실수하는 문제점을 추가로 정리하면

  1. 이차원 배열에 참조를 할 때, [i][j]형태로 한다.

  2. 문자열의 경우 하나의 문자에 접근하게 될 경우 이는 'char'로 간주된다.

추가적으로, 정수형 배열을 생성할 때는

int[] arrInt = new int[]{}; 꼴이다. new int에서 int는 생략이 되긴한다.

나름 많은 걸 배워서 문제는 잘 선정한 것 같다.

profile
게임개발자 취준생입니다

0개의 댓글