# Physics and Collision

Collision setup uses `execute_python` for Blueprint assets and `write_file` + `live_coding_compile` for C++ patterns.

## Collision Channels and Object Types
UE5 has two categories:
- **Object Channels**: Define WHAT an object IS (WorldStatic, WorldDynamic, Pawn, PhysicsBody, etc.)
- **Trace Channels**: Define WHAT a trace IS (Visibility, Camera, custom traces)

Each collision profile defines responses per channel:
- **Ignore** — no interaction at all
- **Overlap** — triggers overlap events, no physics blocking
- **Block** — physical collision, generates hit events

## Set collision on component

> **CRITICAL:** `bp.simple_construction_script` does NOT work in UE 5.7 Python.
> Use `unreal.UNDBlueprintHelpers` for component property access.

```python
import unreal
helpers = unreal.UNDBlueprintHelpers
bp = unreal.load_asset('/Game/Blueprints/BP_Projectile')
# Set collision profile on existing component
helpers.set_component_property(bp, 'CollisionSphere', 'CollisionProfileName', '"OverlapAllDynamic"')
helpers.set_component_property(bp, 'CollisionSphere', 'GenerateOverlapEvents', 'true')
# Compile and save
unreal.KismetEditorLibrary.compile_blueprint(bp)
unreal.EditorAssetLibrary.save_loaded_asset(bp)
```

## Discover Collision Presets and Channels
Instead of hardcoding presets, discover them at runtime:
Use `query_ue_api('ECollisionChannel')` and `query_ue_api('ECollisionResponse')` to discover collision enums (channels, response types) at runtime.
Common presets include NoCollision, BlockAll, OverlapAll, Pawn, Trigger — use `query_ue_api('collision profile')` to get the full current list.

## OnComponentBeginOverlap (C++)
```cpp
// In header
UPROPERTY(VisibleAnywhere)
USphereComponent* TriggerSphere;

UFUNCTION()
void OnTriggerOverlap(UPrimitiveComponent* OverlappedComponent,
    AActor* OtherActor, UPrimitiveComponent* OtherComp,
    int32 OtherBodyIndex, bool bFromSweep,
    const FHitResult& SweepResult);

// In constructor
TriggerSphere = CreateDefaultSubobject<USphereComponent>(TEXT("TriggerSphere"));
TriggerSphere->SetSphereRadius(200.f);
TriggerSphere->SetCollisionProfileName(TEXT("Trigger"));
TriggerSphere->SetGenerateOverlapEvents(true);
TriggerSphere->SetupAttachment(RootComponent);

// In BeginPlay
TriggerSphere->OnComponentBeginOverlap.AddDynamic(
    this, &AMyActor::OnTriggerOverlap);

// Implementation
void AMyActor::OnTriggerOverlap(UPrimitiveComponent* OverlappedComponent,
    AActor* OtherActor, UPrimitiveComponent* OtherComp,
    int32 OtherBodyIndex, bool bFromSweep,
    const FHitResult& SweepResult)
{
    if (OtherActor && OtherActor != this)
    {
        UE_LOG(LogTemp, Log, TEXT("Overlap with: %s"), *OtherActor->GetName());
    }
}
```

## OnComponentHit (C++)
```cpp
// In header
UFUNCTION()
void OnProjectileHit(UPrimitiveComponent* HitComponent,
    AActor* OtherActor, UPrimitiveComponent* OtherComp,
    FVector NormalImpulse, const FHitResult& Hit);

// In BeginPlay
MeshComp->OnComponentHit.AddDynamic(this, &AMyProjectile::OnProjectileHit);

// Implementation
void AMyProjectile::OnProjectileHit(UPrimitiveComponent* HitComponent,
    AActor* OtherActor, UPrimitiveComponent* OtherComp,
    FVector NormalImpulse, const FHitResult& Hit)
{
    // Apply damage, spawn effect, destroy
    if (OtherActor)
    {
        UGameplayStatics::ApplyDamage(OtherActor, 25.f, GetInstigatorController(),
            this, UDamageType::StaticClass());
    }
    Destroy();
}
```

## Projectile setup pattern
```cpp
// AMyProjectile constructor
CollisionComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
CollisionComp->InitSphereRadius(5.0f);
CollisionComp->SetCollisionProfileName(TEXT("Projectile"));
CollisionComp->SetWalkableSlopeOverride(FWalkableSlopeOverride(
    WalkableSlope_Unwalkable, 0.f));
CollisionComp->CanCharacterStepUpOn = ECB_No;
RootComponent = CollisionComp;

ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileComp"));
ProjectileMovement->UpdatedComponent = CollisionComp;
ProjectileMovement->InitialSpeed = 3000.f;
ProjectileMovement->MaxSpeed = 3000.f;
ProjectileMovement->bRotationFollowsVelocity = true;
ProjectileMovement->bShouldBounce = false;
```

## Line Trace (C++)
```cpp
FHitResult HitResult;
FVector Start = GetActorLocation();
FVector End = Start + GetActorForwardVector() * 10000.f;
FCollisionQueryParams Params;
Params.AddIgnoredActor(this);

bool bHit = GetWorld()->LineTraceSingleByChannel(
    HitResult, Start, End, ECC_Visibility, Params);
if (bHit)
{
    AActor* HitActor = HitResult.GetActor();
    // Process hit
}
```

## Physics Constraints basics
- **PhysicsConstraintComponent** — joins two physics bodies
- Set linear/angular limits for joints (hinge, ball socket, prismatic)
- Used for: doors, chains, ragdoll attachments, vehicles

## CRITICAL RULES
- Overlap events REQUIRE `SetGenerateOverlapEvents(true)` on BOTH components
- OnComponentHit only fires when collision response is Block
- Overlap callback signature MUST match exactly (UFUNCTION() required for AddDynamic)
- Hit callback signature is DIFFERENT from overlap (includes NormalImpulse, no bFromSweep)
- For projectiles: set collision to Block WorldStatic + Overlap Pawn (or custom channel)
- Never forget to AddDynamic in BeginPlay — binding in constructor doesn't work for Blueprints
- Trace channels (Visibility, Camera) are for line/sphere traces, not physics simulation
