포트폴리오/개인 프로젝트

[개인 프로젝트] FAED

이름?없음 2024. 4. 29. 09:32
반응형

 

반응형

2022년 1학기 방학 개인 프로젝트


깃허브 : https://github.com/dkdkdsa/FastAndEasyDevelop

 

GitHub - dkdkdsa/FastAndEasyDevelop

Contribute to dkdkdsa/FastAndEasyDevelop development by creating an account on GitHub.

github.com

1. 개요

FAED(FastAndEasyDevelop)는 유니티에서 많이 사용하는 여러 기능이 구현되어 있는 툴입니다

ObjectPooling

GoogleParsing

Bhevior tree

GraphView(확장) 등 다양한 기능이 구현되어 있습니다

 

2. 기획 의도

일반적으로 게임 개발에 많이 사용되는 기능이 있다는 것을 발견했고 그것들을 반복해서 개발을 하는 것은 비효율이라고 생각하여 개발하게 되었다 

 

3. 구현

ObjectPooling

게임 개발에 일반적으로 사용하는 풀링을 개발하였다. SO를 이용하여 풀링을 할 오브젝트를 사전 설정이 가능하도록 하였고, 각 씬별로 오브젝트 풀이 관리될 수 있도록 개발하였다

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace FD.Core
{

    public class FAED_PoolManager
    {

        private Dictionary<string, FAED_PoolObj> alwaysPoolingContainer = new Dictionary<string, FAED_PoolObj>();
        private Dictionary<string, FAED_PoolObj> scenePoolingContainer = new Dictionary<string, FAED_PoolObj>();
        private FAED_PoolingSO poolingSO;
        private Transform parent;
        private Transform sceneParent;

        public FAED_PoolManager(FAED_PoolingSO poolingSO, Transform parent) 
        { 
            
            this.poolingSO = poolingSO;
            this.parent = parent;

            for(int i = 0; i < poolingSO.alwaysPoolingObjects.Count; i++) 
            { 
                
                var key = poolingSO.alwaysPoolingObjects[i].poolingKey;
                var poolingLS = poolingSO.alwaysPoolingObjects[i];

                Queue<GameObject> objQ = CreatePoolingQueue(poolingLS.poolCount, key, poolingLS.poolingObject, parent);


                if (alwaysPoolingContainer.ContainsKey(key))
                {

                    Debug.LogError($"Please check key duplication : keyName {key}");
                    continue;

                }

                alwaysPoolingContainer.Add(key, new FAED_PoolObj(poolingLS.poolingObject, objQ));

            }

        }

        private Queue<GameObject> CreatePoolingQueue(int poolCt, string key, GameObject poolObj, Transform parent)
        {

            Queue<GameObject> objQ = new Queue<GameObject>();

            for (int j = 0; j < poolCt; j++)
            {

                var obj = UnityEngine.Object.Instantiate(poolObj, parent);
                obj.gameObject.name = key;
                obj.SetActive(false);
                objQ.Enqueue(obj);

            }

            return objQ;

        }

        public void CreateScenePool(string sceneName)
        {

            Debug.Log(sceneName);

            var pool = poolingSO.scenePoolingObjects.Find(x => x.sceneName == sceneName);

            if (pool == null) return;

            foreach (var item in scenePoolingContainer)
            {

                foreach (var obj in item.Value.objectQueue)
                {

                    UnityEngine.Object.Destroy(obj);

                }

            }

            scenePoolingContainer = new Dictionary<string, FAED_PoolObj>();

            foreach(var obj in pool.scenePoolingObjects)
            {

                var key = obj.poolingKey;
 
                Queue<GameObject> objQ = CreatePoolingQueue(obj.poolCount, key, obj.poolingObject, parent);

                if (scenePoolingContainer.ContainsKey(key))
                {

                    Debug.LogError($"Please check key duplication : keyName {key}");
                    continue;

                }

                scenePoolingContainer.Add(key, new FAED_PoolObj(obj.poolingObject, objQ));

            }

        }
        public void InsertPool(GameObject obj)
        {

            if(alwaysPoolingContainer.ContainsKey(obj.name)) 
            {

                alwaysPoolingContainer[obj.name].objectQueue.Enqueue(obj);
                obj.transform.SetParent(parent);
                obj.SetActive(false);

            }
            else if (scenePoolingContainer.ContainsKey(obj.name))
            {

                scenePoolingContainer[obj.name].objectQueue.Enqueue(obj);
                obj.transform.SetParent(parent);
                obj.SetActive(false);

            }
            else
            {

                Debug.LogWarning($"Pool named {obj.name} does not exist");
                UnityEngine.Object.Destroy(obj);

            }

        }
        public void SetSceneParent(Transform parent) 
        {

            sceneParent = parent;

        }
        public GameObject TakePool(string key, Nullable<Vector3> pos = null, Nullable<Quaternion> rot = null, Transform parent = null)
        {

            if (pos == null) pos = new Vector3(0, 0, 0);
            if (rot == null) rot = Quaternion.identity;

            if (alwaysPoolingContainer.ContainsKey(key)) 
            {

                if (alwaysPoolingContainer[key].objectQueue.Count <= 0)
                {

                    var ins = UnityEngine.Object.Instantiate(alwaysPoolingContainer[key].originObj, (Vector3)pos, (Quaternion)rot, parent);

                    ins.name = key;
                    return ins;

                }

                var obj = alwaysPoolingContainer[key].objectQueue.Dequeue();
                obj.SetActive(true);
                obj.transform.SetParent(sceneParent);
                obj.transform.SetParent(parent);
                obj.transform.position = (Vector3)pos;
                obj.transform.rotation = (Quaternion)rot;

                return obj;

            }
            else if (scenePoolingContainer.ContainsKey(key))
            {


                if (scenePoolingContainer[key].objectQueue.Count <= 0)
                {

                    var ins = UnityEngine.Object.Instantiate(scenePoolingContainer[key].originObj, (Vector3)pos, (Quaternion)rot, parent);

                    ins.name = key;
                    return ins;

                }


                var obj = scenePoolingContainer[key].objectQueue.Dequeue();
                obj.SetActive(true);
                obj.transform.SetParent(sceneParent);
                obj.transform.SetParent(parent);
                obj.transform.position = (Vector3)pos;
                obj.transform.rotation = (Quaternion)rot;

                return obj;

            }
            else
            {

                Debug.LogError($"Pool named {key} does not exist");
                return null;
            }

        }
        public T TakePool<T>(string key, Nullable<Vector3> pos = null, Nullable<Quaternion> rot = null, Transform parent = null)
        {

            return TakePool(key, pos, rot, parent).GetComponent<T>();

        }

    }

}

 

