Skip to content

Feature/comparator nodes #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Core/BehaviourNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ protected GameObject Actor

public bool IsComposite()
{
return MaxChildCount() > 1;
return MaxChildCount() == int.MaxValue;
}

public bool IsDecorator()
Expand All @@ -174,6 +174,11 @@ public bool IsTask()
{
return MaxChildCount() == 0;
}

public bool IsComparator()
{
return MaxChildCount() == 2;
}

/// <summary>
/// A summary description of the node.
Expand Down
34 changes: 33 additions & 1 deletion Core/BehaviourTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,24 @@ public static BehaviourTree Clone(BehaviourTree sourceTree)
else if (copyNode.IsDecorator() && nodeSource.ChildCount() == 1)
{
var copyDecorator = copyNode as Decorator;
copyDecorator.SetChild(GetInstanceVersion(cloneBt, nodeSource.GetChildAt(0))); ;
copyDecorator.SetChild(GetInstanceVersion(cloneBt, nodeSource.GetChildAt(0)));
}

else if (copyNode.IsComparator() && nodeSource.ChildCount() > 0)
{
var copyComparator = copyNode as Comparator;
switch (nodeSource.ChildCount())
{
case 1:
copyComparator.SetChild(GetInstanceVersion(cloneBt, nodeSource.GetChildAt(0)));
break;
case 2:
copyComparator.SetChilds(
GetInstanceVersion(cloneBt, nodeSource.GetChildAt(0)),
GetInstanceVersion(cloneBt, nodeSource.GetChildAt(1))
);
break;
}
}
}

Expand Down Expand Up @@ -406,6 +423,12 @@ private void ClearChildrenStructure(BehaviourNode node)
var decorator = node as Decorator;
decorator.SetChild(null);
}

else if (node.IsComparator())
{
var decorator = node as Comparator;
decorator.SetChilds(null, null);
}
}

#if UNITY_EDITOR
Expand All @@ -421,6 +444,15 @@ void AddBlackboardAsset()
}
}

public void OnValidate()
{
var hasNullable = allNodes.Any(node => node == null);
if (hasNullable)
{
allNodes = allNodes.Where(node => node != null).ToArray();
}
}

[HideInInspector]
public Vector2 panPosition = Vector2.zero;

Expand Down
70 changes: 70 additions & 0 deletions Core/Comparator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using UnityEngine;

namespace Bonsai.Core
{
/// <summary>
/// The base class for two getter nodes.
/// </summary>
public abstract class Comparator : BehaviourNode
{
public sealed override int MaxChildCount()
{
return 2;
}

public abstract void SetChild(object children);
public abstract void SetChilds(object childrenX, object childrenY);
}

public abstract class Comparator<T> : Comparator
{
[SerializeField, HideInInspector] private GetterNode<T> childrenX;
[SerializeField, HideInInspector] private GetterNode<T> childrenY;

protected abstract bool Compare(T x, T y);

public sealed override Status Run()
{
var x = childrenX.Get();
var y = childrenY.Get();
return Compare(x, y) ? Status.Success : Status.Failure;
}

public sealed override void SetChild(object child)
{
if (childrenX == null)
{
childrenX = child as GetterNode<T>;
return;
}

childrenY = child as GetterNode<T>;
}

public sealed override void SetChilds(object childX, object childY)
{
childrenX = childX as GetterNode<T>;
childrenY = childY as GetterNode<T>;
}

public sealed override int ChildCount()
{
var count = 0;
if (childrenX) count++;
if (childrenY) count++;

return count;
}

public sealed override BehaviourNode GetChildAt(int index)
{
return index switch
{
0 => childrenX ? childrenX : childrenY,
1 => childrenY,
_ => throw new ArgumentOutOfRangeException(nameof(index), index, null)
};
}
}
}
3 changes: 3 additions & 0 deletions Core/Comparator.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions Core/GetterNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace Bonsai.Core
{
public abstract class GetterNode : BehaviourNode
{
public sealed override Status Run()
{
return Status.Success;
}

public sealed override BehaviourNode GetChildAt(int index)
{
return null;
}

public sealed override int ChildCount()
{
return 0;
}

public sealed override int MaxChildCount()
{
return 0;
}
}

/// <summary>
/// Base class for a node that takes some values.
/// </summary>
public abstract class GetterNode<T> : GetterNode
{
public abstract T Get();
}
}
3 changes: 3 additions & 0 deletions Core/GetterNode.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Editor/BonsaiEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,11 @@ public static Type CoreType(BehaviourNode behaviour)
{
return typeof(Decorator);
}

if (behaviour is Comparator)
{
return typeof(Comparator);
}

return typeof(Task);
}
Expand Down
15 changes: 15 additions & 0 deletions Editor/BonsaiNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,21 @@ public void SetParent(BonsaiNode newParent)
newParent.OrphanChildren();
newParent.children.Add(this);
}

else if (newParent.behaviour is Comparator)
{
if (newParent.children.Count == 2)
{
var firstChildren = newParent.children[0];
newParent.OrphanChildren();
newParent.children.Add(firstChildren);
newParent.children.Add(this);
}
else
{
newParent.children.Add(this);
}
}

