Skip to content

Carry System

The carry system is intentionally simple. It is not a physics-grab system, a vehicle system, or a full inventory. It exists to support the vertical-slice fantasy:

pick up salvage
-> carry it by hand
-> enter freeform placement
-> release it into station/workstation space

The main class is:

UAndromedaCarryComponent

It is owned by AAndromedaCharacter, which also owns pickup input routing.

Character Components

The character creates:

CarryComponent = CreateDefaultSubobject<UAndromedaCarryComponent>(TEXT("Carry"));
CarryComponent->SetupAttachment(GetCapsuleComponent());

CarryComponent is a scene component parented to the capsule. It owns the held item reference, carry actions, and the transform used as the carried item attachment anchor.

Pickup

The character resolves salvage pickup targets during focus before generic interactables. When the player presses E, AAndromedaCharacter::InteractInput first gives active placement mode a chance to commit, then asks the carry component to pick up the focused target before falling back to generic interaction:

if (CarryComponent && CarryComponent->TryPickUpTarget(FocusedObject, this))
{
    return;
}

The carry component rejects pickup if:

no item
already holding an item
focused target is not a carryable actor
carryable actor refuses entry into carried state

The item-local carry capability belongs to the focused actor. CanBeCarried controls whether that actor may enter carried state. Prompt text is a separate promptable capability. The focused actor does not execute the carry command itself.

A freeform-placed salvage item keeps normal carry availability enabled after release.

Attach And Collision

On pickup, the item is attached to the carry component:

ItemToPickUp->AttachToComponent(CarryComponent, FAttachmentTransformRules::KeepWorldTransform);
ItemToPickUp->SetActorRelativeLocation(HeldItemRelativeLocation);
ItemToPickUp->SetActorRelativeRotation(HeldItemRelativeRotation);
ItemToPickUp->SetActorEnableCollision(false);

Collision is disabled while carried so the item does not block the player's movement or the interaction trace.

The carry anchor's relative transform is editable on the Carry component in BP_PlayerCharacter. The carried item's additional relative location and rotation are also editable on Carry. Those offsets are combined through normal component attachment instead of hardcoding per-item offsets in pickup logic.

Placement Release

Freeform release is owned by placement mode. When the player commits a valid placement preview, the placement component asks the carry component to release at the computed transform:

CarryComponent->TryPlaceHeldItemAtTransform(TargetTransform)

The carry component clears its held actor, then asks the salvage item to apply its placed physical state with physics enabled.

There is no fallback fixed-distance drop path. Outside placement mode, E remains normal interact input.

Scale Preservation

The carry release path preserves item scale:

const FVector ReleasedItemScale = ReleasedItem->GetActorScale3D();
FTransform ReleaseTransform = TargetTransform;
ReleaseTransform.SetScale3D(ReleasedItemScale);

This matters because spawn points and placement targets may have their own transforms. A carried item's scale should not accidentally inherit a bench's scale or a spawn point's scale.

The asset-side rule is still:

Actor/root scale should usually be 1,1,1.
Visual sizing belongs in the mesh asset or mesh component.