# BPC_PhysicsDragSystem — Physics Drag System

**Parent Class:** `ActorComponent`
**Category:** Interaction
**Target UE Version:** 5.5–5.7
**Build Phase:** 2 — Interaction

---

## 1. Overview

`BPC_PhysicsDragSystem` allows the player to grab and physically drag rigid-body objects in the world. Supports grab-at-distance, hold-to-grab with physics constraints, object rotation, and throw mechanics. Integrates with the interaction detector for grab targeting.

---

## 2. Enums

### `E_DragMode`

| Value | Description |
|-------|-------------|
| `PhysicsConstraint` | Attaches object via physics constraint to player hand |
| `Kinematic` | Sets object to kinematic and parents to hand |
| `Magnetic` | Objects smoothly lerp toward grab point |

---

## 3. Variables

| Name | Type | Description |
|------|------|-------------|
| `DragMode` | `E_DragMode` | Current drag physics mode |
| `GrabbedObject` | `AActor*` | Currently held actor |
| `ConstraintComp` | `UPhysicsConstraintComponent*` | Physics constraint for held object |
| `GrabDistance` | `float` | Max distance to grab (cm) |
| `HoldDistance` | `float` | Distance object is held from camera |
| `ThrowForce` | `float` | Impulse applied on release |
| `RotationSpeed` | `float` | Degrees/sec for object rotation input |
| `bCanThrow` | `bool` | Object can be thrown on release |
| `bIsGrabbing` | `bool` | Currently holding an object |

---

## 4. Functions

| Function | Description |
|----------|-------------|
| `GrabObject` | Attempts to grab targeted physics object. Returns bool. |
| `ReleaseObject` | Releases held object, applies throw force if bCanThrow. |
| `RotateObject` | Rotates held object by input axis values |
| `SetHoldDistance` | Adjusts distance of held object from camera |
| `GetGrabbedObject` | Returns currently held actor (or null) |
| `IsGrabbing` | Returns `bIsGrabbing` |

---

## 5. Event Dispatchers

| Dispatcher | Payload | Description |
|------------|---------|-------------|
| `OnObjectGrabbed` | `AActor* GrabbedObject` | Object successfully grabbed |
| `OnObjectReleased` | `AActor* ReleasedObject`, `bool bWasThrown` | Object released |
| `OnGrabFailed` | `FText FailReason` | Grab attempt failed |

---

## 6. Blueprint Flow

```
GrabObject:
  → Get targeted object from InteractionDetector
  → Check if object has physics simulation enabled
  → If DragMode == PhysicsConstraint:
      → Create physics constraint between hand socket and object
      → Set constraint limits (linear + angular)
  → If DragMode == Kinematic:
      → Set object simulated physics to false
      → Attach to hand socket
  → Set bIsGrabbing = true
  → Broadcast OnObjectGrabbed

ReleaseObject:
  → If bCanThrow → Apply forward impulse * ThrowForce
  → Destroy constraint / detach
  → Re-enable physics on object
  → Set bIsGrabbing = false
  → Broadcast OnObjectReleased
```

---

## 7. Dependencies & Communication

| System | Relationship |
|--------|--------------|
| `BPC_InteractionDetector` | Provides grab target via focus |
| `BPC_CameraStateLayer` | Camera direction for throw vector |
| `BPC_MovementStateSystem` | Speed modifier while carrying objects |

---

## 8. Reuse Notes
- Physics drag uses UE5 physics constraint system for realistic object handling
- Objects must have `Simulate Physics = true` and `Mass` configured

---

## 9. Manual Implementation Guide

### 9.1 Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_PhysicsDragSystem`
2. Save to: `Content/Framework/Interaction/`
3. Add to your Player Character.

### 9.2 Variable Initialization (BeginPlay)

```
Event BeginPlay
  ├─ Set bIsGrabbing = false
  ├─ Set GrabbedObject = None
  ├─ Get Owner → Get Component by Class (BPC_InteractionDetector) → Store reference
  └─ Get Owner → Get PlayerCameraManager → Store for throw direction
```

### 9.3 Function Implementations

#### `GrabObject(TargetActor: Actor)` → `Boolean`

**Node-by-Node Logic:**
```
[Function: GrabObject]
  Step 1: Branch on bIsGrabbing → If true, ReleaseObject first
  Step 2: Branch on IsValid(TargetActor) → If not, return false
  Step 3: Get TargetActor → Get Component by Class (StaticMeshComponent)
    └─ Check: Is Simulate Physics Enabled? → If not, Fire OnGrabFailed("No physics"), return false
  Step 4: Check mass: StaticMeshComponent.GetMass() → If > MaxGrabMass, fail
  Step 5: Switch on DragMode:
    Case PhysicsConstraint:
      - Create Physics Constraint component (spawn dynamically)
      - ConstraintComp.SetConstrainedComponents(StaticMeshComponent, None, PlayerHandBone)
      - Set Linear limits: X=Locked, Y=Locked, Z=Locked (or Free for dangling)
      - Set Angular limits: Free (can rotate), or limited
    Case Kinematic:
      - StaticMeshComponent.SetSimulatePhysics(false)
      - StaticMeshComponent.AttachToComponent(PlayerHandSocket)
    Case Magnetic:
      - Store target; handle in Tick with Lerp toward hand position
  Step 6: Set GrabbedObject = TargetActor
  Step 7: Set bIsGrabbing = true
  Step 8: Fire OnObjectGrabbed(TargetActor)
  Step 9: Return true
```