GoogleParsing

EditorCoroutineUtility와 UnityWebRequest를 사용하여 GoogleSheet를 파싱 해올 수 있는 에디터를 개발하였다

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.EditorCoroutines.Editor;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;

namespace FD.Core.Editors
{

    public class FAED_GoogleFormParser : EditorWindow
    {

        protected void GetFromData(string documentID, string sheetID, Action<bool, string> process)
        {

            EditorCoroutineUtility.StartCoroutine(GetFormDataCo(documentID, sheetID, process), this);

        }

        private IEnumerator GetFormDataCo(string documentID, string sheetID, Action<bool, string> process)
        {

            string url = $"https://docs.google.com/spreadsheets/d/{documentID}/export?format=tsv&gid={sheetID}";
            UnityWebRequest res = UnityWebRequest.Get(url);

            yield return res.SendWebRequest();

            if(res.result == UnityWebRequest.Result.ConnectionError || res.responseCode != 200)
            {

                process?.Invoke(false, null);
                yield break;

            }

            process?.Invoke(true, res.downloadHandler.text);

        }

    }

}

 

Bhevior tree

유니티의 커스텀 에디터를 이용하여 그래프로 쉽게 Bhevior tree를 작성할 수 있도록 개발하였다

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace FD.Dev.AI
{

    public class FAED_BehaviorTreeRunner : MonoBehaviour
    {

        [SerializeField] protected FAED_BehaviorTreeSaveData aiData;

        protected FAED_BehaviorTree behaviorTree;

        protected virtual void Awake()
        {

            behaviorTree = Instantiate(aiData.behaviorTree);

        }

        protected virtual void Start()
        {
            
            behaviorTree.rootNode = behaviorTree.rootNode.Copy();
            behaviorTree.rootNode.Init(transform);

        }

        private void Update()
        {

            behaviorTree.rootNode.Execute();

        }

    }


}

Editor

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.Experimental.GraphView;
using UnityEngine.UIElements;
using System.Linq;
using System;
using FD.Dev.AI;
using UnityEditor.Callbacks;