// else: Tasks cannot have children added.
}
Expand Down
2 changes: 2 additions & 0 deletions Editor/BonsaiPreferences.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ public class BonsaiPreferences : ScriptableObject
[Header("Node Colors")]
public Color compositeColor;
public Color decoratorColor;
public Color comparatorColor;
public Color conditionalColor;
public Color serviceColor;
public Color taskColor;
public Color getterColor;

[Header("Status Colors")]
public Color defaultNodeBackgroundColor;
Expand Down
24 changes: 24 additions & 0 deletions Editor/BonsaiSaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ private void SaveTree(TreeMetaData meta, BonsaiCanvas canvas)
// Set parent-child connections matching those in the canvas. Only consider decorators and composites.
SetCompositeChildren(canvas);
SetDecoratorChildren(canvas);
SetComparatorChildren(canvas);

// Re-add nodes to tree.
if (canvas.Root != null)
Expand Down Expand Up @@ -200,6 +201,29 @@ private void SetDecoratorChildren(BonsaiCanvas canvas)
decoratorBehaviour.SetChild(node.GetChildAt(0).Behaviour);
}
}

private void SetComparatorChildren(BonsaiCanvas canvas)
{
IEnumerable<BonsaiNode> comparatorNodes = canvas.Nodes
.Where(n => n.Behaviour.IsComparator() && n.ChildCount() > 0);

foreach (BonsaiNode node in comparatorNodes)
{
var comparatorBehaviour = node.Behaviour as Comparator;
switch (node.Children.Count)
{
case 1:
comparatorBehaviour.SetChild(node.GetChildAt(0).Behaviour);
break;
case 2:
comparatorBehaviour.SetChilds(
node.GetChildAt(0).Behaviour,
node.GetChildAt(1).Behaviour
);
break;
}
}
}

private void AddNewNodeAssets(
BehaviourTree treeAsset,
Expand Down
10 changes: 10 additions & 0 deletions Editor/Drawer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ private static Color NodeTypeColor(BonsaiNode node)
{
return BonsaiPreferences.Instance.decoratorColor;
}

else if (node.Behaviour is Core.Comparator)
{
return BonsaiPreferences.Instance.comparatorColor;
}

else if (node.Behaviour is Core.GetterNode)
{
return BonsaiPreferences.Instance.getterColor;
}

return BonsaiPreferences.Instance.compositeColor;
}
Expand Down
5 changes: 3 additions & 2 deletions Editor/Resources/DefaultBonsaiPreferences.asset
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ MonoBehaviour:
gridTexture: {fileID: 2800000, guid: 4ab4e605fe422164da65569c46a161d2, type: 3}
failureSymbol: {fileID: 2800000, guid: 8db2b847ab6b6434c9da1e0cf721fd8e, type: 3}
successSymbol: {fileID: 2800000, guid: 39cfff267dd954642b26f231c7a997ad, type: 3}
nodeBackgroundTexture: {fileID: 2800000, guid: 6c5508e99038cdf46bb29a177e477d6d,
type: 3}
nodeBackgroundTexture: {fileID: 2800000, guid: 6c5508e99038cdf46bb29a177e477d6d, type: 3}
nodeGradient: {fileID: 2800000, guid: c453f51bbb9d4134d86679c771689df6, type: 3}
portTexture: {fileID: 2800000, guid: dfda76d4e735e7a47bcf756d5d90c44d, type: 3}
compositeColor: {r: 0.3773585, g: 0.3773585, b: 0.3773585, a: 1}
decoratorColor: {r: 0.4553469, g: 0.38719293, b: 0.7264151, a: 1}
comparatorColor: {r: 0.33397114, g: 0.4972861, b: 0.745283, a: 1}
conditionalColor: {r: 0.36663404, g: 0.7264151, b: 0.72088, a: 1}
serviceColor: {r: 0.990566, g: 0.6200383, b: 0.13550198, a: 1}
taskColor: {r: 0.59607846, g: 0.6431373, b: 0.5372549, a: 1}
getterColor: {r: 0.631871, g: 0.745283, b: 0.2988163, a: 1}
defaultNodeBackgroundColor: {r: 0.2924528, g: 0.2924528, b: 0.2924528, a: 1}
selectedColor: {r: 0.3443396, g: 0.62303853, b: 1, a: 1}
runningColor: {r: 0.2971698, g: 1, b: 0.61701846, a: 1}
Expand Down
3 changes: 3 additions & 0 deletions Standard/Comparators.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions Standard/Comparators/DistanceBetween.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using Bonsai;
using Bonsai.Core;
using UnityEngine;

namespace Bonsai.Standard
{
/// <summary>
/// Compares the distance between two Vector3 points.
/// </summary>
[BonsaiNode("Comparators/", "DistanceBetween")]
public class DistanceBetween : Comparator<Vector3>
{
private enum Type
{
Equal,
Less,
Greater
};

[SerializeField] private Type _type = Type.Less;
[SerializeField] private float _value = 2;

protected override bool Compare(Vector3 x, Vector3 y)
{
var distance = Vector3.Distance(x, y);
var isSuccess = _type switch
{
Type.Equal => Math.Abs(distance - _value) < 0.01f,
Type.Less => distance < _value,
Type.Greater => distance > _value,
_ => throw new ArgumentOutOfRangeException()
};

return isSuccess;
}
}
}
3 changes: 3 additions & 0 deletions Standard/Comparators/DistanceBetween.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.