**Nodes Used:** `IsValid`, `Get Component by Class (StaticMeshComponent)`, `Is Simulate Physics Enabled`, `Get Mass`, `Create Constraint`, `SetConstrainedComponents`, `AttachToComponent`, `Branch`

#### `ReleaseObject(bThrow: Boolean)` → `void`

```
[Function: ReleaseObject]
  Step 1: Branch on bIsGrabbing → If false, return
  Step 2: Branch on bThrow AND bCanThrow:
    True:
      - Get PlayerCameraManager → Get Forward Vector
      - Multiply forward vector by ThrowForce
      - GrabbedObject.StaticMeshComponent.AddImpulse(throw vector)
      - OR: if ConstraintComp exists → BreakConstraint, then AddImpulse
    False:
      - Just release without force
  Step 3: Switch on DragMode:
    - PhysicsConstraint: Destroy ConstraintComp
    - Kinematic: DetachFromComponent, SetSimulatePhysics(true)
    - Magnetic: Clear target reference
  Step 4: Set GrabbedObject = None
  Step 5: Set bIsGrabbing = false
  Step 6: Fire OnObjectReleased(GrabbedObject, bThrow)
```

**Nodes Used:** `Get Forward Vector`, `Multiply (Vector * Float)`, `Add Impulse`, `Break Constraint`, `Destroy Component`, `Detach From Component`, `Set Simulate Physics`

#### `RotateObject(YawInput: Float, PitchInput: Float, RollInput: Float)` → `void`

```
[Function: RotateObject]
  Step 1: Branch on bIsGrabbing → If false, return
  Step 2: Create Rotator from inputs (use RotationSpeed multiplier)
    - NewRotation = Make Rotator(PitchInput * RotationSpeed * DeltaTime, YawInput * RotationSpeed * DeltaTime, RollInput * RotationSpeed * DeltaTime)
  Step 3: Switch on DragMode:
    - PhysicsConstraint: GrabbedObject.AddLocalRotation(NewRotation)
    - Kinematic: GrabbedObject.AddRelativeRotation(NewRotation)
    - Magnetic: Rotate the lerp target
```

#### `SetHoldDistance(NewDistance: Float)` → `void`

```
[Function: SetHoldDistance]
  Step 1: Clamp NewDistance between MinHoldDistance and MaxHoldDistance
  Step 2: Set HoldDistance = NewDistance
  Step 3: If DragMode == PhysicsConstraint:
    - ConstraintComp.SetLinearPositionTarget(PlayerCamera.ForwardVector * HoldDistance)
  Step 4: If DragMode == Kinematic:
    - Set Relative Location (X = HoldDistance, Y = 0, Z = 0) on attached component
```

### 9.4 Event Dispatcher Bindings

| Bind to Dispatcher | Custom Event | Logic |
|-------------------|-------------|-------|
| Input Action: `IA_Grab` (Pressed) | `OnGrabPressed` | Get InteractionDetector.CurrentTarget → Call GrabObject |
| Input Action: `IA_Grab` (Released) | `OnGrabReleased` | Call ReleaseObject(true) |
| `BPC_InteractionDetector.OnTargetFound` | `OnGrabTargetFound(Target)` | Highlight grabbable object outline |

### 9.5 Networking

| Variable | Replication |
|----------|-------------|
| `bIsGrabbing` | `Replicated` |
| `GrabbedObject` | `Replicated` (Actor reference) |

**Server RPC:** `Server_GrabObject(TargetActor)` — server validates range, spawns constraint. Physics is server-authoritative; client predicts locally.

### 9.6 Blueprint Build Checklist

- [ ] Create BPC_PhysicsDragSystem component, add to Player Character
- [ ] Add all variables: DragMode, GrabbedObject, ConstraintComp, GrabDistance, HoldDistance, ThrowForce, RotationSpeed, bCanThrow, bIsGrabbing
- [ ] Implement GrabObject with three drag modes (PhysicsConstraint, Kinematic, Magnetic)
- [ ] Implement ReleaseObject with throw mechanic
- [ ] Implement RotateObject with input axis mapping
- [ ] Implement SetHoldDistance with scroll wheel input
- [ ] Bind to IA_Grab input action (pressed/released)
- [ ] Add MaxGrabMass config to prevent lifting impossibly heavy objects
- [ ] Test: grab crate, rotate, throw — physics should feel natural