namespace FD.Core.Editors
{

    internal class FAED_BehaviorTreeEditorWindow : FAED_GraphBaseWindow<FAED_BehaviorTreeEditorWindow.FAED_BehaviorTreeGraphView>
    {

        private static FAED_BehaviorTreeSaveData saveData;
        private FAED_VisualWindow inspactor;
        private VisualElement graphRoot;

        [MenuItem("FAED/AI/BehaviorTree")]
        private static void OpenEditor()
        {

            var window = CreateWindow<FAED_BehaviorTreeEditorWindow>();
            window.titleContent.text = "BehaviorTreeEditor";

            window.Show();
            window.maximized = true;

        }

        private void SetUpGraph()
        {

            graphView.SetDrag();
            graphView.SetGrid();
            graphView.SetZoom();
            graphView.style.position = Position.Relative;
            graphView.SetMiniMap(new Rect(10, 10, 300, 300));

        }

        private void SetUpInspacter()
        {

            inspactor = new FAED_VisualWindow("Inspactor", Position.Relative, new Color(0.3f, 0.3f, 0.3f));

        }

        private void SetUpSplit()
        {

            var split = new TwoPaneSplitView(1, 300, TwoPaneSplitViewOrientation.Horizontal);
            split.contentContainer.Add(graphView);
            split.contentContainer.Add(inspactor);
            graphRoot.Add(split);

        }

        private void SetUpToolBar()
        {

            var saveBtn = new Button(HandleSave);
            saveBtn.text = "SaveFile";

            var loadBtn = new Button(HandleLoad);
            loadBtn.text = "LoadFile";

            toolbar.Add(saveBtn);
            toolbar.Add(loadBtn);

        }

        private void HandleSave()
        {

            if(saveData == null)
            {

                var path = EditorUtility.SaveFilePanelInProject("Save", "NewBehaviorTree", "asset", "Save");

                if (path == string.Empty) return;


                saveData = ScriptableObject.CreateInstance<FAED_BehaviorTreeSaveData>();
                var bt = ScriptableObject.CreateInstance<FAED_BehaviorTree>();
                bt.name = "AI";

                AssetDatabase.CreateAsset(saveData, path);
                AssetDatabase.AddObjectToAsset(bt, saveData);

                AssetDatabase.SaveAssets();

                graphView.AddGraphNode(new FAED_BehaviorRootNode());
                saveData = AssetDatabase.LoadAssetAtPath<FAED_BehaviorTreeSaveData>(path);
                saveData.behaviorTree = bt;



            }

            var nodeList = graphView.Query<FAED_BehaviorTreeBaseNode>().ToList();

            foreach (var node in nodeList)
            {

                node.nodeObject.editorPos = node.localBound;

                var com = node.nodeObject as FAED_CompositeNode;

                if(com != null)
                {

                    com.childrens.Clear();

                }

                if (saveData.behaviorTree.nodes.Contains(node.nodeObject)) continue;

                saveData.behaviorTree.nodes.Add(node.nodeObject);
                AssetDatabase.AddObjectToAsset(node.nodeObject, saveData.behaviorTree);
                AssetDatabase.SaveAssets();

            }

            SaveConnect();

            saveData.behaviorTree.SettingRootNode();

            AssetDatabase.SaveAssets();
            EditorUtility.SetDirty(saveData.behaviorTree);

        }

        private void HandleLoad()
        {

            saveData = null;

            graphView.nodes.ToList().ForEach(node =>
            {

                graphView.RemoveElement(node);

            });

            graphView.edges.ToList().ForEach(edge =>
            {

                graphView.RemoveElement(edge);

            });

            var path = EditorUtility.OpenFilePanel("Open", Application.dataPath, "asset");

            if (path == string.Empty) return;

            path = path.Replace(Application.dataPath, "");
            path = path.Insert(0, "Assets");

            saveData = AssetDatabase.LoadAssetAtPath<FAED_BehaviorTreeSaveData>(path);

            if (saveData == null) return;

            DrawGraph(saveData);

        }

