A context steering module fills the interest and the danger map.
This is an example of a module that fills the interest map. It takes the main direction and apply a dot product between the direction and the rays.
(Remember to add “AtomsUnreal” and “AtomsRealtime” to the dependency of you plugin/project)
#pragma once #include "CoreMinimal.h" #include "AtomsUnreal/Public/ContextSteering/AtomsContextSteeringBehaviour.h" #include "AtomsContextSteeringMyDirectionBehaviour.generated.h" /* Take the input agent direction and do a dot with the samples in the angle range, starting form the forward sample 0.*/ UCLASS(DefaultToInstanced, editinlinenew, DisplayName = "My Direction") class UAtomsContextSteeringMyDirectionBehaviour : public UAtomsContextSteeringBehaviour { GENERATED_BODY() public: /** Angle used to reduce the interest values, decrease the interest value from 1 to 0 insdie hte angle range*/ UPROPERTY(EditAnywhere, Category = "Behaviour") float Angle; /** Teh angle coudl be controlled by a metadata if the agent has a double metadat with this name*/ UPROPERTY(EditAnywhere, Category = "Behaviour") FString Metadata; UAtomsContextSteeringMyDirectionBehaviour(); virtual void Initialize(class UContextSteering_BehaviourComponent* ParentComponent) override; virtual void Evaluate(Atoms::AgentGroup* AgentGroup, Atoms::Agent* Agent, const float DeltaTime) override; private: std::string m_metadataName; };
#include "AtomsContextSteeringMyDirectionBehaviour.h" #include <AtomsCore/Metadata/DoubleMetadata.h> UAtomsContextSteeringMyDirectionBehaviour::UAtomsContextSteeringMyDirectionBehaviour() : Angle(180.0f) { } void UAtomsContextSteeringMyDirectionBehaviour::Initialize(class UContextSteering_BehaviourComponent* ParentComponent) { if (!Metadata.IsEmpty()) m_metadataName = TCHAR_TO_UTF8(*Metadata); else m_metadataName.clear(); } void UAtomsContextSteeringMyDirectionBehaviour::Evaluate(Atoms::AgentGroup* AgentGroup, Atoms::Agent* Agent, const float DeltaTime) { Atoms::ContextSteeringData& data = Agent->contextSteeringData(); auto& samplesMap = data.samples; auto& interestMap = data.interest; const AtomsMath::Vector3& Direction = Agent->direction()->get(); float AngleValue = Angle; if (!m_metadataName.empty()) { AtomsCore::DoubleMetadata* angleMeta = Agent->metadata().getTypedEntryRaw<AtomsCore::DoubleMetadata>(m_metadataName); AngleValue = angleMeta ? angleMeta->value() : AngleValue; } AtomsMath::Quaternion quat; if (AngleValue < 179.9) { float AngleRad = FMath::DegreesToRadians(AngleValue); for (size_t j = 0; j < interestMap.size(); ++j) { quat.setAxisAngle(data.up, samplesMap[j]); AtomsMath::Vector3 sample_direction = quat.rotateVector(data.direction); double CurrentAngle = FMath::Acos(FMath::Min(FMath::Max(-1.0, Direction.dot(sample_direction)), 1.0)); interestMap[j] = (FMath::Cos(FMath::Min(M_PI, CurrentAngle * M_PI / AngleRad)) * 0.5 + 0.5) * data.distance; } } else { for (size_t j = 0; j < interestMap.size(); ++j) { quat.setAxisAngle(data.up, samplesMap[j]); AtomsMath::Vector3 sample_direction = quat.rotateVector(data.direction); interestMap[j] = (Direction.dot(sample_direction) * 0.5 + 0.5) * data.distance; } } }
Instead, this module fills the danger map using the result of the line trace method.
#pragma once #include "CoreMinimal.h" #include "Engine/EngineTypes.h" #include "AtomsUnreal/Public/ContextSteering/AtomsContextSteeringBehaviour.h" #include "AtomsContextSteeringMyLineTraceAvoidanceBehaviour.generated.h" /* Filter the inreset/danger map using a gauss filter*/ UCLASS(DefaultToInstanced, editinlinenew, DisplayName = "My Line Trace Avoidance") class UAtomsContextSteeringMyLineTraceAvoidanceBehaviour : public UAtomsContextSteeringBehaviour { GENERATED_BODY() public: /** Collision channel used by the line trace */ UPROPERTY(EditAnywhere, Category = "Behaviour") TEnumAsByte<enum ECollisionChannel> CollisionChannel; /** Height offset */ UPROPERTY(EditAnywhere, Category = "Behaviour") float HeightOffset; UAtomsContextSteeringMyLineTraceAvoidanceBehaviour(); virtual void Initialize(class UContextSteering_BehaviourComponent* ParentComponent) override; virtual void Evaluate(Atoms::AgentGroup* AgentGroup, Atoms::Agent* Agent, const float DeltaTime) override; private: class UWorld* World; };
#include "AtomsContextSteeringMyLineTraceAvoidanceBehaviour.h" #include "Components/ContextSteeringBehaviourComponent.h" #include "AtomsConversions.h" UAtomsContextSteeringMyLineTraceAvoidanceBehaviour::UAtomsContextSteeringMyLineTraceAvoidanceBehaviour() : CollisionChannel(ECollisionChannel::ECC_Visibility), World(nullptr) { } void UAtomsContextSteeringMyLineTraceAvoidanceBehaviour::Initialize(class UContextSteering_BehaviourComponent* ParentComponent) { if (!ParentComponent) return; World = ParentComponent->GetWorld(); } void UAtomsContextSteeringMyLineTraceAvoidanceBehaviour::Evaluate(Atoms::AgentGroup* AgentGroup, Atoms::Agent* Agent, const float DeltaTime) { if (!World) return; Atoms::ContextSteeringData& data = Agent->contextSteeringData(); auto& dangerMap = data.danger; auto& sampleDirections = data.samples; const AtomsMath::Vector3& AgentPosition = data.position; FVector startPoint = AtomsConverter::FromVector3(AgentPosition + Agent->up()->get() * HeightOffset); AtomsMath::Quaternion quat; FHitResult result; for (size_t j = 0; j < dangerMap.size(); ++j) { quat.setAxisAngle(data.up, data.samples[j]); AtomsMath::Vector3 sample_direction = quat.rotateVector(data.direction); FVector endPoint = startPoint + AtomsConverter::FromVector3(sample_direction * data.distance); if (World->LineTraceSingleByChannel(result, startPoint, endPoint, CollisionChannel)) { dangerMap[j] = data.distance - FMath::Min(FMath::Max(0.0f, result.Distance - 30.0f), data.distance); } } }