Processing Movement with MassGameplay
built-in resources
-
Movement Trait
Built-in
MassGameplay
Trait located AtUE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovement
Image.hUCLASS(meta = (DisplayName = "Movement")) class MASSMOVEMENT_API UMassMovementTrait : public UMassEntityTraitBase { GENERATED_BODY() protected: virtual void BuildTemplate(FMassEntityTemplateBuildContext& BuildContext, const UWorld& World) const override; UPROPERTY(Category="Movement", EditAnywhere) FMassMovementParameters Movement; };
.cppvoid UMassMovementTrait::BuildTemplate(FMassEntityTemplateBuildContext& BuildContext, const UWorld& World) const { FMassEntityManager& EntityManager = UE::Mass::Utils::GetEntityManagerChecked(World); BuildContext.RequireFragment<FAgentRadiusFragment>(); BuildContext.RequireFragment<FTransformFragment>(); BuildContext.AddFragment<FMassVelocityFragment>(); BuildContext.AddFragment<FMassForceFragment>(); const FConstSharedStruct MovementFragment = EntityManager.GetOrCreateConstSharedFragment(Movement); BuildContext.AddConstSharedFragment(MovementFragment); }
Check Built-in Movement processor to get knwoledge of processing the movement from the trait
-
Fragments for movement
As you can see, the built-in
Movement Trait
ofMassGameplay
plugin works with the 4 following fragments:FMassVelocityFragmentLocated at
UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovement
USTRUCT() struct MASSMOVEMENT_API FMassVelocityFragment : public FMassFragment { GENERATED_BODY() FVector Value = FVector::ZeroVector; };
FMassForceFragmentLocated at
UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovement
USTRUCT() struct MASSMOVEMENT_API FMassForceFragment : public FMassFragment { GENERATED_BODY() FVector Value = FVector::ZeroVector; };
FAgentRadiusFragmentLocated at
UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassCommon
USTRUCT() struct MASSCOMMON_API FAgentRadiusFragment : public FMassFragment { GENERATED_BODY() UPROPERTY(EditAnywhere, Category = "") float Radius = 40.f; };
FTransformFragmentLocated at
UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassCommon
USTRUCT() struct MASSCOMMON_API FTransformFragment : public FMassFragment { GENERATED_BODY() const FTransform& GetTransform() const { return Transform; } void SetTransform(const FTransform& InTransform) { Transform = InTransform; } FTransform& GetMutableTransform() { return Transform; } protected: UPROPERTY(Transient) FTransform Transform; };
-
Movement Processor
Built-in
MassGameplay
Processor located atUE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovement
Now, as you know the fragments and their values, you can check how they are used for automatical processing of movement. The point is, in a case of using the built-in
Movement Trait
(MassGameplay
), all you need for processing movements is to set (update) the traits values. You can do that e.g. from a custom Mass processor..hUCLASS() class MASSMOVEMENT_API UMassApplyMovementProcessor : public UMassProcessor { GENERATED_BODY() public: UMassApplyMovementProcessor(); protected: virtual void ConfigureQueries() override; virtual void Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) override; private: FMassEntityQuery EntityQuery; };
.cppUMassApplyMovementProcessor::UMassApplyMovementProcessor() : EntityQuery(*this) { ExecutionFlags = (int32)EProcessorExecutionFlags::All; ExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::Movement; ExecutionOrder.ExecuteAfter.Add(UE::Mass::ProcessorGroupNames::Avoidance); } void UMassApplyMovementProcessor::ConfigureQueries() { EntityQuery.AddRequirement<FMassVelocityFragment>(EMassFragmentAccess::ReadWrite); EntityQuery.AddRequirement<FTransformFragment>(EMassFragmentAccess::ReadWrite); EntityQuery.AddRequirement<FMassForceFragment>(EMassFragmentAccess::ReadWrite); EntityQuery.AddTagRequirement<FMassOffLODTag>(EMassFragmentPresence::None); EntityQuery.AddConstSharedRequirement<FMassMovementParameters>(EMassFragmentPresence::All); } void UMassApplyMovementProcessor::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { // Clamp max delta time to avoid force explosion on large time steps (i.e. during initialization). const float DeltaTime = FMath::Min(0.1f, Context.GetDeltaTimeSeconds()); QUICK_SCOPE_CYCLE_COUNTER(HighRes); EntityQuery.ForEachEntityChunk(EntityManager, Context, [this, DeltaTime](FMassExecutionContext& Context) { const int32 NumEntities = Context.GetNumEntities(); const FMassMovementParameters& MovementParams = Context.GetConstSharedFragment<FMassMovementParameters>(); const TArrayView<FTransformFragment> LocationList = Context.GetMutableFragmentView<FTransformFragment>(); const TArrayView<FMassForceFragment> ForceList = Context.GetMutableFragmentView<FMassForceFragment>(); const TArrayView<FMassVelocityFragment> VelocityList = Context.GetMutableFragmentView<FMassVelocityFragment>(); for (int32 EntityIndex = 0; EntityIndex < NumEntities; ++EntityIndex) { FMassForceFragment& Force = ForceList[EntityIndex]; FMassVelocityFragment& Velocity = VelocityList[EntityIndex]; FTransform& CurrentTransform = LocationList[EntityIndex].GetMutableTransform(); // Update velocity from steering forces. (Force default value is ZeroVevtor) Velocity.Value += Force.Value * DeltaTime; FVector CurrentLocation = CurrentTransform.GetLocation(); CurrentLocation += Velocity.Value * DeltaTime; CurrentTransform.SetTranslation(CurrentLocation); } }); }