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(Entity, new FVector3(0, 5, 0));
FVector3 Velocity = World.Physics.GetLinearVelocity(Entity);

The entity needs a Rigid Body for body methods to do anything. Calls on a body-less entity are safe (mutators no-op, getters return zero).

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, v)Replace linear velocity (m/s)
SetAngularVelocity(entity, v)Replace angular velocity (rad/s)
GetLinearVelocity(entity) / GetAngularVelocity(entity)Read it back (FVector3)
GetVelocityAtPoint(entity, point)Velocity of a world point on the body
MethodReturns / effect
GetBodyPosition(entity) / GetBodyRotation(entity)The true physics pose
GetCenterOfMass(entity)World-space center of mass
GetBodyId(entity)The Jolt body id (0xFFFFFFFF if no body)
ActivateBody(entity) / DeactivateBody(entity)Wake or sleep the body
SetGravityFactor(entity, factor)Per-body gravity multiplier (0 = float, 1 = normal)

A raycast shoots a line through the world and returns the first thing it hits, the workhorse behind shooting, line of sight, ground checks, and interaction. Pass an origin, a direction (normalized for you), and a distance. The result is a RaycastHit?, null when nothing is hit. Pass an entity to Ignore to skip its body (usually the caster’s own).

FVector3 From = Transform.GetWorldLocation();
FVector3 Dir = Transform.GetForward();
RaycastHit? Hit = World.Physics.Raycast(From, Dir, 100.0f, Ignore: Entity);
if (Hit is RaycastHit H)
{
Debug.Log($"hit {H.Entity} at {H.Point}");
}

The RaycastHit fields.

FieldMeaning
EntityThe entity that was hit
PointThe world-space hit point (FVector3)
NormalThe surface normal at the hit (FVector3)
DistanceDistance from the origin to the hit
FractionHow far along the ray the hit is, 0 at the origin, 1 at the end
BodyIdThe Jolt body id that was hit

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. It returns every hit, sorted near-to-far.

RaycastHit[] Hits = World.Physics.SphereCast(From, Dir, 100.0f, Radius: 0.5f, Ignore: Entity);
foreach (RaycastHit Swept in Hits)
{
Debug.Log($"swept into {Swept.Entity}");
}

An overlap returns every entity whose body intersects a shape right now, the core AI-perception, area-of-effect, and trigger primitive.

// Everything within 5m, excluding ourselves.
Entity[] Nearby = World.Physics.OverlapSphere(Transform.GetWorldLocation(), 5.0f, Ignore: Entity);
// An oriented or axis-aligned box.
Entity[] InBox = World.Physics.OverlapBox(center, halfExtents, rotation, Ignore: Entity);

Each query is capped at Physics.MaxQueryResults (256). For per-frame queries, the OverlapSphere overload that writes into a caller Span<uint> avoids the array allocation.

A rigid body publishes its contacts and overlaps as events you bind a handler to. Cache the SRigidBodyComponent with [RequireComponent] and bind in OnReady. The payload is an SCollisionEvent, oriented from your entity’s point of view.

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

public sealed class Mine : EntityScript
{
[RequireComponent] private SRigidBodyComponent _Body = null!;
public override void OnReady()
{
_Body.OnContactBegin.Bind(OnHit);
_Body.OnOverlapBegin.Bind(OnEnterTrigger);
}
private void OnHit(SCollisionEvent Event)
{
Debug.Log($"hit {Event.Other} at {Event.ImpactSpeed} m/s");
}
private void OnEnterTrigger(SCollisionEvent Event)
{
Debug.Log($"entered trigger of {Event.Other}");
}
}

The full set is OnContactBegin / OnContactEnd and OnOverlapBegin / OnOverlapEnd (each carrying an SCollisionEvent), plus the payload-free OnWake / OnSleep (bound with a plain Action). Bind returns a DelegateBinding, but a script’s bindings are removed for you when it detaches, so you only need to keep it when you want to Unbind() early.

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

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

World.SpawnProjectile fires a lightweight projectile entity. It sweeps forward every frame with a continuous raycast, so it never tunnels through thin walls, reports its first hit, and despawns after its lifetime. This is far cheaper than a full rigid body and runs entirely in the ECS.

public sealed class Gun : EntityScript
{
private void Fire(FVector3 muzzle, FVector3 aim)
{
Entity shot = World.SpawnProjectile(muzzle, aim * 60.0f, damage: 25.0f, lifetime: 5.0f);
World.Registry.Get<SProjectileComponent>(shot).OnHit.Bind(OnProjectileHit);
}
private void OnProjectileHit(SProjectileHitEvent hit)
{
Debug.Log($"hit {hit.HitEntity} at {hit.Point} for {hit.Damage}");
}
}

The full overload also takes an instigator entity that the sweep ignores, so a projectile never hits whoever fired it: World.SpawnProjectile(origin, velocity, damage, lifetime, instigator).

Tune the spawned SProjectileComponent (or add it to an entity yourself in the editor, under Gameplay).

FieldMeaning
VelocityWorld-space velocity (m/s)
GravityScaleMultiplier on world gravity; 0 = a straight line
RadiusSweep radius; 0 = a thin ray, larger for a fatter projectile
DamageCarried in the hit event; you decide how to apply it
CollisionMaskWhich collision layers it can hit
bDestroyOnHitDestroy the projectile on its first hit
InstigatorEntity the sweep ignores (the shooter)
OnHitFired once on hit, with an SProjectileHitEvent

SProjectileHitEvent carries Projectile, HitEntity, Point, Normal, and Damage. The same API is available from C++ as CWorld::SpawnProjectile.