Movement with Mass Framework

Published on

How to process movement with Mass Framework. Mass Framework is a ECS for managing crowds and traffic in Unreal 5.0 and above.

Platforma

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.<mark>RequireFragment&lt;FAgentRadiusFragment&gt;</mark>();
    	BuildContext.<mark>RequireFragment&lt;FTransformFragment&gt;</mark>();
    
    	BuildContext.<mark>AddFragment&lt;FMassVelocityFragment&gt;</mark>();
    	BuildContext.<mark>AddFragment&lt;FMassForceFragment&gt;</mark>();
    
    	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()
    
    	<mark>FVector Value = FVector::ZeroVector;</mark>
    };
  • 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()
    {
    	EntityQuery.<mark>AddRequirement&lt;FMassVelocityFragment&gt;</mark>(EMassFragmentAccess::ReadWrite);
    	EntityQuery.<mark>AddRequirement&lt;FTransformFragment&gt;</mark>(EMassFragmentAccess::ReadWrite);
    	EntityQuery.<mark>AddRequirement&lt;FMassForceFragment&gt;</mark>(EMassFragmentAccess::ReadWrite);
    	EntityQuery.<mark>AddTagRequirement&lt;FMassOffLODTag&gt;</mark>(EMassFragmentPresence::None);
    	EntityQuery.<mark>AddConstSharedRequirement&lt;FMassMovementParameters&gt;</mark>(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&lt;FMassMovementParameters&gt;();
    
    		const TArrayView&lt;FTransformFragment&gt; LocationList = Context.GetMutableFragmentView&lt;FTransformFragment&gt;();
    		const TArrayView&lt;FMassForceFragment&gt; ForceList = Context.GetMutableFragmentView&lt;FMassForceFragment&gt;();
    		const TArrayView&lt;FMassVelocityFragment&gt; VelocityList = Context.GetMutableFragmentView&lt;FMassVelocityFragment&gt;();
    
    		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)
    			<mark>Velocity.Value += Force.Value * DeltaTime;</mark>
    
    			FVector CurrentLocation = CurrentTransform.GetLocation();
    			<mark>CurrentLocation += Velocity.Value * DeltaTime;</mark>
    			<mark>CurrentTransform.SetTranslation(CurrentLocation);</mark>
    		}
    	});
    }
Vrealmatic consulting

Anything unclear?

Let us know!

Contact Us