using System; using System.Collections.Generic; using UnityEngine; namespace SynapticPro.BehaviorTree { /// /// Node execution status /// public enum BTStatus { Success, Failure, Running } /// /// Base class for all Behavior Tree nodes /// public abstract class BTNode { public string Name { get; set; } public BTNode Parent { get; protected set; } public bool IsRunning { get; protected set; } /// /// Context data shared across the tree /// public BTContext Context { get; set; } protected BTNode(string name = "Node") { Name = name; } /// /// Execute this node /// public abstract BTStatus Tick(); /// /// Reset node state /// public virtual void Reset() { IsRunning = false; } /// /// Called when node is aborted /// public virtual void Abort() { IsRunning = false; } /// /// Set parent node /// internal void SetParent(BTNode parent) { Parent = parent; } } /// /// Base class for nodes with children /// public abstract class BTComposite : BTNode { protected List children = new List(); protected int currentChildIndex = 0; public IReadOnlyList Children => children; protected BTComposite(string name = "Composite") : base(name) { } /// /// Add a child node /// public BTComposite AddChild(BTNode child) { if (child != null) { child.SetParent(this); child.Context = Context; children.Add(child); } return this; } /// /// Add multiple children /// public BTComposite AddChildren(params BTNode[] nodes) { foreach (var node in nodes) { AddChild(node); } return this; } /// /// Remove a child node /// public void RemoveChild(BTNode child) { if (child != null) { child.SetParent(null); children.Remove(child); } } /// /// Clear all children /// public void ClearChildren() { foreach (var child in children) { child.SetParent(null); } children.Clear(); currentChildIndex = 0; } public override void Reset() { base.Reset(); currentChildIndex = 0; foreach (var child in children) { child.Reset(); } } public override void Abort() { base.Abort(); foreach (var child in children) { child.Abort(); } } } /// /// Base class for decorator nodes (single child) /// public abstract class BTDecorator : BTNode { protected BTNode child; public BTNode Child => child; protected BTDecorator(string name = "Decorator") : base(name) { } /// /// Set the child node /// public BTDecorator SetChild(BTNode node) { if (child != null) { child.SetParent(null); } child = node; if (child != null) { child.SetParent(this); child.Context = Context; } return this; } public override void Reset() { base.Reset(); child?.Reset(); } public override void Abort() { base.Abort(); child?.Abort(); } } /// /// Shared context data for the behavior tree /// public class BTContext { private Dictionary data = new Dictionary(); /// /// The GameObject this tree is attached to /// public GameObject GameObject { get; set; } /// /// The Transform of the GameObject /// public Transform Transform => GameObject?.transform; /// /// Set a value in the context /// public void Set(string key, T value) { data[key] = value; } /// /// Get a value from the context /// public T Get(string key, T defaultValue = default) { if (data.TryGetValue(key, out var value) && value is T typedValue) { return typedValue; } return defaultValue; } /// /// Check if a key exists /// public bool Has(string key) { return data.ContainsKey(key); } /// /// Remove a value /// public void Remove(string key) { data.Remove(key); } /// /// Clear all data /// public void Clear() { data.Clear(); } } }