Grid Placement System
Library Components
ObjectManager

ObjectManager

The ObjectManager is a specialized library component that handles the creation, management, and cleanup of preview objects, overlay visuals, and directional arrows during the placement process. It manages the visual representation of objects being placed and provides seamless actor lifecycle management.

Overview

ObjectManager coordinates all visual elements during placement mode, including preview actors (with materials and opacity), placement overlay indicators, outline materials, and directional arrow components. It ensures proper cleanup and handles the complex interactions between different visual elements.

Key Features

  • Preview Actor Management - Creates and manages translucent preview objects
  • Overlay System - Handles placement indicator overlays with dynamic sizing
  • Material Management - Manages dynamic materials for outline and overlay effects
  • Arrow Integration - Coordinates with DirectionalArrowComponent for visual feedback
  • Lifecycle Management - Proper creation and cleanup of all visual elements
  • Performance Optimized - Efficient actor management with minimal overhead

Core Methods

Initialization

Initialize

void Initialize(UWorld* World);

Initializes the ObjectManager with a world context.

Parameters:

  • World - The world context for spawning actors

Preview Actor Management

CreatePreviewActor

void CreatePreviewActor(TSubclassOf<AActor> ObjectClass, UMaterialInterface* SelectedOutlineMaterial);

Creates a preview actor for the specified object class with visual modifications.

Parameters:

  • ObjectClass - The actor class to create a preview for
  • SelectedOutlineMaterial - Material for outline effect

Process:

  1. Destroys any existing preview actor
  2. Spawns new actor with no collision
  3. Applies preview opacity (0.5) to base material
  4. Creates dynamic outline material with initial color
  5. Applies outline material as overlay

Usage:

ObjectManager->CreatePreviewActor(ChairClass, SelectedOutlineMaterial);

DestroyPreviewActor

void DestroyPreviewActor();

Safely destroys the current preview actor and clears material references.

GetPreviewActor

AActor* GetPreviewActor() const;

Returns the current preview actor (can be null).

Overlay Actor Management

CreateOverlayActor

void CreateOverlayActor(UMaterialInterface* OverlayMaterial);

Creates a placement overlay actor (visual indicator on surfaces).

Parameters:

  • OverlayMaterial - Material for the overlay plane

Process:

  1. Destroys any existing overlay actor
  2. Creates new actor with StaticMeshComponent
  3. Uses engine plane mesh as base geometry
  4. Creates dynamic material instance for color changes
  5. Disables collision and shadows

Usage:

if (bShowPlacementOverlay)
{
    ObjectManager->CreateOverlayActor(OverlayMaterial);
}

DestroyOverlayActor

void DestroyOverlayActor();

Destroys the overlay actor and hides any associated arrows.

GetOverlayActor

AActor* GetOverlayActor() const;

Returns the current overlay actor (can be null).

GetOverlayMeshComponent

UStaticMeshComponent* GetOverlayMeshComponent() const;

Returns the mesh component of the overlay actor.

GetOverlayDynamicMaterial

UMaterialInstanceDynamic* GetOverlayDynamicMaterial() const;

Returns the dynamic material instance used for overlay color changes.

Material Management

GetOutlineDynamicMaterial

UMaterialInstanceDynamic* GetOutlineDynamicMaterial() const;

Returns the dynamic material instance used for outline effects on preview objects.

Arrow Management

SetupCurrentObjectArrow

void SetupCurrentObjectArrow(AActor* InPreviewActor, AActor* InEditingTarget);

Configures arrow visualization for the current object.

Parameters:

  • InPreviewActor - The preview actor being placed
  • InEditingTarget - The object being edited (can be null for new placement)

Process:

  1. Checks preview actor first, then editing target for arrow component
  2. Gets arrow component via IPlaceableObjectInterface
  3. Shows arrow with current overlay material if available
  4. Hides arrow if no overlay material exists

UpdateArrowMaterial

void UpdateArrowMaterial();

Updates the arrow material to match the current overlay material.

GetCurrentArrowComponent

UDirectionalArrowComponent* GetCurrentArrowComponent() const;

Returns the currently active arrow component (can be null).

Settings

SetShowPlacementOverlay

void SetShowPlacementOverlay(bool bShow);

Controls whether placement overlays are created.

Parameters:

  • bShow - Whether to show placement overlays

Cleanup

CleanupActors

void CleanupActors();

Destroys both preview and overlay actors. Called during mode transitions.

Material System

Preview Materials

ObjectManager manages multiple material layers for preview objects:

  1. Base Material: Modified with transparency (50% opacity)
  2. Outline Material: Applied as overlay material for visual feedback
