diff --git a/Source/Engine/AI/BehaviorTreeNodes.cpp b/Source/Engine/AI/BehaviorTreeNodes.cpp index 4dedc0606..df424a864 100644 --- a/Source/Engine/AI/BehaviorTreeNodes.cpp +++ b/Source/Engine/AI/BehaviorTreeNodes.cpp @@ -312,3 +312,52 @@ BehaviorUpdateResult BehaviorTreeForceFinishNode::Update(BehaviorUpdateContext c context.Behavior->StopLogic(Result); return Result; } + +void BehaviorTreeInvertDecorator::PostUpdate(BehaviorUpdateContext context, BehaviorUpdateResult& result) +{ + if (result == BehaviorUpdateResult::Success) + result = BehaviorUpdateResult::Failed; + else if (result == BehaviorUpdateResult::Failed) + result = BehaviorUpdateResult::Success; +} + +void BehaviorTreeForceSuccessDecorator::PostUpdate(BehaviorUpdateContext context, BehaviorUpdateResult& result) +{ + if (result != BehaviorUpdateResult::Running) + result = BehaviorUpdateResult::Success; +} + +void BehaviorTreeForceFailedDecorator::PostUpdate(BehaviorUpdateContext context, BehaviorUpdateResult& result) +{ + if (result != BehaviorUpdateResult::Running) + result = BehaviorUpdateResult::Failed; +} + +int32 BehaviorTreeLoopDecorator::GetStateSize() const +{ + return sizeof(State); +} + +void BehaviorTreeLoopDecorator::InitState(Behavior* behavior, void* memory) +{ + auto state = GetState(memory); + if (!LoopCountSelector.TryGet(behavior->GetKnowledge(), state->Loops)) + state->Loops = LoopCount; +} + +void BehaviorTreeLoopDecorator::PostUpdate(BehaviorUpdateContext context, BehaviorUpdateResult& result) +{ + // Continue looping only if node succeeds + if (result == BehaviorUpdateResult::Success) + { + auto state = GetState(context.Memory); + state->Loops--; + if (state->Loops > 0) + { + // Keep running in a loop but reset node's state (preserve decorators state including Loops counter) + result = BehaviorUpdateResult::Running; + _parent->BecomeIrrelevant(context, true); + _parent->BecomeRelevant(context); + } + } +} diff --git a/Source/Engine/AI/BehaviorTreeNodes.h b/Source/Engine/AI/BehaviorTreeNodes.h index ffe477542..71bae05f0 100644 --- a/Source/Engine/AI/BehaviorTreeNodes.h +++ b/Source/Engine/AI/BehaviorTreeNodes.h @@ -162,3 +162,67 @@ public: // [BehaviorTreeNode] BehaviorUpdateResult Update(BehaviorUpdateContext context) override; }; + +/// +/// Inverts node's result - fails if node succeeded or succeeds if node failed. +/// +API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeInvertDecorator : public BehaviorTreeDecorator +{ + DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(BehaviorTreeInvertDecorator, BehaviorTreeDecorator); + +public: + // [BehaviorTreeNode] + void PostUpdate(BehaviorUpdateContext context, BehaviorUpdateResult& result) override; +}; + +/// +/// Forces node to success - even if it failed. +/// +API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeForceSuccessDecorator : public BehaviorTreeDecorator +{ + DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(BehaviorTreeForceSuccessDecorator, BehaviorTreeDecorator); + +public: + // [BehaviorTreeNode] + void PostUpdate(BehaviorUpdateContext context, BehaviorUpdateResult& result) override; +}; + +/// +/// Forces node to fail - even if it succeeded. +/// +API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeForceFailedDecorator : public BehaviorTreeDecorator +{ + DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(BehaviorTreeForceFailedDecorator, BehaviorTreeDecorator); + +public: + // [BehaviorTreeNode] + void PostUpdate(BehaviorUpdateContext context, BehaviorUpdateResult& result) override; +}; + +/// +/// Loops node execution multiple times as long as it doesn't fail. Returns the last iteration result. +/// +API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeLoopDecorator : public BehaviorTreeDecorator +{ + DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(BehaviorTreeLoopDecorator, BehaviorTreeDecorator); + API_AUTO_SERIALIZATION(); + + // Amount of times to execute the node. Unused if LoopCountSelector is used. + API_FIELD(Attributes="EditorOrder(10), Limit(0)") + int32 LoopCount = 3; + + // Amount of times to execute the node from behavior's knowledge (blackboard, goal or sensor). If set, overrides LoopCount. + API_FIELD(Attributes="EditorOrder(20)") + BehaviorKnowledgeSelector LoopCountSelector; + +public: + // [BehaviorTreeNode] + int32 GetStateSize() const override; + void InitState(Behavior* behavior, void* memory) override; + void PostUpdate(BehaviorUpdateContext context, BehaviorUpdateResult& result) override; + + struct State + { + int32 Loops; + }; +};