491 lines
28 KiB
C#
491 lines
28 KiB
C#
|
//============= Copyright (c) Ludic GmbH, All rights reserved. ==============
|
|||
|
//
|
|||
|
// Purpose: Part of the My Behaviour Tree Code
|
|||
|
//
|
|||
|
//=============================================================================
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Xml.Serialization;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
namespace MyBT {
|
|||
|
public enum CompositeParameter {
|
|||
|
Undefined,
|
|||
|
|
|||
|
Sequence,
|
|||
|
Selector,
|
|||
|
Race,
|
|||
|
Marathon,
|
|||
|
}
|
|||
|
|
|||
|
// [XmlInclude(typeof(CompositeNode))]
|
|||
|
public class CompositeNode : Node {
|
|||
|
[SerializeField]
|
|||
|
public List<CompositeParameter> parameters;
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
private CompositeParameter compositeType = CompositeParameter.Undefined;
|
|||
|
|
|||
|
public bool Has(CompositeParameter compositeParameter) {
|
|||
|
return parameters.Contains(compositeParameter);
|
|||
|
}
|
|||
|
|
|||
|
public void Init(int _nodeDepth, Token[] _tokens, List<string> stringParameter) {
|
|||
|
base.Init(_nodeDepth, _tokens);
|
|||
|
parameters = new List<CompositeParameter>();
|
|||
|
for (int i = 0; i < stringParameter.Count; i++) {
|
|||
|
CompositeParameter compositeParameter = CompositeParameter.Undefined;
|
|||
|
if (Enum.TryParse(stringParameter[i], out compositeParameter)) {
|
|||
|
parameters.Add(compositeParameter);
|
|||
|
}
|
|||
|
|
|||
|
else {
|
|||
|
UnityEngine.Debug.LogError("CompositeNode." + this + " cannot convert parameter " + stringParameter[i]);
|
|||
|
//throw new Exception("CompositeNode." + this + " cannot convert parameter " + stringParameter[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Has(CompositeParameter.Race)) {
|
|||
|
compositeType = CompositeParameter.Race;
|
|||
|
}
|
|||
|
else if (Has(CompositeParameter.Marathon)) {
|
|||
|
compositeType = CompositeParameter.Marathon;
|
|||
|
}
|
|||
|
else if (Has(CompositeParameter.Sequence)) {
|
|||
|
compositeType = CompositeParameter.Sequence;
|
|||
|
}
|
|||
|
else if (Has(CompositeParameter.Selector)) {
|
|||
|
compositeType = CompositeParameter.Selector;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// reset the whole behaviour tree structure
|
|||
|
/// </summary>
|
|||
|
public override void Destroy() {
|
|||
|
base.Destroy();
|
|||
|
parameters = null;
|
|||
|
//activeNodeId = 0;
|
|||
|
}
|
|||
|
|
|||
|
public override IEnumerable<NodeResult> Tick(NodeRuntimeData parentNodeRuntimeData, int recursions) {
|
|||
|
|
|||
|
if (debugInternalActive) {
|
|||
|
Debug.Log(NodeLogger($"Tick", $""));
|
|||
|
}
|
|||
|
|
|||
|
// only work with 1 child && failsave in case we have an infinite loop
|
|||
|
if (recursions < recursionLimit) {
|
|||
|
using (NodeRuntimeData myNodeRuntimeData = new NodeRuntimeData(this, parentNodeRuntimeData)) {
|
|||
|
myNodeRuntimeData.taskHasChanges = false;
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Tick.OnStart", $"{myNodeRuntimeData} nodeResult {myNodeRuntimeData.nodeResult} nodeState {myNodeRuntimeData.nodeState}"));
|
|||
|
|
|||
|
switch (compositeType) {
|
|||
|
/// <summary>
|
|||
|
/// Selector (fallback) node
|
|||
|
///
|
|||
|
/// Runs all Children in sequence:
|
|||
|
/// - any child running -> continue in loop
|
|||
|
/// - any child failed -> continue in loop
|
|||
|
/// - any child success -> abort loop with succeeded result
|
|||
|
/// - finally -> exit failed (there is no looping)
|
|||
|
///
|
|||
|
/// In pseudocode, the algorithm for a fallback composition is:
|
|||
|
/// 1 for i from 1 to n do
|
|||
|
/// 2 childstatus ← Tick(child(i))
|
|||
|
/// 3 if childstatus = success
|
|||
|
/// 4 return success
|
|||
|
/// 5 end
|
|||
|
/// 6 return failure
|
|||
|
/// </summary>
|
|||
|
case CompositeParameter.Selector:
|
|||
|
//int selectorIndex = 0;
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Continue;
|
|||
|
for (int selectorIndex = 0; selectorIndex < children.Count; selectorIndex++) {
|
|||
|
myNodeRuntimeData.currentIndex = selectorIndex;
|
|||
|
//while (myNodeRuntimeData.nodeResult == NodeResult.Continue) {
|
|||
|
|
|||
|
myNodeRuntimeData.tickExecuteEnumerator = children[selectorIndex].Tick(myNodeRuntimeData, recursions + 1).GetEnumerator();
|
|||
|
|
|||
|
// must be run before MoveNext
|
|||
|
myNodeRuntimeData.taskHasChanges = base.PreTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
while ((myNodeRuntimeData.tickExecuteEnumerator != null) && myNodeRuntimeData.tickExecuteEnumerator.MoveNext() && (myNodeRuntimeData.nodeResult == NodeResult.Continue)){
|
|||
|
//if (debugInternalActive) Debug.Log(NodeLogger($"Tick.Selector", $"{selectorIndex} exec {children[selectorIndex]} childResult {myNodeRuntimeData.tickEnumerator.Current}"));
|
|||
|
|
|||
|
// selector succeedes when any child succeedes
|
|||
|
if (myNodeRuntimeData.tickExecuteEnumerator.Current == NodeResult.Succeeded) {
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Succeeded;
|
|||
|
}
|
|||
|
// if last selector fails all children have failed
|
|||
|
if ((myNodeRuntimeData.tickExecuteEnumerator.Current == NodeResult.Failed) && (selectorIndex == children.Count - 1)) {
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Failed;
|
|||
|
}
|
|||
|
|
|||
|
myNodeRuntimeData.taskHasChanges |= base.PostTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Tick.Selector", $"childResult {myNodeRuntimeData.tickExecuteEnumerator.Current} nodeState {myNodeRuntimeData.nodeState} nodeResult {myNodeRuntimeData.nodeResult}"));
|
|||
|
yield return myNodeRuntimeData.nodeResult;
|
|||
|
|
|||
|
if (myNodeRuntimeData.taskHasChanges && taskController) {
|
|||
|
taskController.SetUiUpdate();
|
|||
|
}
|
|||
|
|
|||
|
if (myNodeRuntimeData.nodeResult != NodeResult.Continue) {
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
// this should not be run again if it isnt in runnning mode anymore
|
|||
|
if (myNodeRuntimeData.nodeState == NodeState.Running) {
|
|||
|
myNodeRuntimeData.taskHasChanges = PreTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (myNodeRuntimeData.nodeState != NodeState.Running) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Failed;
|
|||
|
yield return myNodeRuntimeData.nodeResult;
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Tick.Selector", $"finished nodeState {myNodeRuntimeData.nodeState} nodeResult {myNodeRuntimeData.nodeResult}"));
|
|||
|
yield break;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Sequence node
|
|||
|
///
|
|||
|
/// Starts all Children in sequence:
|
|||
|
/// - any child running -> continue running
|
|||
|
/// - any child success -> continue running
|
|||
|
/// - any child failed -> abort loop with failed result
|
|||
|
/// - finally -> return success result
|
|||
|
///
|
|||
|
/// In pseudocode, the algorithm for a sequence composition is:
|
|||
|
/// 1 for i from 1 to n do
|
|||
|
/// 2 childstatus ← Tick(child(i))
|
|||
|
/// 3 if childstatus = failure
|
|||
|
/// 4 return failure
|
|||
|
/// 5 end
|
|||
|
/// 6 return success
|
|||
|
/// </summary>
|
|||
|
case CompositeParameter.Sequence:
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Continue;
|
|||
|
for (int sequenceIndex = 0; sequenceIndex < children.Count; sequenceIndex++) {
|
|||
|
myNodeRuntimeData.currentIndex = sequenceIndex;
|
|||
|
|
|||
|
myNodeRuntimeData.tickExecuteEnumerator = children[sequenceIndex].Tick(myNodeRuntimeData, recursions + 1).GetEnumerator();
|
|||
|
// must be run before MoveNext
|
|||
|
|
|||
|
myNodeRuntimeData.taskHasChanges = base.PreTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
while ((myNodeRuntimeData.tickExecuteEnumerator != null) && myNodeRuntimeData.tickExecuteEnumerator.MoveNext() && (myNodeRuntimeData.nodeResult == NodeResult.Continue)) {
|
|||
|
|
|||
|
// if any child fails, return failure
|
|||
|
if (myNodeRuntimeData.tickExecuteEnumerator.Current == NodeResult.Failed) {
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Failed;
|
|||
|
}
|
|||
|
// if the last child succeedes, return succeeded
|
|||
|
if ((myNodeRuntimeData.tickExecuteEnumerator.Current == NodeResult.Succeeded) && (sequenceIndex == children.Count - 1)) {
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Succeeded;
|
|||
|
}
|
|||
|
|
|||
|
myNodeRuntimeData.taskHasChanges |= base.PostTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Tick.Sequence", $"exec {sequenceIndex} childResult {myNodeRuntimeData.tickExecuteEnumerator.Current} nodeResult {myNodeRuntimeData.nodeResult}"));
|
|||
|
yield return myNodeRuntimeData.nodeResult;
|
|||
|
|
|||
|
if (myNodeRuntimeData.taskHasChanges && taskController) {
|
|||
|
taskController.SetUiUpdate();
|
|||
|
}
|
|||
|
|
|||
|
if (myNodeRuntimeData.nodeResult != NodeResult.Continue) {
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
// this should not be run again if it isnt in runnning mode anymore
|
|||
|
if (myNodeRuntimeData.nodeState == NodeState.Running) {
|
|||
|
myNodeRuntimeData.taskHasChanges = PreTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (myNodeRuntimeData.nodeState != NodeState.Running) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Succeeded;
|
|||
|
yield return myNodeRuntimeData.nodeResult;
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Tick.Selector", $"finished nodeState {myNodeRuntimeData.nodeState} nodeResult {myNodeRuntimeData.nodeResult}"));
|
|||
|
yield break;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Marathon Node
|
|||
|
///
|
|||
|
/// Starts all Children in parallel:
|
|||
|
/// - any child running -> continue in loop
|
|||
|
/// - any child success -> continue in loop
|
|||
|
/// - any child failed -> continue in loop
|
|||
|
/// - return after 1 iteration
|
|||
|
/// - succeed when all are succeeded or failed
|
|||
|
/// </summary>
|
|||
|
case CompositeParameter.Marathon:
|
|||
|
myNodeRuntimeData.childResults = new NodeResult[children.Count];
|
|||
|
myNodeRuntimeData.subTickExecuteEnumerators = new IEnumerator<NodeResult>[children.Count];
|
|||
|
for (int i = 0; i < children.Count; i++) {
|
|||
|
myNodeRuntimeData.childResults[i] = NodeResult.Continue;
|
|||
|
myNodeRuntimeData.subTickExecuteEnumerators[i] = children[i].Tick(myNodeRuntimeData, recursions + 1).GetEnumerator();
|
|||
|
}
|
|||
|
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Continue;
|
|||
|
myNodeRuntimeData.taskHasChanges = base.PreTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
while (myNodeRuntimeData.nodeResult == NodeResult.Continue) {
|
|||
|
// run one interation of all childs
|
|||
|
for (int i = 0; i < children.Count; i++) {
|
|||
|
// if in continue, run
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"HandleMarathonExecute.BeforeRunning", $"running {i} {myNodeRuntimeData.childResults[i]} {children[i].GetType().ToString()}"));
|
|||
|
if (myNodeRuntimeData.childResults[i] == NodeResult.Continue) {
|
|||
|
myNodeRuntimeData.subTickExecuteEnumerators[i].MoveNext();
|
|||
|
myNodeRuntimeData.childResults[i] = (NodeResult)myNodeRuntimeData.subTickExecuteEnumerators[i].Current;
|
|||
|
|
|||
|
if (myNodeRuntimeData.childResults[i] == NodeResult.Undefined) {
|
|||
|
//throw new System.ArgumentException("Parameter should not be undefined", $"childResults[{i}] -> {childResults[i]} from {children[i].ToString()}");
|
|||
|
Debug.LogError(NodeLogger($"HandleMarathonExecute", $"Parameter should not be undefined childResults[{i}] -> NodeResult.Undefined")); // from {children[i].ToString()}");
|
|||
|
}
|
|||
|
if (myNodeRuntimeData.childResults[i] == NodeResult.Error) {
|
|||
|
Debug.LogError(NodeLogger($"HandleMarathonExecute", $"error in child {i} : {children[i]}"));
|
|||
|
}
|
|||
|
}
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"HandleMarathonExecute.AfterRunning", $"running {i} {myNodeRuntimeData.childResults[i]}"));
|
|||
|
}
|
|||
|
|
|||
|
#if false // nice but slow
|
|||
|
// evaluate results
|
|||
|
bool allSucceededOrFailed = myNodeRuntimeData.childResults.All(result => ((result == NodeResult.Succeeded) || (result == NodeResult.Failed)));
|
|||
|
bool anyError = myNodeRuntimeData.childResults.Any(result => result == NodeResult.Error);
|
|||
|
|
|||
|
if (anyError) {
|
|||
|
Debug.LogError(NodeLogger($"HandleMarathonExecute", "HandleMarathonExecute: some node returned error"));
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Error;
|
|||
|
}
|
|||
|
#else
|
|||
|
bool allSucceededOrFailed = true;
|
|||
|
foreach (NodeResult childResult in myNodeRuntimeData.childResults) {
|
|||
|
switch (childResult) {
|
|||
|
case NodeResult.Succeeded:
|
|||
|
case NodeResult.Failed:
|
|||
|
break;
|
|||
|
case NodeResult.Undefined:
|
|||
|
case NodeResult.Continue:
|
|||
|
allSucceededOrFailed = false;
|
|||
|
break;
|
|||
|
case NodeResult.Error:
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Error;
|
|||
|
break;
|
|||
|
}
|
|||
|
//if (childResult == NodeResult.Error) {
|
|||
|
// //anyError = true;
|
|||
|
// Debug.LogError(NodeLogger($"HandleMarathonExecute", "HandleMarathonExecute: some node returned error"));
|
|||
|
// myNodeRuntimeData.nodeResult = NodeResult.Error;
|
|||
|
// break;
|
|||
|
//}
|
|||
|
//if ( ! ((childResult == NodeResult.Succeeded) || (childResult == NodeResult.Failed)) ) {
|
|||
|
// allSucceededOrFailed = false;
|
|||
|
// //myNodeRuntimeData.nodeResult = NodeResult.Succeeded;
|
|||
|
// break;
|
|||
|
//}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// generate result
|
|||
|
if (allSucceededOrFailed) {
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Succeeded;
|
|||
|
}
|
|||
|
myNodeRuntimeData.taskHasChanges |= base.PostTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
|
|||
|
if (myNodeRuntimeData.taskHasChanges && taskController) {
|
|||
|
taskController.SetUiUpdate();
|
|||
|
}
|
|||
|
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"HandleMarathonExecute.Final", $"return {myNodeRuntimeData.nodeResult}"));
|
|||
|
yield return myNodeRuntimeData.nodeResult;
|
|||
|
|
|||
|
// this should not be run again if it isnt in runnning mode anymore
|
|||
|
if (myNodeRuntimeData.nodeState == NodeState.Running) {
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Tick.Cleanup", $"changed to {myNodeRuntimeData.nodeResult}"));
|
|||
|
myNodeRuntimeData.taskHasChanges = PreTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
}
|
|||
|
else {
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Tick.Cleanup", $"Testing, should be executed once after success of enumerator"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
yield break;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Race Node
|
|||
|
///
|
|||
|
/// Starts all Children in parallel:
|
|||
|
/// - any child running -> continue in loop
|
|||
|
/// - any child success -> return success, abort all remaining running
|
|||
|
/// - any child failed -> continue in loop
|
|||
|
/// - return after 1 iteration
|
|||
|
/// - if all fail, fail.
|
|||
|
/// </summary>
|
|||
|
case CompositeParameter.Race:
|
|||
|
myNodeRuntimeData.childResults = new NodeResult[children.Count];
|
|||
|
myNodeRuntimeData.subTickExecuteEnumerators = new IEnumerator<NodeResult>[children.Count];
|
|||
|
for (int i = 0; i < children.Count; i++) {
|
|||
|
myNodeRuntimeData.childResults[i] = NodeResult.Continue;
|
|||
|
myNodeRuntimeData.subTickExecuteEnumerators[i] = children[i].Tick(myNodeRuntimeData, recursions + 1).GetEnumerator();
|
|||
|
}
|
|||
|
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Continue;
|
|||
|
myNodeRuntimeData.taskHasChanges = base.PreTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
while (myNodeRuntimeData.nodeResult == NodeResult.Continue) {
|
|||
|
// run one interation of all childs
|
|||
|
for (int i = 0; i < children.Count; i++) {
|
|||
|
if (myNodeRuntimeData.childResults[i] == NodeResult.Continue) {
|
|||
|
myNodeRuntimeData.subTickExecuteEnumerators[i].MoveNext();
|
|||
|
myNodeRuntimeData.childResults[i] = myNodeRuntimeData.subTickExecuteEnumerators[i].Current;
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Race", $"node resulted in {myNodeRuntimeData.childResults[i]}"));
|
|||
|
}
|
|||
|
|
|||
|
if (myNodeRuntimeData.childResults[i] == NodeResult.Error) {
|
|||
|
if (debugInternalActive) Debug.LogError(NodeLogger($"Race", $"{children[i]} has error"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if false
|
|||
|
// nice but slow?
|
|||
|
bool anySucceeded = myNodeRuntimeData.childResults.Any(result => result == NodeResult.Succeeded);
|
|||
|
bool allFailed = myNodeRuntimeData.childResults.All(result => result == NodeResult.Failed);
|
|||
|
bool anyError = myNodeRuntimeData.childResults.Any(result => result == NodeResult.Error);
|
|||
|
|
|||
|
if (anyError) {
|
|||
|
Debug.LogError(NodeLogger($"Race", "some node returned error"));
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Error;
|
|||
|
}
|
|||
|
if (anySucceeded) {
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Succeeded;
|
|||
|
}
|
|||
|
#else
|
|||
|
bool allFailed = true;
|
|||
|
foreach (NodeResult childResult in myNodeRuntimeData.childResults) {
|
|||
|
switch (childResult) {
|
|||
|
case NodeResult.Failed:
|
|||
|
break;
|
|||
|
case NodeResult.Succeeded:
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Succeeded;
|
|||
|
goto case NodeResult.Undefined;
|
|||
|
case NodeResult.Undefined:
|
|||
|
case NodeResult.Continue:
|
|||
|
allFailed = false;
|
|||
|
break;
|
|||
|
case NodeResult.Error:
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Error;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//if (childResult != NodeResult.Failed) {
|
|||
|
// allFailed = false;
|
|||
|
//}
|
|||
|
//if (childResult == NodeResult.Error) {
|
|||
|
// //anyError = true;
|
|||
|
// Debug.LogError(NodeLogger($"Race", "some node returned error"));
|
|||
|
// myNodeRuntimeData.nodeResult = NodeResult.Error;
|
|||
|
// break;
|
|||
|
//}
|
|||
|
//if (childResult == NodeResult.Succeeded) {
|
|||
|
// //anySucceeded = true;
|
|||
|
// myNodeRuntimeData.nodeResult = NodeResult.Succeeded;
|
|||
|
// break;
|
|||
|
//}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if (allFailed) {
|
|||
|
myNodeRuntimeData.nodeResult = NodeResult.Failed;
|
|||
|
}
|
|||
|
myNodeRuntimeData.taskHasChanges |= base.PostTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
|
|||
|
if (myNodeRuntimeData.taskHasChanges && taskController) {
|
|||
|
taskController.SetUiUpdate();
|
|||
|
}
|
|||
|
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Race", $"HandleRaceExecute: result {myNodeRuntimeData.nodeResult}"));
|
|||
|
yield return myNodeRuntimeData.nodeResult;
|
|||
|
|
|||
|
// this should not be run again if it isnt in runnning mode anymore
|
|||
|
if (myNodeRuntimeData.nodeState == NodeState.Running) {
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Race", $"changed to {myNodeRuntimeData.nodeResult}"));
|
|||
|
myNodeRuntimeData.taskHasChanges = PreTick(NodeExecute.Run, myNodeRuntimeData);
|
|||
|
}
|
|||
|
else {
|
|||
|
if (debugInternalActive) Debug.Log(NodeLogger($"Race", $"Testing, should be executed once after success of enumerator"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
yield break;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
default:
|
|||
|
Debug.LogError(NodeLogger($"Tick", "no behaviour defined for CompositeNode, use at least Sequence or Parallel"));
|
|||
|
yield break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
Debug.LogError(NodeLogger("RunTreeNode.Tick", $"recursions {recursions}"));
|
|||
|
taskController.SetUiUpdate();
|
|||
|
yield return NodeResult.Error;
|
|||
|
}
|
|||
|
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public override Node Duplicate () {
|
|||
|
CompositeNode tn = ScriptableObject.CreateInstance<CompositeNode>();
|
|||
|
base.BaseDuplicate (tn);
|
|||
|
|
|||
|
// CompositeNode tn = base.Duplicate() as CompositeNode;
|
|||
|
tn.parameters = parameters;
|
|||
|
tn.compositeType = compositeType;
|
|||
|
return tn;
|
|||
|
}
|
|||
|
|
|||
|
public string ToString (NodeRuntimeData myNodeRuntimeData) {
|
|||
|
string customData = "";
|
|||
|
|
|||
|
switch (compositeType) {
|
|||
|
case CompositeParameter.Race:
|
|||
|
case CompositeParameter.Marathon:
|
|||
|
customData += "CResults: ";
|
|||
|
if (myNodeRuntimeData.childResults != null) {
|
|||
|
for (int i = 0; i < children.Count; i++) {
|
|||
|
if (i < myNodeRuntimeData.childResults.Length) {
|
|||
|
customData += myNodeRuntimeData.childResults[i] + " ";
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
case CompositeParameter.Sequence:
|
|||
|
//customData += "Index: "+sequenceIndex;
|
|||
|
break;
|
|||
|
case CompositeParameter.Selector:
|
|||
|
//customData += "Index: "+selectorIndex;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return base.ToString() + " " + customData;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|