LODCollector in Mass Framework

How does Crowd Visualization Trait works in Mass Framework? Mass Framework is a ECS for managing crowds and traffic in Unreal 5.0 and above.

Crowd Visualization Trait

Setup:

  • Params

    • RepresentationActorManagementClass: Class for adjusted controlling of spawned Actors, such as position adjustments
      // Copyright Epic Games, Inc. All Rights Reserved.
      #pragma once
      
      #include "MassCrowdRepresentationActorManagement.h"
      
      #include "SampleMassCrowdRepresentationActorManagement.generated.h"
      
      struct FMassEntityManager;
      class UMassCrowdSpawnerSubsystem;
      
      /**
      * Overridden actor management fro forsty specific
      */
      UCLASS(meta = (DisplayName = "Vrealmatic Crowd Visualization"))
      class VREALMATICSAMPLE_API USampleMassCrowdRepresentationActorManagement : public UMassCrowdRepresentationActorManagement
      {
      	GENERATED_BODY()
      
      	/**
      	* Method that will be bound to a delegate used post-spawn to notify and let the requester configure the actor
      	* @param SpawnRequestHandle the handle of the spawn request that was just spawned
      	* @param SpawnRequest of the actor that just spawned
      	* @param EntitySubsystem to use to retrieve the mass agent fragments
      	* @return The action to take on the spawn request, either keep it there or remove it.
      	*/
      	virtual EMassActorSpawnRequestAction OnPostActorSpawn(const FMassActorSpawnRequestHandle& SpawnRequestHandle, FConstStructView SpawnRequest, FMassEntityManager* EntitySubsystem) const override;
      
      	/**
      	 * Teleports the actor at the specified transform by preserving its velocity and without collision.
      	 * The destination will be adjusted to fit an existing capsule.
      	 * @param Transform is the new actor's transform
      	 * @param Actor is the actual actor to teleport
      	 * @param CommandBuffer to queue up anything that is thread sensitive
      	 */
      	 virtual void TeleportActor(const FTransform& Transform, AActor& Actor, FMassCommandBuffer& CommandBuffer) const override;
      };
      
      	
      // Copyright Epic Games, Inc. All Rights Reserved.
      
      #include "Mass/SampleMassCrowdRepresentationActorManagement.h"
      #include "IMassCrowdActor.h"
      #include "MassEntityManager.h"
      
      #include "MassCrowdSpawnerSubsystem.h"
      #include "Components/CapsuleComponent.h"
      #include "Character/OccupantCharacter.h"
      #include "Enum/MovementAction.h"
      
      EMassActorSpawnRequestAction USampleMassCrowdRepresentationActorManagement::OnPostActorSpawn(const FMassActorSpawnRequestHandle& SpawnRequestHandle, FConstStructView SpawnRequest, FMassEntityManager* EntitySubsystem) const
      {
      	check(EntitySubsystem);
      
      	const EMassActorSpawnRequestAction Result = Super::OnPostActorSpawn(SpawnRequestHandle, SpawnRequest, EntitySubsystem);
      	
      	const FMassActorSpawnRequest& MassActorSpawnRequest = SpawnRequest.Get<FMassActorSpawnRequest>();
      	checkf(MassActorSpawnRequest.SpawnedActor, TEXT("Expecting valid spawned actor"));
      
      	if (IMassCrowdActorInterface* MassCrowdActor = Cast<IMassCrowdActorInterface>(MassActorSpawnRequest.SpawnedActor))
      	{
      		MassCrowdActor->OnGetOrSpawn(EntitySubsystem, MassActorSpawnRequest.MassAgent);
      		//MassCrowdActor->SetMovementMode(EMovementMode::MOVE_Custom);
      	}
      
      	return Result;
      }
      
      void USampleMassCrowdRepresentationActorManagement::TeleportActor(const FTransform& Transform, AActor& Actor, FMassCommandBuffer& CommandBuffer) const
      {
      	FTransform RootTransform = Transform;
      
      	if (const UCapsuleComponent* CapsuleComp = Actor.FindComponentByClass<UCapsuleComponent>())
      	{
      		const FVector HalfHeight(0.0f, 0.0f, CapsuleComp->GetScaledCapsuleHalfHeight());
      		RootTransform.AddToTranslation(HalfHeight);
      
      		const FVector RootLocation = RootTransform.GetLocation();
      		const FVector SweepOffset(0.0f, 0.0f, 20.0f);
      		const FVector Start = RootLocation + SweepOffset;
      		const FVector End = RootLocation - SweepOffset;
      		FCollisionQueryParams Params;
      		Params.AddIgnoredActor(&Actor);
      		FHitResult OutHit;
      		if (Actor.GetWorld()->SweepSingleByChannel(OutHit, Start, End, Transform.GetRotation(), CapsuleComp->GetCollisionObjectType(), CapsuleComp->GetCollisionShape(), Params))
      		{
      			if (IMassCrowdActorInterface* MassCrowdActor = Cast(&Actor))
      			{
      				MassCrowdActor->SetAdditionalMeshOffset(RootTransform.GetLocation().Z - OutHit.Location.Z);
      			}
      
      			if (AOccupantCharacter* Character = Cast<AOccupantCharacter>(&Actor))
                  {
                      // Now you can access properties and methods of AOccupantCharacter
                      // ...
                  }
      			RootTransform.SetLocation(OutHit.Location);
      		}
      	}
      	// Skip Super(UMassCrowdRepresentationActorManagement) because we already done that work here and we needed to know the offset to send to the feet IK logic
      	UMassRepresentationActorManagement::TeleportActor(RootTransform, Actor, CommandBuffer);
      }
  • LODParams

    • LODMax Count

      • High: Maximum number of displayed entities with LODRepresentation::High