Grab, carry & throw

UMovaIxGrabComponent is the "hands" half of MovaInteract: physics grab, carry, and throw for a pawn. Add it, bind a few inputs, and the player can pick up any simulating physics primitive under the crosshair, carry it floating in front of the camera, and hurl it.

grab carry throw (placeholder mockup)

Save the real screenshot as: shot-grab-carry-throw.png

Add it to a pawn

  1. Select your pawn Blueprint → Add Component → Mova Interact Grab.

  2. Bind input actions to the verbs you want:

Function

Does

ToggleGrab()

Grab the aimed primitive when hands are empty, else drop the held one. The one binding most games need.

GrabAimed()

Grab only: returns true if something was grabbed.

ReleaseHeld()

Drop the held primitive where it is, no impulse.

ThrowHeld(StrengthScale = 1.0f)

Throw along the view; StrengthScale multiplies ThrowImpulse.

That's the whole setup, no physics handle to configure by hand, the component spawns and owns a UPhysicsHandleComponent in BeginPlay.

What counts as grabbable: IsGrabbable

A primitive is grabbable when it:

  • Is simulating physics (bSimulatePhysics = true), and

  • Is under MaxGrabMass (kg; 0 = no cap), and

  • Carries GrabTag on the primitive or its actor. GrabTag defaults to the canonical #Grab component tag: set it in the constructor from MovaIx::Names::Grab so the literal lives in one place. Set GrabTag = None to allow grabbing any simulating primitive regardless of tag.

IsGrabbable(Prim) is BlueprintPure and public: a game needs to ask before offering a prompt, an outline, or a "too big" message, and it's the exact filter the server re-runs on every grab request, so you can test it directly.

Tuning the feel

Property

Controls

ReachDistance

How far the grab trace reaches from the camera (cm): how far away you can start a grab.

HoldDistance

Where the held object floats in front of the camera (cm) once grabbed.

HoldInterpSpeed

How snappily the held object chases the hold point as you move (0 = the physics handle's own default: very stiff).

ThrowImpulse

Impulse magnitude applied along the view on ThrowHeld (full strength, before StrengthScale).

bRotateHeldWithView

On: the object's rotation follows your view while held (good for tools, weapons). Off (default): it keeps whatever rotation it was grabbed at (good for crates, debris, no snapping to face you).

TraceChannel

Trace channel used to find the grabbable under the crosshair (default ECC_Visibility).

A heavier-feeling game wants a lower HoldInterpSpeed and a shorter ReachDistance; an arcade-y one wants both cranked up.

Composing with the tag grammar

OnGrabbed(Component) / OnReleased(Component) / OnThrown(Component) hand you the primitive on pickup and drop. Use them to run ordinary interaction tags (glow while carried, a thunk on landing) bridging the grab system into the same Tag Grammar Reference everything else uses:

void AMyPawn::HandleGrabbed(UPrimitiveComponent* Comp)
{
    if (UMovaIxComponent* IC = Comp->GetOwner()->FindComponentByClass<UMovaIxComponent>())
    {
        IC->ExecuteTags({ TEXT("!Highlight #Self") });
    }
}

Bind these three events once on BeginPlay and every grabbable object in the level gets the same pickup/drop feedback without per-object wiring.

Multiplayer: server-authoritative

Grab is server-authoritative, the same pattern as the rest of the plugin (see Multiplayer):

  • A client aims and traces locally for responsiveness, then calls Server_Grab(Prim, GrabLocation) / Server_Release() / Server_Throw(StrengthScale): all WithValidation.

  • The server re-validates: IsGrabbable(Prim) again, plus IsGrabInServerRange(GrabLocation) (reach + lag slack), before it ever touches the physics handle. A modified client cannot grab past a wall or across the map.

  • HeldComponent is ReplicatedUsing = OnRep_Held: every client mirrors the held state and fires OnGrabbed / OnReleased / OnThrown from the rep notify, so effects trigger the same way on every machine, not only the grabber's.

  • The carried object itself must be a replicated actor with replicated movement to visibly move on remote machines: the grab component moves it authoritatively on the server, but if the actor doesn't replicate transform, other clients won't see it follow.

Note

bLastReleaseWasThrow is a small replicated flag that tells OnRep_Held whether to fire OnThrown instead of OnReleased when the held component clears, so remote clients get the right event even though they never see the throw impulse itself.

See also