Skip to content

Commit c47bdb2

Browse files
Working Visual Tree With Parameters
Visual Tree tool is working with parameter lists and descriptive labels!
1 parent f8debb4 commit c47bdb2

File tree

80 files changed

+3557
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+3557
-0
lines changed

Assets/AI.meta

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/AI/BehaviorManager.cs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
using Assets.Scripts.AI.Components;
2+
using Assets.Scripts.AI.Tree;
3+
using System;
4+
using System.Collections;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using UnityEngine;
8+
using Newtonsoft.Json;
9+
using System.ComponentModel;
10+
11+
namespace Assets.Scripts.AI
12+
{
13+
public class BehaviorManager : MonoBehaviour
14+
{
15+
public string FileName = "";
16+
/// <summary>
17+
/// The file to actually save/load to/from.
18+
/// </summary>
19+
[JsonIgnore]
20+
public BehaviorTreeManagerAsset BehaviorTreeFile;
21+
22+
/// <summary>
23+
/// Primary Runner for this manager.
24+
/// Runs all sub-behaviors/trees at the same time using the specified parallelrunner attributes.
25+
/// </summary>
26+
private ParallelRunner runner = new ParallelRunner("Main Root", -1, -1);
27+
public ParallelRunner Runner
28+
{
29+
get
30+
{
31+
return runner;
32+
}
33+
34+
set
35+
{
36+
runner = value;
37+
}
38+
}
39+
40+
/// <summary>
41+
/// Seconds between every tick. At "0" this will tick every frame (basically an update loop)
42+
/// </summary>
43+
[SerializeField]
44+
[Description("Seconds between every tick. At 0 this will tick every frame")]
45+
public float SecondsBetweenTicks = 0.1f;
46+
47+
/// <summary>
48+
/// Number of times to tick the full trees. Set to a negative number to make an infinitely running behavior tree.
49+
/// </summary>
50+
[SerializeField]
51+
52+
public int TimesToTick = 10;
53+
54+
55+
public bool spliceNewIntoTree = false;
56+
/// <summary>
57+
/// A list of trees to splice into the current tree. These are not directly editable.
58+
/// </summary>
59+
[JsonIgnore]
60+
public List<BehaviorTreeManagerAsset> SpliceList;
61+
62+
private bool initialized = false;
63+
64+
void OnEnable()
65+
{
66+
InitIfNeeded();
67+
}
68+
69+
public void InitIfNeeded()
70+
{
71+
if (initialized == false)
72+
{
73+
Reinitialize();
74+
}
75+
}
76+
77+
public void Reinitialize()
78+
{
79+
//TODO: Change to runner extension (?)
80+
Runner = BehaviorTreeFile.LoadFromJSON(this);
81+
82+
83+
if(spliceNewIntoTree) SpliceIntoRunner();
84+
initialized = true;
85+
}
86+
87+
//TODO: Add ILogger *(perhaps Observer pattern? This is our "singleton")*
88+
//Dispatch messages to observed classes and receive that information here...
89+
//How to store? List? Dictionary? My face? Cat Pictures?
90+
91+
/// <summary>
92+
/// Ticks on the aggregate ParallelRunner then continues ticking for as long as the runner is in running state
93+
/// </summary>
94+
/// <returns></returns>
95+
IEnumerator Start()
96+
{
97+
WaitForSeconds wfs = new WaitForSeconds(SecondsBetweenTicks);
98+
99+
Debug.Log("Starting ticks on Runner: \n\t" + Runner.ToString());
100+
yield return Runner.Tick();
101+
while (Runner.CurrentState == BehaviorState.Running && (TimesToTick != 0))
102+
{
103+
yield return StartCoroutine(Runner.Tick(wfs));
104+
--TimesToTick;
105+
}
106+
107+
Debug.Log("All Coroutines Should be DONE now! Ending all to make sure....");
108+
StopAllCoroutines();
109+
}
110+
111+
/// <summary>
112+
/// Splice all trees in the "splice" area of the editor and return "true" if new trees were spliced.
113+
/// </summary>
114+
/// <returns></returns>
115+
public bool SpliceIntoRunner()
116+
{
117+
if (SpliceList != null)
118+
{
119+
foreach (var behaviorAsset in SpliceList)
120+
{
121+
if (behaviorAsset == null) return false;
122+
123+
var spliceTree = behaviorAsset.LoadFromJSON();
124+
125+
foreach (var behavior in spliceTree.Children)
126+
{
127+
if (behavior.Depth == -1 || behavior.Name == "root") continue;
128+
129+
dynamic newBehavior = Activator.CreateInstance(Type.GetType(((BehaviorTreeElement)behavior).ElementType),
130+
behavior.Name, behavior.Depth, behavior.ID);
131+
newBehavior.BehaviorTreeManager = this;
132+
Runner.AddChild(newBehavior);
133+
}
134+
}
135+
136+
return true;
137+
}
138+
else return false;
139+
}
140+
}
141+
}

Assets/AI/BehaviorManager.cs.meta

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/AI/BehaviorState.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace Assets.Scripts.AI
2+
{
3+
//TODO: Error state? Needed? Useful?
4+
/// <summary>
5+
/// Null usually means this behavior has not started or is in an error state.
6+
/// Fail, Success, and Running are for checking the current state from the parent object.
7+
/// </summary>
8+
public enum BehaviorState
9+
{
10+
Null = 0,
11+
Fail,
12+
Success,
13+
Running
14+
}
15+
}

