diff --git a/Source/Engine/AI/BehaviorKnowledge.cpp b/Source/Engine/AI/BehaviorKnowledge.cpp index fc2504688..1ad5319c4 100644 --- a/Source/Engine/AI/BehaviorKnowledge.cpp +++ b/Source/Engine/AI/BehaviorKnowledge.cpp @@ -68,7 +68,7 @@ bool AccessVariant(Variant& instance, const StringAnsiView& member, Variant& val if (set) mField->SetValue(instanceObject, MUtils::VariantToManagedArgPtr(value, mField->GetType(), failed)); else - value = MUtils::UnboxVariant(mField->GetValueBoxed(instanceObject)); + value = MUtils::UnboxVariant(mField->GetValueBoxed(instanceObject)); return true; } else if (const auto mProperty = mClass->GetProperty(member.Get())) @@ -76,7 +76,7 @@ bool AccessVariant(Variant& instance, const StringAnsiView& member, Variant& val if (set) mProperty->SetValue(instanceObject, MUtils::BoxVariant(value), nullptr); else - value = MUtils::UnboxVariant(mProperty->GetValue(instanceObject, nullptr)); + value = MUtils::UnboxVariant(mProperty->GetValue(instanceObject, nullptr)); return true; } } @@ -173,3 +173,24 @@ bool BehaviorKnowledge::Set(const StringAnsiView& path, const Variant& value) { return AccessBehaviorKnowledge(this, path, const_cast(value), true); } + +bool BehaviorKnowledge::CompareValues(float a, float b, BehaviorValueComparison comparison) +{ + switch (comparison) + { + case BehaviorValueComparison::Equal: + return Math::NearEqual(a, b); + case BehaviorValueComparison::NotEqual: + return Math::NotNearEqual(a, b); + case BehaviorValueComparison::Less: + return a < b; + case BehaviorValueComparison::LessEqual: + return a <= b; + case BehaviorValueComparison::Greater: + return a > b; + case BehaviorValueComparison::GreaterEqual: + return a >= b; + default: + return false; + } +} diff --git a/Source/Engine/AI/BehaviorKnowledge.h b/Source/Engine/AI/BehaviorKnowledge.h index 252f85764..c4b515d43 100644 --- a/Source/Engine/AI/BehaviorKnowledge.h +++ b/Source/Engine/AI/BehaviorKnowledge.h @@ -8,6 +8,7 @@ class Behavior; class BehaviorTree; +enum class BehaviorValueComparison; /// /// Behavior logic component knowledge data container. Contains blackboard values, sensors data and goals storage for Behavior Tree execution. @@ -69,4 +70,13 @@ API_CLASS() class FLAXENGINE_API BehaviorKnowledge : public ScriptingObject /// Value to set. /// True if set value, otherwise false. API_FUNCTION() bool Set(const StringAnsiView& path, const Variant& value); + + /// + /// Compares two values and returns the comparision result. + /// + /// The left operand. + /// The right operand. + /// The comparison function. + /// True if comparision passed, otherwise false. + API_FUNCTION() static bool CompareValues(float a, float b, BehaviorValueComparison comparison); }; diff --git a/Source/Engine/AI/BehaviorTreeNodes.cpp b/Source/Engine/AI/BehaviorTreeNodes.cpp index 05b631530..1706a154d 100644 --- a/Source/Engine/AI/BehaviorTreeNodes.cpp +++ b/Source/Engine/AI/BehaviorTreeNodes.cpp @@ -435,3 +435,13 @@ void BehaviorTreeCooldownDecorator::PostUpdate(const BehaviorUpdateContext& cont state->EndTime += context.Time; } } + +bool BehaviorTreeKnowledgeConditionalDecorator::CanUpdate(const BehaviorUpdateContext& context) +{ + return BehaviorKnowledge::CompareValues((float)ValueA.Get(context.Knowledge), ValueB, Comparison); +} + +bool BehaviorTreeKnowledgeValuesConditionalDecorator::CanUpdate(const BehaviorUpdateContext& context) +{ + return BehaviorKnowledge::CompareValues((float)ValueA.Get(context.Knowledge), (float)ValueB.Get(context.Knowledge), Comparison); +} diff --git a/Source/Engine/AI/BehaviorTreeNodes.h b/Source/Engine/AI/BehaviorTreeNodes.h index 10eca71ea..6d9716988 100644 --- a/Source/Engine/AI/BehaviorTreeNodes.h +++ b/Source/Engine/AI/BehaviorTreeNodes.h @@ -292,3 +292,53 @@ public: float EndTime; }; }; + +/// +/// Checks certain knowledge value to conditionally enter the node. +/// +API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeKnowledgeConditionalDecorator : public BehaviorTreeDecorator +{ + DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(BehaviorTreeKnowledgeConditionalDecorator, BehaviorTreeDecorator); + API_AUTO_SERIALIZATION(); + + // The first value from behavior's knowledge (blackboard, goal or sensor) to use for comparision. + API_FIELD(Attributes="EditorOrder(0)") + BehaviorKnowledgeSelectorAny ValueA; + + // The second value to use for comparision. + API_FIELD(Attributes="EditorOrder(10)") + float ValueB = 0.0f; + + // Values comparision mode. + API_FIELD(Attributes="EditorOrder(20)") + BehaviorValueComparison Comparison = BehaviorValueComparison::Equal; + +public: + // [BehaviorTreeNode] + bool CanUpdate(const BehaviorUpdateContext& context) override; +}; + +/// +/// Checks certain knowledge value to conditionally enter the node. +/// +API_CLASS(Sealed) class FLAXENGINE_API BehaviorTreeKnowledgeValuesConditionalDecorator : public BehaviorTreeDecorator +{ + DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(BehaviorTreeKnowledgeValuesConditionalDecorator, BehaviorTreeDecorator); + API_AUTO_SERIALIZATION(); + + // The first value from behavior's knowledge (blackboard, goal or sensor) to use for comparision. + API_FIELD(Attributes="EditorOrder(0)") + BehaviorKnowledgeSelectorAny ValueA; + + // The second value from behavior's knowledge (blackboard, goal or sensor) to use for comparision. + API_FIELD(Attributes="EditorOrder(10)") + BehaviorKnowledgeSelectorAny ValueB; + + // Values comparision mode. + API_FIELD(Attributes="EditorOrder(20)") + BehaviorValueComparison Comparison = BehaviorValueComparison::Equal; + +public: + // [BehaviorTreeNode] + bool CanUpdate(const BehaviorUpdateContext& context) override; +}; diff --git a/Source/Engine/AI/BehaviorTypes.h b/Source/Engine/AI/BehaviorTypes.h index 80133f53a..38aa65f98 100644 --- a/Source/Engine/AI/BehaviorTypes.h +++ b/Source/Engine/AI/BehaviorTypes.h @@ -59,3 +59,22 @@ API_ENUM() enum class BehaviorUpdateResult // Action failed. Failed, }; + +/// +/// Comparison function modes for behavior knowledge values. +/// +API_ENUM() enum class BehaviorValueComparison +{ + // If A is equal to B, the comparison passes. + Equal, + // If A is not equal to B, the comparison passes. + NotEqual, + // If A is less than the B, the comparison passes. + Less, + // If A is less than or equal to the B, the comparison passes. + LessEqual, + // If A is greater than the B, the comparison passes. + Greater, + // If A is greater than or equal to the B, the comparison passes. + GreaterEqual, +}; diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index 1cc401e4b..846a98992 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -1506,6 +1506,7 @@ Variant::operator float() const case VariantType::Float3: return AsFloat3().X; case VariantType::Float4: + case VariantType::Color: return AsFloat4().X; case VariantType::Double2: return (float)AsDouble2().X; @@ -1519,6 +1520,16 @@ Variant::operator float() const return (float)AsInt3().X; case VariantType::Int4: return (float)AsInt4().X; + case VariantType::Pointer: + return AsPointer ? 1.0f : 0.0f; + case VariantType::Object: + return AsObject ? 1.0f : 0.0f; + case VariantType::Asset: + return AsAsset ? 1.0f : 0.0f; + case VariantType::Blob: + return AsBlob.Length > 0 ? 1.0f : 0.0f; + case VariantType::ManagedObject: + return MANAGED_GC_HANDLE ? 1.0f : 0.0f; default: return 0; }