Movement with Mass Framework

How to process movement with Mass Framework. Mass Framework is an ECS for managing crowds and traffic, available since Unreal Engine 5.0. Engine code excerpts below were taken from UE 5.3 and their signatures updated to the Unreal Engine 5.8 API - check the source of your engine version for implementation details.

Vladimír NeporAuthorVladimír Nepor
Published

Processing Movement with MassGameplay built-in resources

  • Movement Trait

    Built-in MassGameplay Trait located At UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovement

    void 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 of MassGameplay plugin works with the 4 following fragments:

    Located at UE5/Engine/Plugins/Runtime/MassGameplay/Source/MassMovement

    USTRUCT()
    struct MASSMOVEMENT_API FMassVelocityFragment : public FMassFragment
    {
    	GENERATED_BODY()
    
    	FVector Value = FVector::ZeroVector;
    };
  • Movement Processor

    Built-in MassGameplay Processor located at UE5/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.

    UMassApplyMovementProcessor::UMassApplyMovementProcessor()
    	: EntityQuery(*this)
    {
    	ExecutionFlags = (int32)EProcessorExecutionFlags::All;
    	ExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::Movement;
    	ExecutionOrder.ExecuteAfter.Add(UE::Mass::ProcessorGroupNames::Avoidance);
    }
    
    void UMassApplyMovementProcessor::ConfigureQueries(const TSharedRef<FMassEntityManager>& EntityManager)
    {
    	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(Context, [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 ZeroVector)
    			Velocity.Value += Force.Value * DeltaTime;
    
    			FVector CurrentLocation = CurrentTransform.GetLocation();
    			CurrentLocation += Velocity.Value * DeltaTime;
    			CurrentTransform.SetTranslation(CurrentLocation);
    		}
    	});
    }

Anything unclear?

Let us know!

Contact Us