Loading...
Loading...
Use when implementing collision detection, trace queries, physics simulation, or physical interactions in Unreal Engine. Triggers on: 'collision', 'trace', 'LineTrace', 'line trace', 'overlap', 'physics', 'hit result', 'sweep', 'collision channel', 'physics body', 'Chaos', 'raytrace', 'OnHit', 'OnBeginOverlap'. See related skills for component architecture and AI navigation.
npx skill4agent add quodsoler/unreal-engine-skills ue-physics-collision.agents/ue-project-context.md"PhysicsCore""Engine"Build.csECC_WorldStatic, ECC_WorldDynamic, ECC_Pawn, ECC_PhysicsBody,
ECC_Vehicle, ECC_Destructible // object channels (what an object IS)
ECC_Visibility, ECC_Camera // trace channels (used for queries)
// Custom: ECC_GameTraceChannel1..ECC_GameTraceChannel18ECR_IgnoreECR_OverlapECR_BlockBlockAllBlockAllDynamicOverlapAllOverlapAllDynamicPawnPhysicsActorNoCollisionMyMesh->SetCollisionProfileName(TEXT("BlockAll")); // preferred — sets all at once
MyMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
// ECollisionEnabled: NoCollision | QueryOnly | PhysicsOnly | QueryAndPhysics
MyMesh->SetCollisionObjectType(ECC_PhysicsBody);
MyMesh->SetCollisionResponseToAllChannels(ECR_Block);
MyMesh->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
MyMesh->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore);ByObjectTypeByChannelECC_VisibilityWeaponECC_Pawn[/Script/Engine.CollisionProfile]
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Block,bTraceType=True,bStaticObject=False,Name="Weapon")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Block,bTraceType=False,bStaticObject=False,Name="Interactable")
+Profiles=(Name="Interactable",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Interactable",CustomResponses=((Channel="Weapon",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Block)))bTraceType=TruebTraceType=Falsereferences/collision-channel-setup.mdFCollisionQueryParams Params;
Params.TraceTag = TEXT("WeaponTrace"); // for profiling/debug
Params.bTraceComplex = false; // false=simple hull (fast); true=per-poly (expensive)
Params.bReturnPhysicalMaterial = true; // populates Hit.PhysMaterial
Params.bReturnFaceIndex = false; // expensive, only when needed
Params.AddIgnoredActor(this);
Params.AddIgnoredComponent(MyComp);WorldCollision.hUWorldFHitResult Hit;
// By trace channel
GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Visibility, Params);
GetWorld()->LineTraceMultiByChannel(Hits, Start, End, ECC_Visibility, Params);
// By object type
FCollisionObjectQueryParams ObjParams(ECC_PhysicsBody);
ObjParams.AddObjectTypesToQuery(ECC_WorldDynamic);
GetWorld()->LineTraceSingleByObjectType(Hit, Start, End, ObjParams, Params);
// By profile
GetWorld()->LineTraceSingleByProfile(Hit, Start, End, TEXT("BlockAll"), Params);CollisionShape.hFCollisionShape Sphere = FCollisionShape::MakeSphere(30.f);
FCollisionShape Box = FCollisionShape::MakeBox(FVector(50.f, 50.f, 50.f));
FCollisionShape Capsule = FCollisionShape::MakeCapsule(34.f, 88.f); // radius, half-height
GetWorld()->SweepSingleByChannel(Hit, Start, End, FQuat::Identity, ECC_Pawn, Sphere, Params);
GetWorld()->SweepMultiByChannel(Hits, Start, End, FQuat::Identity, ECC_Pawn, Sphere, Params);
GetWorld()->SweepSingleByObjectType(Hit, Start, End, FQuat::Identity, ObjParams, Sphere, Params);
GetWorld()->SweepSingleByProfile(Hit, Start, End, FQuat::Identity, TEXT("Pawn"), Sphere, Params);TArray<FOverlapResult> Overlaps;
GetWorld()->OverlapMultiByObjectType(Overlaps, Center, FQuat::Identity,
FCollisionObjectQueryParams(ECC_Pawn), FCollisionShape::MakeSphere(500.f), Params);
for (const FOverlapResult& R : Overlaps) { AActor* A = R.GetActor(); }
// By trace channel (uses channel responses, not object type matching):
GetWorld()->OverlapMultiByChannel(
Overlaps, Center, FQuat::Identity, ECC_Pawn,
FCollisionShape::MakeSphere(Radius), QueryParams);Hit.bBlockingHit; // true if blocking
Hit.ImpactPoint; // world space contact point
Hit.ImpactNormal; // surface normal
Hit.Distance; // from Start to impact
Hit.BoneName; // skeletal mesh bone
Hit.GetActor();
Hit.GetComponent();
// Physical material (requires bReturnPhysicalMaterial=true):
if (UPhysicalMaterial* M = Hit.PhysMaterial.Get())
EPhysicalSurface S = UPhysicalMaterial::DetermineSurfaceType(M);#include "Kismet/KismetSystemLibrary.h"
TArray<AActor*> Ignore = { this };
// LineTrace with debug draw (ETraceTypeQuery maps to ECollisionChannel)
UKismetSystemLibrary::LineTraceSingle(this, Start, End,
ETraceTypeQuery::TraceTypeQuery1, false, Ignore, EDrawDebugTrace::ForDuration, Hit, true);
// SphereTrace
UKismetSystemLibrary::SphereTraceSingle(this, Start, End, 50.f,
ETraceTypeQuery::TraceTypeQuery1, false, Ignore, EDrawDebugTrace::ForOneFrame, Hit, true);
// By profile
UKismetSystemLibrary::LineTraceSingleByProfile(this, Start, End,
TEXT("BlockAll"), false, Ignore, EDrawDebugTrace::None, Hit, true);FTraceHandle Handle = GetWorld()->AsyncLineTraceByChannel(
EAsyncTraceType::Single, Start, End, ECC_Visibility, Params);
// Read next frame:
FTraceDatum Datum;
if (GetWorld()->QueryTraceData(Handle, Datum) && Datum.OutHits.Num() > 0)
FHitResult& Hit = Datum.OutHits[0];#if ENABLE_DRAW_DEBUG
DrawDebugLine(GetWorld(), Start, End, FColor::Red, false, 2.f);
DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 10.f, 12, FColor::Green, false, 2.f);
#endifDrawDebugLineDrawDebugSphereDrawDebugHelpers.hENABLE_DRAW_DEBUGbPersistentLinesLifeTimereferences/trace-patterns.mdPrimitiveComponent.hOnComponentHit(HitComp, OtherActor, OtherComp, NormalImpulse, FHitResult)OnComponentBeginOverlap(OverlappedComp, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult)OnComponentEndOverlap(OverlappedComp, OtherActor, OtherComp, OtherBodyIndex)// Hit events (physics collision)
MyMesh->SetNotifyRigidBodyCollision(true); // "Simulation Generates Hit Events"
MyMesh->OnComponentHit.AddDynamic(this, &AMyActor::OnHit);
UFUNCTION()
void AMyActor::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor,
UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) {}
// Overlap events — SetGenerateOverlapEvents(true) REQUIRED on BOTH components
MyMesh->SetGenerateOverlapEvents(true);
MyMesh->OnComponentBeginOverlap.AddDynamic(this, &AMyActor::OnBeginOverlap);
MyMesh->OnComponentEndOverlap.AddDynamic(this, &AMyActor::OnEndOverlap);
UFUNCTION()
void AMyActor::OnBeginOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) {}
UFUNCTION()
void AMyActor::OnEndOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) {}QueryAndPhysicsECR_BlockSetNotifyRigidBodyCollision(true)ECR_OverlapSetGenerateOverlapEvents(true)// Enable simulation (PrimitiveComponent.h / BodyInstanceCore.h)
MyMesh->SetSimulatePhysics(true);
MyMesh->SetEnableGravity(true);
MyMesh->SetMassOverrideInKg(NAME_None, 50.f, true); // 50 kg
MyMesh->SetLinearDamping(0.1f);
MyMesh->SetAngularDamping(0.05f);
float Mass = MyMesh->GetMass();
// Forces and impulses
MyMesh->AddImpulse(FVector(0,0,1000), NAME_None, false); // bVelChange=true ignores mass
MyMesh->AddImpulseAtLocation(FVector(500,0,0), HitPoint); // adds torque
MyMesh->AddForce(FVector(0,0,9800), NAME_None, false); // continuous (per tick)
MyMesh->AddRadialImpulse(Center, 500.f, 2000.f, RIF_Linear, false);
MyMesh->SetPhysicsLinearVelocity(FVector(0,0,300)); // use sparinglybSimulatePhysicsbOverrideMassbEnableGravitybAutoWeldbStartAwakebGenerateWakeEventsbUpdateKinematicFromSimulationBodySetupEnums.hCTF_UseDefaultCTF_UseSimpleAndComplexCTF_UseSimpleAsComplexCTF_UseComplexAsSimpleUPhysicsConstraintComponent* C = NewObject<UPhysicsConstraintComponent>(this);
C->SetupAttachment(RootComponent);
C->SetConstrainedComponents(MeshA, NAME_None, MeshB, NAME_None);
C->SetAngularSwing1Limit(EAngularConstraintMotion::ACM_Limited, 45.f);
C->SetAngularTwistLimit(EAngularConstraintMotion::ACM_Free, 0.f);
C->SetLinearXLimit(ELinearConstraintMotion::LCM_Locked, 0.f);
C->RegisterComponent();ConstraintProfile| Preset | Angular Limits | Linear Limits |
|---|---|---|
| Fixed | All locked | All locked |
| Hinge | One axis free | All locked |
| Prismatic | All locked | One axis free |
| Ball-and-Socket | All free | All locked |
PhysicalMaterials/PhysicalMaterial.hfloat Friction; // kinetic (0 = frictionless)
float StaticFriction; // before sliding starts
float Restitution; // 0 (no bounce) to 1 (elastic)
float Density; // g/cm^3 — used to compute mass from shape volume
EPhysicalSurface SurfaceType; // SurfaceType_Default, SurfaceType1..SurfaceType62
// FrictionCombineMode / RestitutionCombineMode: Average, Min, Multiply, Max
// Runtime override
MyMesh->SetPhysMaterialOverride(MyPhysMaterial);
// Detect surface from trace (requires bReturnPhysicalMaterial=true)
if (UPhysicalMaterial* M = Hit.PhysMaterial.Get())
{
EPhysicalSurface S = UPhysicalMaterial::DetermineSurfaceType(M);
switch (S) { case SurfaceType1: /* Metal */ break; }
}FChaosSceneChaosScene.hStartFrame()SetUpForFrame()EndFrame()MaxSubstepsMaxSubstepDeltaTimeUPhysicsSettings::bTickPhysicsAsyncUAsyncPhysicsInputComponentUPhysicsSettingsCorePhysicsSettingsCore.hfloat DefaultGravityZ; // -980 cm/s^2 default
float BounceThresholdVelocity; // min velocity to bounce
float MaxAngularVelocity; // rad/s cap
float MaxDepenetrationVelocity;
float ContactOffsetMultiplier; // contact shell size
FChaosSolverConfiguration SolverOptions;SurfaceType1..SurfaceType62UGeometryCollectionComponentFPhysicalMaterialStrengthFPhysicalMaterialDamageModifierUPhysicalMaterial// Cloth uses UClothingAssetBase attached to USkeletalMeshComponent
// Enable in Mesh asset: Clothing → Add Clothing Data
// C++ access:
USkeletalMeshComponent* Mesh = GetMesh();
if (UClothingSimulationInteractor* Cloth = Mesh->GetClothingSimulationInteractor())
{
Cloth->PhysicsAssetUpdated(); // re-sync after physics asset change
Cloth->SetAnimDriveSpringStiffness(10.f); // blend anim ↔ cloth
}// Place AFieldSystemActor in level, add field nodes:
// URadialFalloff — distance-based falloff
// URadialVector — directional force from center
// UUniformVector — constant directional force
// UBoxFalloff — box-shaped field region
// Trigger destruction at runtime:
AFieldSystemActor* FieldActor = GetWorld()->SpawnActor<AFieldSystemActor>();
URadialFalloff* Falloff = NewObject<URadialFalloff>(FieldActor);
Falloff->SetRadialFalloff(1000000.f, 0.8f, 1.f, 0.f, 500.f, FVector::ZeroVector, EFieldFalloffType::Field_Falloff_Linear);
UFieldSystemMetaDataFilter* Meta = NewObject<UFieldSystemMetaDataFilter>(FieldActor);
Meta->SetMetaDataFilterType(EFieldFilterType::Field_Filter_All, EFieldObjectType::Field_Object_All, EFieldPositionType::Field_Position_CenterOfMass);
FieldActor->GetFieldSystemComponent()->ApplyPhysicsField(true, EFieldPhysicsType::Field_ExternalClusterStrain, Meta, Falloff);ECR_OverlapbGenerateOverlapEvents=trueQueryOnlyPhysicsOnlyQueryAndPhysicsbTraceComplex=truefalseSetNotifyRigidBodyCollisionOnComponentHitbSimulateSkeletalMeshOnDedicatedServer=falseOnComponentHitOnBeginOverlapFRepMovementbReplicateMovementbReplicateMovement = true// Build.cs
PublicDependencyModuleNames.AddRange(new string[] {
"Core", "CoreUObject",
"Engine", // UPrimitiveComponent, FHitResult, UWorld trace API
"PhysicsCore", // UPhysicalMaterial, FCollisionShape, FBodyInstanceCore
});ue-actor-component-architectureUPrimitiveComponentue-ai-navigationue-gameplay-abilitiesue-cpp-foundations