        private void DrawGraph(FAED_BehaviorTreeSaveData save)
        {

            if(save == null)
            {

                save = saveData;

            }
            else
            {

                saveData = save;

            }

            if (save == null) return;

            save.behaviorTree.nodes.ForEach((node) =>
            {

                if (node as FAED_ActionNode)
                {

                    var obj = new FAED_BehaviorTreeBaseNode(node.GetType(), node.GetType().Name, "ActionNode");
                    obj.AddPort(Orientation.Vertical, Direction.Input, Port.Capacity.Single);
                    obj.nodeObject = node;
                    obj.guid = node.guid;
                    obj.SetPosition(node.editorPos);
                    obj.OnSelectEvent += inspactor.HandleCreateInspactor;
                    graphView.AddElement(obj);

                }
                else if (node as FAED_CompositeNode)
                {

                    var obj = new FAED_BehaviorChildNode(node.GetType(), Port.Capacity.Multi, node.GetType().Name, "CompositeNode");
                    obj.AddPort(Orientation.Vertical, Direction.Input, Port.Capacity.Single);
                    obj.nodeObject = node;
                    obj.guid = node.guid;
                    obj.SetPosition(node.editorPos);
                    obj.OnSelectEvent += inspactor.HandleCreateInspactor;
                    graphView.AddElement(obj);

                }
                else if (node as FAED_DecoratorNode)
                {

                    var obj = new FAED_BehaviorChildNode(node.GetType(), Port.Capacity.Single, node.GetType().Name, "DecoratorNode");
                    obj.AddPort(Orientation.Vertical, Direction.Input, Port.Capacity.Single);
                    obj.nodeObject = node;
                    obj.guid = node.guid;
                    obj.SetPosition(node.editorPos);
                    obj.OnSelectEvent += inspactor.HandleCreateInspactor;
                    graphView.AddElement(obj);

                }
                else if (node as FAED_RootNode)
                {

                    var obj = new FAED_BehaviorChildNode(node.GetType(), Port.Capacity.Single, "StartPoint", "Root");
                    obj.nodeObject = node;
                    obj.guid = node.guid;
                    obj.SetPosition(node.editorPos);
                    obj.OnSelectEvent += inspactor.HandleCreateInspactor;
                    graphView.AddElement(obj);


                }

            });

            save.connectData.ForEach((x) =>
            {

                var inputNode = graphView.Query<FAED_BehaviorTreeBaseNode>().ToList().Find(xx => xx.guid.ToString() == x.inputGuid);
                var outputNode = graphView.Query<FAED_BehaviorTreeBaseNode>().ToList().Find(xx => xx.guid.ToString() == x.outputGuid);

                var edge = inputNode.inputContainer.Q<Port>().ConnectTo(outputNode.outputContainer.Q<Port>());

                graphView.AddElement(edge);

            });


        }

        private void SaveConnect()
        {

            var edgeLs = graphView.edges.ToList();
            saveData.connectData.Clear();

            foreach(var edge in edgeLs)
            {

                var inputNode = edge.input.node as FAED_BehaviorTreeBaseNode;
                var outputNode = edge.output.node as FAED_BehaviorTreeBaseNode;

                saveData.connectData.Add(new FAED_ConnectData 
                { 

                    inputGuid = inputNode.guid.ToString(), 
                    outputGuid = outputNode.guid.ToString()

                });

                ConnectNode(inputNode, outputNode);

            }

        }

        private void ConnectNode(FAED_BehaviorTreeBaseNode input, FAED_BehaviorTreeBaseNode output)
        {

            if(output.nodeObject as FAED_CompositeNode != null)
            {

                var obj = output.nodeObject as FAED_CompositeNode;

                obj.childrens.Add(input.nodeObject);
                obj.childrens = obj.childrens.OrderBy(x => x.editorPos.x).ToList();

            }
            else if(output.nodeObject as FAED_DecoratorNode != null)
            {

                var obj = output.nodeObject as FAED_DecoratorNode;
                obj.children = input.nodeObject;

            }
            else if(output.nodeObject as FAED_RootNode != null)
            {


                var obj = output.nodeObject as FAED_RootNode;
                obj.children = input.nodeObject;

            }

        }

        private GraphViewChange HandleGraphViewChanged(GraphViewChange graphViewChange)
        {

            if (graphViewChange.elementsToRemove != null)
            {

                foreach (var elem in graphViewChange.elementsToRemove)
                {

                    var node = elem as FAED_BehaviorTreeBaseNode;

                    if (node != null && saveData != null)
                    {

                        if (saveData.behaviorTree.nodes.Contains(node.nodeObject))
                        {

                            saveData.behaviorTree.nodes.Remove(node.nodeObject);
                            AssetDatabase.RemoveObjectFromAsset(node.nodeObject);

                        }

                    }

                }

            }

            return graphViewChange;

        }

