# 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. ```{image} ../_static/screenshots/shot-grab-carry-throw-mockup.svg :alt: grab carry throw (placeholder mockup) :width: 100% ``` 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 {doc}`../concepts/tag-grammar` everything else uses: ```cpp void AMyPawn::HandleGrabbed(UPrimitiveComponent* Comp) { if (UMovaIxComponent* IC = Comp->GetOwner()->FindComponentByClass()) { 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 {doc}`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 - {doc}`../concepts/tag-grammar`: the syntax `OnGrabbed`/`OnReleased` handlers run. - {doc}`multiplayer`: the server-authoritative pattern this component shares with the rest of MovaInteract. - {doc}`debugging`: `mova.ix.Debug` shows detection state alongside grab reach, useful when tuning `ReachDistance`.