Processing Movement with MassGameplay built-in resources
-
Movement Trait
Built-in
MassGameplayTrait located AtUE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovementImage.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 TraitofMassGameplayplugin works with the 4 following fragments:FMassVelocityFragmentLocated at
UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovementUSTRUCT() struct MASSMOVEMENT_API FMassVelocityFragment : public FMassFragment { GENERATED_BODY() FVector Value = FVector::ZeroVector; };FMassForceFragmentLocated at
UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovementUSTRUCT() struct MASSMOVEMENT_API FMassForceFragment : public FMassFragment { GENERATED_BODY() FVector Value = FVector::ZeroVector; };FAgentRadiusFragmentLocated at
UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassCommonUSTRUCT() struct MASSCOMMON_API FAgentRadiusFragment : public FMassFragment { GENERATED_BODY() UPROPERTY(EditAnywhere, Category = "") float Radius = 40.f; };FTransformFragmentLocated at
UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassCommonUSTRUCT() 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
MassGameplayProcessor located atUE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovementNow, 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); } }); }