Skip to content

Physics & Collisions

Physics lives on World.Physics. Most methods take the entity you want to act on, so the same call works for your own entity or any other:

World.Physics:AddImpulse(self.Entity, Vec3(0, 500, 0))
local Velocity: vector = World.Physics:GetLinearVelocity(self.Entity)

The entity needs a Rigid Body for body methods to do anything.

MethodEffect
AddForce(Entity, Force)World-space force (N) for one step
AddImpulse(Entity, Impulse)Instantaneous impulse (kg·m/s)
AddTorque(Entity, Torque)Torque (N·m) for one step
AddAngularImpulse(Entity, Impulse)Instantaneous angular impulse
AddForceAtPosition(Entity, Force, Point)Force at a world point (adds spin)
AddImpulseAtPosition(Entity, Impulse, Point)Impulse at a world point
MethodEffect
SetLinearVelocity(Entity, Velocity)Replace linear velocity (m/s)
SetAngularVelocity(Entity, Velocity)Replace angular velocity (rad/s)
GetLinearVelocity(Entity) / GetAngularVelocity(Entity)Read it back (vector)
GetVelocityAtPoint(Entity, Point)Velocity of a point on the body
MethodReturns / effect
GetBodyPosition(Entity) / GetBodyRotation(Entity)The true physics pose, not the lagged render transform
GetCenterOfMass(Entity)World-space center of mass
GetBodyID(Entity)The Jolt body id (used below for ignore lists and waking)
ActivateBody(BodyId) / DeactivateBody(BodyId)Wake or sleep a body (pass a GetBodyID result)
SetGravityFactor(Entity, Factor)Per-body gravity multiplier (0 = float, 1 = normal)

A raycast shoots a line through the world and tells you the first thing it hits, the workhorse behind shooting, line of sight, ground checks, and interaction.

Build an SRayCastSettings, set its Start and End, and call World.Physics:RayCast. It returns the closest hit as an SRayResult, or nil when the ray hits nothing:

local From = self.Transform:GetWorldLocation()
local To = From + self.Transform:GetForward() * 100
local Settings = SRayCastSettings.new()
Settings.Start = From
Settings.End = To
local Hit = World.Physics:RayCast(Settings)
if Hit then
print("hit", Hit.Entity, "at", Hit.Location)
end

The SRayResult fields:

FieldMeaning
Hit.EntityThe entity that was hit
Hit.LocationThe world-space hit point (vector)
Hit.NormalThe surface normal at the hit (vector)
Hit.DistanceDistance from Start to the hit
Hit.FractionHow far along the ray the hit is, 0 at Start, 1 at End
Hit.BodyIDThe Jolt body id that was hit

The engine types behind a cast:

struct SRayCastSettings // and SSphereCastSettings, which adds: float Radius;
{
FVector3 Start, End;
ECollisionProfiles LayerMask; // which layers the ray can hit
TVector<uint32> IgnoreBodies; // bodies to skip
bool bDrawDebug = false;
// ...
};
struct SRayResult
{
uint32 Entity; // the entity that was hit
int64 BodyID; // its Jolt body id
FVector3 Location; // world-space hit point
FVector3 Normal; // surface normal at the hit
float Fraction; // 0 at Start, 1 at End
float Distance; // distance from Start to the hit
};

SRayCastSettings has more fields to control what the ray can hit:

Field / methodWhat it does
Settings:AddIgnoredBody(BodyId)Skip a specific body. Ignore the shooter with Settings:AddIgnoredBody(World.Physics:GetBodyID(self.Entity)).
Settings.IgnoreBodiesThe list of ignored body ids.
Settings.LayerMaskOnly hit bodies on certain collision layers.
Settings.bDrawDebug / Settings.DebugDurationDraw the ray for debugging, with DebugHitColor / DebugMissColor.

A sphere cast sweeps a sphere along a line instead of an infinitely thin ray, useful for thick projectiles, character probes, or “is there room here” checks. Build an SSphereCastSettings (the same fields, plus a Radius) and call World.Physics:SphereCast, which returns an array of every body the sphere touches along the sweep:

local Settings = SSphereCastSettings.new()
Settings.Start = From
Settings.End = To
Settings.Radius = 0.5
for _, Hit in ipairs(World.Physics:SphereCast(Settings)) do
print("swept into", Hit.Entity)
end

Each element is an SRayResult with the same fields as a raycast hit.

Define any of these on your script to be notified. The payload is a SCollisionEvent, annotate it for autocomplete on its fields.

Contacts are solid collisions. Overlaps are triggers, a collider with its trigger flag set, or a rigid body marked as a sensor, which produces overlap events but no physical response.

function Script:OnContactBegin(Event: SCollisionEvent)
print("hit", Event.Other, "at", Event.ImpactSpeed, "m/s")
end
function Script:OnContactEnd(Event: SCollisionEvent) end
function Script:OnOverlapBegin(Event: SCollisionEvent) -- entered a trigger
print("entered trigger of", Event.Other)
end
function Script:OnOverlapEnd(Event: SCollisionEvent) end

The SCollisionEvent fields, all read from your entity’s point of view:

FieldMeaning
EntityYour entity
OtherThe other entity
PointWorld-space contact point (vector)
NormalContact normal, pointing away from you (vector)
Velocity / OtherVelocityLinear velocities at contact (m/s)
RelativeVelocityOther minus self (vector)
ImpactSpeedSpeed along the normal (m/s)
bIsTriggertrue if the other side was a trigger or sensor
BodyID / OtherBodyIDThe Jolt body ids

The engine type behind the callback:

struct SCollisionEvent
{
uint32 Entity, Other; // this entity, the other entity
uint32 BodyID, OtherBodyID; // Jolt body ids
FVector3 Point; // world-space contact point
FVector3 Normal; // away from self, toward the other body
FVector3 Velocity, OtherVelocity, RelativeVelocity;
float ImpactSpeed; // speed along the normal
bool bIsTrigger; // true if the other side was a trigger
};