Assets/AI/BehaviorState.cs.meta

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/AI/BehaviorTreeElement.cs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using Assets.Scripts.AI.Tree;
2+
using System;
3+
using System.Collections;
4+
using System.Collections.Generic;
5+
using UnityEngine;
6+
7+
namespace Assets.Scripts.AI
8+
{
9+
[Serializable]
10+
public class BehaviorTreeElement : TreeElement
11+
{
12+
private string _ElementType;
13+
public string ElementType
14+
{
15+
get
16+
{
17+
return _ElementType;
18+
}
19+
20+
set
21+
{
22+
_ElementType = value;
23+
}
24+
}
25+
26+
[Newtonsoft.Json.JsonIgnore]
27+
[SerializeField]
28+
private BehaviorManager _BehaviorTreeManager;
29+
[Newtonsoft.Json.JsonIgnore]
30+
public BehaviorManager BehaviorTreeManager
31+
{
32+
get
33+
{
34+
return _BehaviorTreeManager;
35+
}
36+
37+
set
38+
{
39+
_BehaviorTreeManager = value;
40+
}
41+
}
42+
43+
public BehaviorTreeElement(string name, int depth, int id)
44+
: base(name, depth, id)
45+
{
46+
ElementType = this.GetType().ToString();
47+
_CurrentState = BehaviorState.Null;
48+
Children = new List<TreeElement>();
49+
}
50+
51+
private BehaviorState _CurrentState;
52+
[Newtonsoft.Json.JsonIgnore]
53+
public BehaviorState CurrentState
54+
{
55+
get
56+
{
57+
return _CurrentState;
58+
}
59+
protected set
60+
{
61+
_CurrentState = value;
62+
}
63+
}
64+
65+
public virtual IEnumerator Tick(WaitForSeconds delayStart = null)
66+
{
67+
if (delayStart != null)
68+
{
69+
yield return delayStart;
70+
}
71+
}
72+
73+
public override string ToString()
74+
{
75+
var depthPad = "";
76+
for (int d = 0; d < this.Depth +1; ++d)
77+
{
78+
depthPad += " ";
79+
}
80+
var retString = depthPad + "ID: " + ID + "\n" +
81+
depthPad + "Name: " + this.Name + "\n" +
82+
depthPad +"Depth: " + Depth + "\n" +
83+
depthPad + "Type: " + ElementType.ToString() + "\n" +
84+
depthPad + "NumChildren: " + (HasChildren ? Children.Count : 0) + "\n";
85+
86+
if (Children != null)
87+
{
88+
retString += depthPad + "Children: \n";
89+
foreach (var child in Children)
90+
{
91+
retString += child.ToString();
92+
}
93+
}
94+
95+
return retString;
96+
97+
}
98+
}
99+
}

Assets/AI/BehaviorTreeElement.cs.meta

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using Assets.Scripts.AI.Components;
2+
using Assets.Scripts.AI.Tree;
3+
using Newtonsoft.Json;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Reflection;
7+
using UnityEngine;
8+
9+
namespace Assets.Scripts.AI
10+
{
11+
[System.Serializable]
12+
public class BehaviorTreeManagerAsset : ScriptableObject
13+
{
14+
public int TimesToTick;
15+
public float SecondsBetweenTicks = 0.1f;
16+
17+
public string RunnerElementsJSON;
18+
}
19+
20+
public static class AssetExtensions
21+
{
22+
public static ParallelRunner LoadFromJSON(this BehaviorTreeManagerAsset asset, BehaviorManager manager = null)
23+
{
24+
//TODO: Reload button
25+
//TODO: Confirm reload from json
26+
if (asset == null)
27+
{
28+
Debug.Log("Asset is null when loading");
29+
return new ParallelRunner("Empty Root", -1, -1);
30+
}
31+
else
32+
{
33+
//Elements should be a list of dynamic objects
34+
var elements = JsonConvert.DeserializeObject<List<dynamic>>(asset.RunnerElementsJSON);
35+
36+
var newElements = new List<BehaviorTreeElement>();
37+
foreach(dynamic el in elements)
38+
{
39+
string typeName = el.ElementType;
40+
Type type = Assembly.GetAssembly(typeof(BehaviorTreeElement)).GetType(typeName);
41+
dynamic newBehavior = Activator.CreateInstance(type, (string)el.Name, (int)el.Depth, (int)el.ID);
42+
43+
FieldInfo[] fields = type.GetFields();
44+
45+
JsonConvert.PopulateObject(JsonConvert.SerializeObject(el), newBehavior);
46+
newElements.Add(newBehavior);
47+
}
48+
var str = "";
49+
foreach(var e in newElements)
50+
{
51+
e.BehaviorTreeManager = manager;
52+
str += e.Name + "\n";
53+
}
54+
55+
var tree = TreeElementUtility.ListToTree(newElements);
56+
57+
return (ParallelRunner)tree;
58+
}
59+
}
60+
}
61+
62+
}

Assets/AI/BehaviorTreeManagerAsset.cs.meta

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/AI/BehaviorTrees.meta

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)