Skip to content

Commit 0e13b8d

Browse files
committed
feat(composites): new selector random node
Selects the first node to return success and shuffles ever time it's run. Optimized for performance.
1 parent cec1d36 commit 0e13b8d

File tree

6 files changed

+123
-0
lines changed

6 files changed

+123
-0
lines changed

Assets/FluidBehaviorTree/Runtime/BehaviorTree/Builder/BehaviorTreeBuilder.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ public BehaviorTreeBuilder Selector (string name = "selector") {
7070
return ParentTask<Selector>(name);
7171
}
7272

73+
/// <summary>
74+
/// Selects the first node to return success
75+
/// </summary>
76+
/// <param name="name"></param>
77+
/// <returns></returns>
78+
public BehaviorTreeBuilder SelectorRandom (string name = "selector random") {
79+
return ParentTask<SelectorRandom>(name);
80+
}
81+
7382
public BehaviorTreeBuilder Parallel (string name = "parallel") {
7483
return ParentTask<Parallel>(name);
7584
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Adnc.FluidBT.Tasks;
2+
using Random = System.Random;
3+
4+
namespace Adnc.FluidBT.TaskParents.Composites {
5+
/// <summary>
6+
/// Randomly selects a child node with a shuffle algorithm
7+
/// </summary>
8+
public class SelectorRandom : CompositeBase {
9+
private bool _init;
10+
11+
protected override TaskStatus OnUpdate () {
12+
if (!_init) {
13+
ShuffleChildren();
14+
_init = true;
15+
}
16+
17+
for (var i = ChildIndex; i < Children.Count; i++) {
18+
var child = Children[ChildIndex];
19+
20+
switch (child.Update()) {
21+
case TaskStatus.Success:
22+
return TaskStatus.Success;
23+
case TaskStatus.Continue:
24+
return TaskStatus.Continue;
25+
}
26+
27+
ChildIndex++;
28+
}
29+
30+
return TaskStatus.Failure;
31+
}
32+
33+
public override void Reset () {
34+
base.Reset();
35+
36+
ShuffleChildren();
37+
}
38+
39+
private void ShuffleChildren () {
40+
var rng = new Random();
41+
var n = Children.Count;
42+
while (n > 1) {
43+
n--;
44+
var k = rng.Next(n + 1);
45+
var value = Children[k];
46+
Children[k] = Children[n];
47+
Children[n] = value;
48+
}
49+
}
50+
}
51+
}

Assets/FluidBehaviorTree/Runtime/TaskParents/Composites/SelectorRandom.cs.meta

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

Assets/FluidBehaviorTree/Tests/Editor/BehaviorTrees/Builders/BehaviorTreeBuilderTest.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ public void BeforeEach () {
1414
_invokeCount = 0;
1515
_builder = new BehaviorTreeBuilder(null);
1616
}
17+
18+
public class SelectorRandomMethod : BehaviorTreeBuilderTest {
19+
public void It_should_add_a_random_selector () {
20+
var tree = _builder
21+
.SelectorRandom("random selector")
22+
.Build();
23+
24+
var selectorRandom = tree.Root.Children[0] as SelectorRandom;
25+
26+
Assert.IsNotNull(selectorRandom);
27+
}
28+
}
1729

1830
public class SequenceMethod : BehaviorTreeBuilderTest {
1931
[Test]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using Adnc.FluidBT.Tasks;
2+
using Adnc.FluidBT.Testing;
3+
using NUnit.Framework;
4+
5+
namespace Adnc.FluidBT.TaskParents.Composites.Editors.Tests {
6+
public class SelectorRandomTest {
7+
public class UpdateMethod {
8+
[Test]
9+
public void It_should_return_success_if_a_child_returns_success () {
10+
var child = A.TaskStub().WithUpdateStatus(TaskStatus.Success).Build();
11+
var selectorRandom = new SelectorRandom();
12+
selectorRandom.AddChild(child);
13+
14+
Assert.AreEqual(TaskStatus.Success, selectorRandom.Update());
15+
}
16+
17+
[Test]
18+
public void It_should_return_continue_if_a_child_returns_continue () {
19+
var child = A.TaskStub().WithUpdateStatus(TaskStatus.Continue).Build();
20+
var selectorRandom = new SelectorRandom();
21+
selectorRandom.AddChild(child);
22+
23+
Assert.AreEqual(TaskStatus.Continue, selectorRandom.Update());
24+
}
25+
26+
[Test]
27+
public void It_should_return_failure_if_empty () {
28+
var selectorRandom = new SelectorRandom();
29+
30+
Assert.AreEqual(TaskStatus.Failure, selectorRandom.Update());
31+
32+
}
33+
34+
[Test]
35+
public void It_should_return_failure_if_child_returns_failure () {
36+
var child = A.TaskStub().WithUpdateStatus(TaskStatus.Failure).Build();
37+
var selectorRandom = new SelectorRandom();
38+
selectorRandom.AddChild(child);
39+
40+
Assert.AreEqual(TaskStatus.Failure, selectorRandom.Update());
41+
42+
}
43+
}
44+
}
45+
}

Assets/FluidBehaviorTree/Tests/Editor/TaskParents/Composites/SelectorRandomTest.cs.meta

Lines changed: 3 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)