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
-> place it on a scanner/bench/zone
-> drop it if needed

The main class is:

UAndromedaCarryComponent

It is owned by AAndromedaCharacter.

Character Components

The character creates:

CarryHoldPointComponent = CreateDefaultSubobject<USceneComponent>(TEXT("CarryHoldPoint"));
CarryHoldPointComponent->SetupAttachment(FirstPersonCameraComponent);

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

CarryHoldPointComponent is a camera-relative attachment point. CarryComponent owns the actual held item reference and carry actions.

At BeginPlay:

CarryComponent->SetHoldParent(CarryHoldPointComponent);

That gives the carry component a scene component to attach items to.

Pickup

AAndromedaSalvageItem::Interact_Implementation tries to pick up the item:

UAndromedaCarryComponent* CarryComponent = InteractingPawn
    ? InteractingPawn->FindComponentByClass<UAndromedaCarryComponent>()
    : nullptr;

const bool bPickedUp = CarryComponent && CarryComponent->PickUpItem(this);

The carry component rejects pickup if:

no item
already holding an item
no hold parent
item already processed
item already held

If the item was sitting on a station, pickup clears that station first:

if (AAndromedaItemStation* CurrentStation = ItemToPickUp->GetCurrentStation())
{
    CurrentStation->ClearPlacedItem(ItemToPickUp);
}

That prevents the station from thinking it still owns the item.

Attach And Collision

On pickup, the item is attached to the hold parent:

ItemToPickUp->AttachToComponent(HoldParent, 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 relative location and rotation are editable on the Carry component in BP_PlayerCharacter. That is where the carried item was adjusted so it no longer blocks the player's view.

Placement

Stations do not manually move items. They ask the carry component to place the held item at their placement point:

CarryComponent->PlaceHeldItem(PlacementPointComponent)

That goes through:

ReleaseHeldItemAtTransform(PlacementPoint->GetComponentTransform());

The release code detaches the item, applies the target transform, re-enables collision, and clears the held pawn reference.

Drop

Dropping is now contextual through E. There is no separate IA_Drop.

If the player presses E while carrying an item and not focused on a valid interactable, the character calls:

CarryComponent->DropHeldItem();

The drop transform is built from the owning character:

DropLocation = OwnerLocation + OwnerForwardVector * DropDistance
DropRotation = OwnerRotation

This puts the item in front of the player. It is still intentionally simple; there is no sweep, floor projection, or physics settling yet.

Scale Preservation

The carry release path preserves item scale:

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

This matters because station placement points and spawn points 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.