// Base material opacity modification
if (UMaterialInterface* Material = MeshComp->GetMaterial(0))
{
    UMaterialInstanceDynamic* DynamicMat = UMaterialInstanceDynamic::Create(Material, this);
    if (DynamicMat)
    {
        DynamicMat->SetScalarParameterValue(TEXT("Opacity"), PREVIEW_OPACITY); // 0.5f
        MeshComp->SetMaterial(0, DynamicMat);
    }
}

Outline Materials

// Outline material setup
if (SelectedOutlineMaterial)
{
    OutlineDynamicMaterial = UMaterialInstanceDynamic::Create(SelectedOutlineMaterial, this);
    if (OutlineDynamicMaterial)
    {
        FLinearColor InitialColor = FLinearColor(0.5f, 0.5f, 0.5f, 1.0f);
        OutlineDynamicMaterial->SetVectorParameterValue(TEXT("BaseColor"), InitialColor);
        MeshComp->SetOverlayMaterial(OutlineDynamicMaterial);
    }
}

Overlay Materials

// Dynamic overlay material for color changes
if (OverlayMaterial)
{
    OverlayDynamicMaterial = UMaterialInstanceDynamic::Create(OverlayMaterial, this);
    OverlayMeshComponent->SetMaterial(0, OverlayDynamicMaterial);
    
    FLinearColor InitialColor = FLinearColor(0.5f, 0.5f, 0.5f, 1.0f);
    OverlayDynamicMaterial->SetVectorParameterValue(TEXT("BaseColor"), InitialColor);
}

Integration with PlacementSystemComponent

ObjectManager is automatically configured and used by PlacementSystemComponent:

Configuration

// In PlacementSystemComponent::ConfigureComponents()
if (ObjectManager)
{
    ObjectManager->SetShowPlacementOverlay(bShowPlacementOverlay);
}

Object Selection Process

// When selecting object to place
if (ObjectManager)
{
    ObjectManager->CleanupActors();
    ObjectManager->CreatePreviewActor(ObjectClass, SelectedOutlineMaterial);
    
    if (bShowPlacementOverlay)
    {
        ObjectManager->CreateOverlayActor(OverlayMaterial);
    }
    
    ObjectManager->SetupCurrentObjectArrow(ObjectManager->GetPreviewActor(), EditingTarget);
}

Visual Updates

// During placement updates
if (ObjectManager)
{
    ObjectManager->UpdateArrowMaterial(); // Sync arrow with overlay colors
}

Usage Examples

Basic Preview Creation

// Create preview for furniture placement
ObjectManager->Initialize(GetWorld());
ObjectManager->SetShowPlacementOverlay(true);
 
// Create preview with outline
ObjectManager->CreatePreviewActor(ChairClass, OutlineMaterial);
 
// Add overlay indicator
ObjectManager->CreateOverlayActor(OverlayMaterial);

Material Color Updates

// Update colors based on placement validity
void UpdateVisualFeedback(EPlacementValidity Validity)
{
    FLinearColor TargetColor;
    
    switch (Validity)
    {
        case EPlacementValidity::Valid:
            TargetColor = FLinearColor::Green;
            break;
        case EPlacementValidity::Invalid:
            TargetColor = FLinearColor::Red;
            break;
        default:
            TargetColor = FLinearColor(0.5f, 0.5f, 0.5f, 1.0f);
            break;
    }
    
    // Update overlay color
    if (UMaterialInstanceDynamic* OverlayMaterial = ObjectManager->GetOverlayDynamicMaterial())
    {
        OverlayMaterial->SetVectorParameterValue(TEXT("BaseColor"), TargetColor);
    }
    
    // Update outline color
    if (UMaterialInstanceDynamic* OutlineMaterial = ObjectManager->GetOutlineDynamicMaterial())
    {
        OutlineMaterial->SetVectorParameterValue(TEXT("BaseColor"), TargetColor);
    }
    
    // Update arrow color
    ObjectManager->UpdateArrowMaterial();
}

Arrow Integration

// Setup arrow for object with directional component
if (AActor* PreviewActor = ObjectManager->GetPreviewActor())
{
    ObjectManager->SetupCurrentObjectArrow(PreviewActor, nullptr);
    
    // Check if arrow was found and configured
    if (UDirectionalArrowComponent* Arrow = ObjectManager->GetCurrentArrowComponent())
    {
        UE_LOG(LogTemp, Log, TEXT("Arrow component configured for preview"));
    }
}

Cleanup During Mode Changes