        [OnOpenAsset]
        public static bool OnOpenAsset(int instanceID, int line)
        {

            var obj = Selection.activeObject as FAED_BehaviorTreeSaveData;

            if (obj != null)
            {

                saveData = obj;
                OpenEditor();
                return true;

            }

            return false;

        }

        protected override void OnEnable()
        {
            
            base.OnEnable();
            AddToolBar();

            graphRoot = new VisualElement();
            graphRoot.style.flexGrow = 1;
            rootVisualElement.Add(graphRoot);

            SetUpGraph();
            SetUpInspacter();
            SetUpSplit();
            SetUpToolBar();

            graphView.Init(inspactor, HandleGraphViewChanged);

            DrawGraph(null);

        }

        private void OnDisable()
        {

            saveData = null;

        }

        #region 그래프 관련

        /// <summary>
        /// 그래프뷰
        /// </summary>
        internal class FAED_BehaviorTreeGraphView : FAED_BaseGraphView
        {

            private FAED_BehaviorTreeSearchWindow searchWindow;
            private FAED_VisualWindow inspactor;

            public FAED_BehaviorTreeGraphView() : base()
            {

                SetSearchWindow();

            }

            private void SetSearchWindow()
            {

                searchWindow = ScriptableObject.CreateInstance<FAED_BehaviorTreeSearchWindow>();
                searchWindow.Init(this);
                nodeCreationRequest = context => SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), searchWindow);

            }

            public void Init(FAED_VisualWindow inspactor, GraphViewChanged changed)
            {

                this.inspactor = inspactor;
                graphViewChanged += changed;

            }

            public void AddGraphNode(FAED_BehaviorTreeBaseNode node)
            {

                node.OnSelectEvent += inspactor.HandleCreateInspactor;

                AddElement(node);

            }

