Files
FlaxEngine/Source/Engine/AI/BehaviorTreeNodes.cpp
2023-08-21 00:07:25 +02:00

155 lines
4.6 KiB
C++

// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "BehaviorTreeNodes.h"
#include "Behavior.h"
#include "BehaviorKnowledge.h"
#include "Engine/Core/Random.h"
#include "Engine/Serialization/Serialization.h"
BehaviorUpdateResult BehaviorTreeNode::InvokeUpdate(const BehaviorUpdateContext& context)
{
ASSERT_LOW_LAYER(_executionIndex != -1);
if (context.Knowledge->RelevantNodes.Get(_executionIndex) == false)
{
// Node becomes relevant so initialize it's state
context.Knowledge->RelevantNodes.Set(_executionIndex, true);
InitState(context.Behavior, context.Memory);
}
// Node-specific update
const BehaviorUpdateResult result = Update(context);
// Check if node is not relevant anymore
if (result != BehaviorUpdateResult::Running)
{
context.Knowledge->RelevantNodes.Set(_executionIndex, false);
ReleaseState(context.Behavior, context.Memory);
}
return result;
}
void BehaviorTreeNode::Serialize(SerializeStream& stream, const void* otherObj)
{
SerializableScriptingObject::Serialize(stream, otherObj);
SERIALIZE_GET_OTHER_OBJ(BehaviorTreeNode);
SERIALIZE(Name);
}
void BehaviorTreeNode::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
SerializableScriptingObject::Deserialize(stream, modifier);
Name.Clear(); // Missing Name is assumes as unnamed node
DESERIALIZE(Name);
}
void BehaviorTreeCompoundNode::Init(BehaviorTree* tree)
{
for (BehaviorTreeNode* child : Children)
child->Init(tree);
}
BehaviorUpdateResult BehaviorTreeCompoundNode::Update(BehaviorUpdateContext context)
{
auto result = BehaviorUpdateResult::Success;
for (int32 i = 0; i < Children.Count() && result == BehaviorUpdateResult::Success; i++)
{
BehaviorTreeNode* child = Children[i];
result = child->InvokeUpdate(context);
}
return result;
}
int32 BehaviorTreeSequenceNode::GetStateSize() const
{
return sizeof(State);
}
void BehaviorTreeSequenceNode::InitState(Behavior* behavior, void* memory)
{
auto state = GetState<State>(memory);
new(state)State();
}
BehaviorUpdateResult BehaviorTreeSequenceNode::Update(BehaviorUpdateContext context)
{
auto state = GetState<State>(context.Memory);
if (state->CurrentChildIndex >= Children.Count())
return BehaviorUpdateResult::Success;
if (state->CurrentChildIndex == -1)
return BehaviorUpdateResult::Failed;
auto result = Children[state->CurrentChildIndex]->InvokeUpdate(context);
switch (result)
{
case BehaviorUpdateResult::Success:
state->CurrentChildIndex++; // Move to the next node
if (state->CurrentChildIndex < Children.Count())
result = BehaviorUpdateResult::Running; // Keep on running to the next child on the next update
break;
case BehaviorUpdateResult::Failed:
state->CurrentChildIndex = -1; // Mark whole sequence as failed
break;
}
return result;
}
int32 BehaviorTreeSelectorNode::GetStateSize() const
{
return sizeof(State);
}
void BehaviorTreeSelectorNode::InitState(Behavior* behavior, void* memory)
{
auto state = GetState<State>(memory);
new(state)State();
}
BehaviorUpdateResult BehaviorTreeSelectorNode::Update(BehaviorUpdateContext context)
{
auto state = GetState<State>(context.Memory);
if (state->CurrentChildIndex >= Children.Count())
return BehaviorUpdateResult::Failed;
auto result = Children[state->CurrentChildIndex]->InvokeUpdate(context);
switch (result)
{
case BehaviorUpdateResult::Success:
return BehaviorUpdateResult::Success;
case BehaviorUpdateResult::Failed:
state->CurrentChildIndex++; // Move to the next node
if (state->CurrentChildIndex < Children.Count())
result = BehaviorUpdateResult::Running; // Keep on running to the next child on the next update
break;
}
return result;
}
int32 BehaviorTreeDelayNode::GetStateSize() const
{
return sizeof(State);
}
void BehaviorTreeDelayNode::InitState(Behavior* behavior, void* memory)
{
auto state = GetState<State>(memory);
if (!WaitTimeSelector.TryGet(behavior->GetKnowledge(), state->TimeLeft))
state->TimeLeft = WaitTime;
state->TimeLeft = Random::RandRange(Math::Max(WaitTime - RandomDeviation, 0.0f), WaitTime + RandomDeviation);
}
BehaviorUpdateResult BehaviorTreeDelayNode::Update(BehaviorUpdateContext context)
{
auto state = GetState<State>(context.Memory);
state->TimeLeft -= context.DeltaTime;
return state->TimeLeft <= 0.0f ? BehaviorUpdateResult::Success : BehaviorUpdateResult::Running;
}