# Node 초기화 함수 추가
런타임 중에 Awake나 Start 함수에서 Node를 초기화하는 기능이 필요할 것 같아서 추가했다.
Root Node부터 시작해서 하위 Node들의 Init 함수를 재귀형태로 실행한다.
public void Init(BehaviourTreeContext context)
{
this.Context = context;
if (string.IsNullOrEmpty(RootNodeGuid))
Debug.LogError($"{nameof(BehaviourTree)} : Root Node Guid is Empty");
rootNode = FindNode(RootNodeGuid);
InitRecursive(rootNode);
}
private void InitRecursive(BehaviourNode node)
{
node.Init(this);
List<string> nodeGuidList = FindNode(node.Guid).ChildNodeGuidList;
foreach(string guid in nodeGuidList)
InitRecursive(FindNode(guid));
}
public class BehaviourTreeController : MonoBehaviour
{
public BehaviourTree BehaviourTree;
private void Awake()
{
BehaviourTreeContext context = new BehaviourTreeContext(gameObject);
BehaviourTree.Init(context);
}
private void Update()
{
BehaviourTree.Evaluate();
}
}
# Blackboard
Behaviour Tree에서 Node끼리의 데이터를 공유할 때 Blackboard란 걸 만들어서 사용하는 것 같다.
Behavior Tree (4) - 데이터 전달하기(Blackboard)
이전 글: 2022.08.30 - [Game AI] - Behavior Tree (3) - Parallel Behavior Tree (3) - Parallel 이전 글 : 2022.08.27 - [Game AI] - Behavior Tree (2) - 확률, Decorator, 리소스 보호 Behavior Tree (2) - 확률, Decorator, 리소스 보호 이전 글
tsyang.tistory.com
예를 들어, 게임에서 적 AI가 플레이어를 쫓아가는 행동 트리를 구성한다고 할 때, Blackboard에는 아래와 같은 데이터가 저장되고 사용될 수 있다.
- 플레이어의 현재 위치
- 적 AI의 현재 체력
- 적 AI가 현재 따라가고 있는 경로
데이터 타입을 한정하기 위해서 Dictionary 안에 Dictionary가 들어가는 형태로 만들어서 Type의 따라 새로운 Dictionary를 만들어서 데이터를 관리한다.
public class BehaviourTreeBlackboard
{
private Dictionary<Type, IDictionary> blackboardDictionary = new Dictionary<Type, IDictionary>();
public void SetData<T>(string keyName, T value)
{
if (!blackboardDictionary.ContainsKey(typeof(T)))
blackboardDictionary.Add(typeof(T), new Dictionary<string, T>());
IDictionary dic = blackboardDictionary[typeof(T)];
if (dic.Contains(keyName))
{
dic[keyName] = value;
}
else
{
dic.Add(keyName, value);
}
}
public T GetData<T>(string keyName)
{
if (!blackboardDictionary.ContainsKey(typeof(T)))
return default(T);
IDictionary dic = blackboardDictionary[typeof(T)];
if (!dic.Contains(keyName))
return default(T);
return (T)dic[keyName];
}
}
public override void Init(BehaviourTree tree)
{
base.Init(tree);
tree.Blackboard.SetData<string>("Test Key", "Test String Value");
}
public override NodeState Evaluate()
{
string testString = tree.Blackboard.GetData<string>("Test Key");
Debug.LogWarning("Blackboard 출력 : " + testString);
return NodeState.Success;
}
# Behaviour Tree Settings
Node별로 이미지를 추가해서 노드가 어떤 기능인지 나타내는 기능을 만들었는데, 개별 Tree마다 설정할게 아니라 모든 Tree가 공유하는 이미지나 값들을 추가하는 게 더 나을 것 같아서 만들게 되었다.
Setting 값들을 저장하고 관리하는 ScriptableObject
public class BehaviourTreeSettings : ScriptableObject
{
public const string SettingsPath = "Assets/BehaviourTreeEditor/BehaviourTreeSettings.asset";
public Texture2D SequenceTexture;
private static BehaviourTreeSettings instance;
public static BehaviourTreeSettings Instance
{
get
{
if (instance == null)
{
instance = GetOrCreateSettings();
}
return instance;
}
}
public static BehaviourTreeSettings GetOrCreateSettings()
{
var settings = AssetDatabase.LoadAssetAtPath<BehaviourTreeSettings>(SettingsPath);
if (settings == null)
{
settings = ScriptableObject.CreateInstance<BehaviourTreeSettings>();
AssetDatabase.CreateAsset(settings, SettingsPath);
AssetDatabase.SaveAssets();
}
return settings;
}
public void Save()
{
EditorUtility.SetDirty(this);
AssetDatabase.SaveAssets();
}
}
ScriptableObject에 설정된 Setting 값들을 [ProjectSettings] 창에서 보여주기 위한 SettingsProvider 클래스
public class BehaviourTreeSettingsProvider : SettingsProvider
{
private static BehaviourTreeSettings settings;
public BehaviourTreeSettingsProvider(string path, SettingsScope scopes, IEnumerable<string> keywords = null) : base(path, scopes, keywords)
{
settings = BehaviourTreeSettings.GetOrCreateSettings();
}
public override void OnGUI(string searchContext)
{
base.OnGUI(searchContext);
GUILayout.Label("Node Texture", EditorStyles.boldLabel);
settings.SequenceTexture = EditorGUILayout.ObjectField("Sequence Node Texture", settings.SequenceTexture, typeof(Texture2D), false) as Texture2D;
if (GUI.changed)
{
settings.Save();
}
}
[SettingsProvider]
public static SettingsProvider CreateBehaviourTreeSettingsProvider()
{
return new BehaviourTreeSettingsProvider("Project/Behaviour Tree Settings", SettingsScope.Project);
}
}
GitHub - mintchobab/Unity_Practice_Editor
Contribute to mintchobab/Unity_Practice_Editor development by creating an account on GitHub.
github.com
'Unity > 개발연습' 카테고리의 다른 글
[Unity] Behaviour Tree Editor 제작기 - 8 (0) | 2024.10.21 |
---|---|
[Unity] Behaviour Tree Editor 제작기 - 7 (2) | 2024.10.21 |
[Unity] Behaviour Tree Editor 제작기 - 5 (0) | 2024.09.01 |
[Unity] Behaviour Tree Editor 제작기 - 4 (1) | 2024.08.30 |
[Unity] Behaviour Tree Editor 제작기 - 3 (0) | 2024.08.30 |