            public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
            {

                return ports.ToList().Where(x => x.direction != startPort.direction && x.node != startPort.node).ToList();

            }


        }

        /// <summary>
        /// 그래프 노드 생성창
        /// </summary>
        internal class FAED_BehaviorTreeSearchWindow : ScriptableObject, ISearchWindowProvider
        {

            private FAED_BehaviorTreeGraphView graphView;

            public void Init(FAED_BehaviorTreeGraphView graphView)
            {

                this.graphView = graphView;

            }

            public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
            {

                var tree = new List<SearchTreeEntry>()
                {

                    new SearchTreeGroupEntry(new GUIContent("Create Behavior"), 0),
                    new SearchTreeGroupEntry(new GUIContent("Create Node"), 1),

                };

                var types = TypeCache.GetTypesDerivedFrom<FAED_Node>();

                foreach(var t in types)
                {

                    if (t == typeof(FAED_RootNode) || t.IsAbstract) continue;

                    tree.Add(new SearchTreeEntry(new GUIContent(t.Name))
                    {

                        userData = t,
                        level = 2

                    });

                }

                

                return tree;

            }

            public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context)
            {

                if(SearchTreeEntry.userData as Type != null)
                {

                    var type = SearchTreeEntry.userData as Type;

                    if (type.IsSubclassOf(typeof(FAED_ActionNode)))
                    {

                        var node = new FAED_BehaviorTreeBaseNode(type, type.Name, "ActionNode");
                        node.AddPort(Orientation.Vertical, Direction.Input, Port.Capacity.Single);
                        node.transform.position = graphView.ChangeCoordinatesTo(graphView.contentContainer, context.screenMousePosition);

                        graphView.AddGraphNode(node);

                    }
                    else if (type.IsSubclassOf(typeof(FAED_CompositeNode)))
                    {

                        var node = new FAED_BehaviorChildNode(type, Port.Capacity.Multi, type.Name, "CompositeNode");
                        node.AddPort(Orientation.Vertical, Direction.Input, Port.Capacity.Single);
                        node.transform.position = context.screenMousePosition;

                        graphView.AddGraphNode(node);

                    }
                    else if (type.IsSubclassOf(typeof(FAED_DecoratorNode)))
                    {


                        var node = new FAED_BehaviorChildNode(type, Port.Capacity.Single, type.Name, "CompositeNode");
                        node.AddPort(Orientation.Vertical, Direction.Input, Port.Capacity.Single);
                        node.transform.position = context.screenMousePosition;

                        graphView.AddGraphNode(node);

                    }

                    return true;

                }

                return false;

            }

        }

        #endregion

        #region Node 관련

        internal class FAED_BehaviorTreeBaseNode : FAED_BaseNode
        {

            public event Action<FAED_BehaviorTreeBaseNode> OnSelectEvent;
            public FAED_Node nodeObject;
            public Label descriptionLabel;

            internal FAED_BehaviorTreeBaseNode(Type classType, string title, string message) : base(AssetDatabase.GetAssetPath(Resources.Load<VisualTreeAsset>("BehaviorNode")))
            {

                nodeObject = ScriptableObject.CreateInstance(classType) as FAED_Node;

                nodeObject.guid = guid;
                nodeObject.name = classType.Name;

                styleSheets.Clear();
                styleSheets.Add(Resources.Load<StyleSheet>("BehaviorNodeStyle"));
                descriptionLabel = mainContainer.Q<Label>("description");
                this.title = title;
                descriptionLabel.text = message;

                RefreshAll();

            }

            public override void OnSelected()
            {

                base.OnSelected();
                
                OnSelectEvent?.Invoke(this);

            }

        }

        internal class FAED_BehaviorChildNode : FAED_BehaviorTreeBaseNode
        {

            public List<FAED_BehaviorTreeBaseNode> childrens;

            internal FAED_BehaviorChildNode(Type classType, Port.Capacity capacity, string title, string message) : base(classType, title, message)
            {

                AddPort(Orientation.Vertical, Direction.Output, capacity);

            }

        }

        internal class FAED_BehaviorRootNode : FAED_BehaviorChildNode
        {

            internal FAED_BehaviorRootNode() : base(typeof(FAED_RootNode), Port.Capacity.Single, "StartPoint", "Root")
            {


            }

        }

        #endregion

        #region 잡것들

        /// <summary>
        /// uxml작성할줄 몰라서 만든 윈도우
        /// </summary>
        internal class FAED_VisualWindow : VisualElement
        {

            private Editor editor;

            public VisualElement titleContainer { get; protected set; }
            public Label titleLabel { get; protected set; }
            public VisualElement guiContainer { get; protected set; }

            public FAED_VisualWindow(string text, Position position, Color backGroundColor)
            {

                style.backgroundColor = backGroundColor;
                style.position = position;
                style.flexGrow = 1;

                CreateTitleContainer();

                titleContainer = new VisualElement();
                titleContainer.style.position = Position.Relative;
                titleContainer.style.backgroundColor = Color.black;
                titleContainer.style.flexShrink = 0;

                titleLabel = new Label(text);
                titleLabel.style.position = Position.Relative;
                titleLabel.style.fontSize = 24;

                titleContainer.Add(titleLabel);

                guiContainer = new VisualElement();
                guiContainer.style.position = Position.Relative;
                guiContainer.style.flexGrow = 1;

                Add(titleContainer);
                Add(guiContainer);


            }

            private void CreateTitleContainer()
            {

                titleContainer = new VisualElement();
                titleContainer.style.position = Position.Relative;
                titleContainer.style.backgroundColor = Color.black;

                Add(titleContainer);

            }

            public void HandleCreateInspactor(FAED_BehaviorTreeBaseNode node)
            {

                UnityEngine.Object.DestroyImmediate(editor);
                editor = Editor.CreateEditor(node.nodeObject);
                guiContainer.Clear();

                var imgui = new IMGUIContainer(() =>
                {

                    if (editor.target)
                    {

                        editor.OnInspectorGUI();

                    }

                });

                imgui.style.flexGrow = 1;

                guiContainer.Add(imgui);


            }

        }
        #endregion

    }

}

 

4. 개발 중 문제점

1학년때부터 개발하던 코드라 약간 더러운 감이 있고 커스텀 에디터를 개발할 때는 UIToolKit의 존재를 알지 못하여 직접 하나하나 코드로 작성했다는 문제점이 있다

 

5. 프로젝트로 느낀 점

여러 프로젝트에서도 사용 가능하게 코드를 작성하는 것이 어려웠다 하지만 완성을 시키니 내가 만드는 거의 모든 프로젝트에서 사용이 가능하여 편리했다

반응형