// When exiting placement mode
void CleanupPlacementMode()
{
    if (ObjectManager)
    {
        ObjectManager->CleanupActors(); // Removes all visual elements
    }
}

Constants

PREVIEW_OPACITY

static constexpr float PREVIEW_OPACITY = 0.5f;

Opacity value applied to preview objects (50% transparency).

Error Handling

ObjectManager includes comprehensive null-checking and validation:

void SafeCreatePreviewActor(TSubclassOf<AActor> ObjectClass)
{
    if (!ObjectClass)
    {
        UE_LOG(LogTemp, Warning, TEXT("ObjectManager: Cannot create preview for null ObjectClass"));
        return;
    }
    
    if (!CachedWorld)
    {
        UE_LOG(LogTemp, Error, TEXT("ObjectManager: World context not initialized"));
        return;
    }
    
    ObjectManager->CreatePreviewActor(ObjectClass, SelectedOutlineMaterial);
    
    // Verify creation
    if (AActor* PreviewActor = ObjectManager->GetPreviewActor())
    {
        UE_LOG(LogTemp, Log, TEXT("Preview actor created successfully: %s"), *PreviewActor->GetName());
    }
    else
    {
        UE_LOG(LogTemp, Error, TEXT("Failed to create preview actor"));
    }
}

Performance Considerations

Efficient Actor Management

  1. Reuse Prevention: Always destroys existing actors before creating new ones
  2. Minimal Components: Overlay actors use minimal component setup
  3. Collision Disabled: Preview and overlay actors have no collision
  4. Shadow Disabled: Overlay actors don't cast shadows

Memory Management

// Proper cleanup prevents memory leaks
void SafeDestroy(AActor* Actor)
{
    if (Actor && IsValid(Actor))
    {
        Actor->Destroy();
    }
}

Material Optimization

// Reuse material instances when possible
UMaterialInstanceDynamic* GetOrCreateDynamicMaterial(UMaterialInterface* BaseMaterial)
{
    if (!BaseMaterial) return nullptr;
    
    // Create new instance each time to ensure clean state
    return UMaterialInstanceDynamic::Create(BaseMaterial, this);
}

Troubleshooting

Common Issues

"Preview actor not showing"

  • Verify ObjectClass implements IPlaceableObjectInterface
  • Check that CreatePreviewActor completed successfully
  • Ensure world context is valid during creation

"Overlay not appearing"

  • Verify bShowPlacementOverlay is true
  • Check that overlay material is assigned
  • Ensure overlay actor creation succeeded

"Colors not updating"

  • Verify dynamic material instances exist
  • Check parameter names match material expectations ("BaseColor")
  • Ensure UpdateArrowMaterial is called after color changes

"Arrow not showing"

  • Verify object implements IPlaceableObjectInterface
  • Check that object has DirectionalArrowComponent
  • Ensure overlay material exists before setting up arrow

Debug Commands

// Debug actor state
void DebugObjectManager()
{
    UE_LOG(LogTemp, Log, TEXT("=== ObjectManager Debug ==="));
    
    // Preview actor status
    AActor* PreviewActor = ObjectManager->GetPreviewActor();
    UE_LOG(LogTemp, Log, TEXT("Preview Actor: %s"), 
           PreviewActor ? *PreviewActor->GetName() : TEXT("None"));
    
    // Overlay actor status
    AActor* OverlayActor = ObjectManager->GetOverlayActor();
    UE_LOG(LogTemp, Log, TEXT("Overlay Actor: %s"), 
           OverlayActor ? *OverlayActor->GetName() : TEXT("None"));
    
    // Material status
    UMaterialInstanceDynamic* OverlayMat = ObjectManager->GetOverlayDynamicMaterial();
    UMaterialInstanceDynamic* OutlineMat = ObjectManager->GetOutlineDynamicMaterial();
    UE_LOG(LogTemp, Log, TEXT("Overlay Material: %s"), OverlayMat ? TEXT("Valid") : TEXT("None"));
    UE_LOG(LogTemp, Log, TEXT("Outline Material: %s"), OutlineMat ? TEXT("Valid") : TEXT("None"));
    
    // Arrow status
    UDirectionalArrowComponent* Arrow = ObjectManager->GetCurrentArrowComponent();
    UE_LOG(LogTemp, Log, TEXT("Arrow Component: %s"), Arrow ? TEXT("Valid") : TEXT("None"));
}

ObjectManager provides comprehensive visual management for the placement system, ensuring smooth creation, updates, and cleanup of all visual elements while maintaining excellent performance and reliability.