Unity 최종 프로젝트 - 26 (Behavior Tree Editor 제작-4)

이준호·2024년 2월 18일
0
post-custom-banner

📌 Unity 최종 프로젝트



📌 Behavior Tree Graph View Editor 제작

➔ Runtime Editing

  • 현재 선택된 객체가 null이 아닌지 확인.

  • null이 아니라면 해당 객체의 ‘BehaviorTreeRunner’ 컴포넌트를 가져온다.

  • 애플리케이션이 실행 중 이라면, 트리뷰를 그린다.

  • 실행중이 아니라면 에셋 데이터베이스의 인스턴스 아이디를 조회하여 트리뷰를 그린다.

  • Traverse 메서드로 노드를 순회하여 자식을 tree의 nodes 리스트에 추가하여 행동 트리의 모든 노드들의 클론을 생성.

  • 에디터를 On/Off 할 때, OnEnable/Disalbe 메서드를 사용하여 OnPlayModeStateChanged 메서드 구독 및 취소로 뷰를 업데이트(새로 그려줌) (편집 모드, 플레이 모드 시에 OnSelectionChange(선택시 변경 이벤트 메서드)를 실행)

  • 런타임 중에 에디터 변경 가능.
    CreatNode메서드에서 에셋 데이터베이스에 노드를 추가하는 코드를 if(!Application.isPlaying) 으로 조건문을 걸어주어 런타임중이 아니라면 추가하지 않게 하여 런타임중에 에디터를 추가 및 삭제하며 수정 가능 (종료시 원상복귀)

  • 런타임 중에 에디터의 수평 순서에 따라 노드 순회 순서 자동 변경(왼쪽에서 오른쪽으로)









Add Code

BehaviorTree.cs

if (!Application.isPlaying)
	AssetDatabase.AddObjectToAsset(node, this);
    
    public void Traverse(Node node, System.Action<Node> visitor)
    {
        if (node)
        {
            visitor.Invoke(node);
            var children = GetChildren(node);
            children.ForEach((n) => Traverse(n, visitor));
        }
    }
    
    tree.nodes = new List<Node>();
        
    Traverse(tree.rootNode, (n) => { tree.nodes.Add(n); });




BehaviorTreeEditor.cs

    private void OnEnable()
    {
        EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
        EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
    }

    private void OnDisable()
    {
        EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
    }
    
    // 플레이 모드 상태가 변경될 때 호출되는 메서드
    private void OnPlayModeStateChanged(PlayModeStateChange obj)
    {
        switch (obj)
        {
            case PlayModeStateChange.EnteredEditMode:
                OnSelectionChange();
                break;
            case PlayModeStateChange.ExitingEditMode:
                break;
            case PlayModeStateChange.EnteredPlayMode:
                OnSelectionChange();
                break;
            case PlayModeStateChange.ExitingPlayMode:
                break;
        }
    }


        if (_treeView == null)
            return;

        if (!tree)
        {
            if (Selection.activeGameObject) // 화성화된 게임 오브젝트가 null이 아니라면
            {
                BehaviorTreeRunner runner = Selection.activeGameObject.GetComponent<BehaviorTreeRunner>();
                if (runner)
                    tree = runner.tree;
            }
        }

        if (Application.isPlaying)
        {
            if (tree)
                _treeView.PopulateView(tree);
        }
        else
        {
            if (tree && AssetDatabase.CanOpenAssetInEditor(tree.GetInstanceID()))
            {
                _treeView.PopulateView(tree);
            }




BehaviorTreeView.cs

        // 이동요소가 있다면, view의 자식들을 Sort정렬
        if (graphViewChange.movedElements != null)
        {
            nodes.ForEach((n) =>
            {
                NodeView view = n as NodeView;
                view.SortChildren();
            });
        }




NodeView.cs

    // 에디터상 수평 위치 순서에 따라 노드 순서 변경 메서드
    public void SortChildren()
    {
        Composite composite = node as Composite;
        
        if (composite)
            composite.children.Sort(SortByHorizontalPosition);
    }

    private int SortByHorizontalPosition(Node left, Node right)
    {
        return left.position.x < right.position.x ? -1 : 1;
    }











📌 출저

TheKiwiCoder

profile
No Easy Day
post-custom-banner

0개의 댓글