Not translated yet — showing English.
Collision
Bind a transform to the obstacle map; declare what contact does. Collision runs inside the platform's simulation. You declare bodies, layers and responses, and subscribe to contacts.
When to use it
- Moving entities must resolve contacts server-side (slide, stop, bounce) without a hand-written deflection routine.
- Gameplay reacts to touch: pickups collect on overlap, trigger volumes fire an entity state machine.
- Locomotion and projectiles need swept resolution against the map's obstacle set.
- Placement previews or targeting need "would this fit here?" and volume-overlap queries.
- Skip it when nothing physically meets. Request/response gameplay over records is plain Data.
Who does what
| Actor | On this page |
|---|---|
room-owner | declares bodies, layers and responses; queries overlaps and contacts |
Which rooms this applies to
This module runs where the platform steps the simulation: rooms declared Host = "Backend". If your own game server owns the simulation (PlayServ as the metaserver), movement, collision and prediction stay engine-side, and this page describes the platform-hosted alternative rather than a requirement.
At a glance
Shape, layer and what contact does all sit on the body itself — nothing declares layer pairs from a distance:
Body on the tank: vehicles layer — sliding off walls, passing through pickups, crates decided per contact[Entity("tank")]
public class Tank
{
[Sync] public Vector3 Position;
[Body(Shape.Capsule, Radius = 0.6f, Layer = "vehicles")]
[CollidesWith("walls", Response.Slide)]
[CollidesWith("pickups", Response.Pass)] // reported, motion passes through
public Body Body;
}@Entity('tank')
export class Tank {
@Sync() position!: Vector3;
@Body({ shape: 'capsule', radius: 0.6, layer: 'vehicles' })
@CollidesWith('walls', Response.Slide)
@CollidesWith('pickups', Response.Pass) // reported, motion passes through
body: Body;
}@entity("tank")
class Tank:
position: Vector3 = sync()
body = collision.body(shape="capsule", radius=0.6, layer="vehicles",
collides_with=[
("walls", Response.SLIDE),
("pickups", Response.PASS), # reported, motion passes through
])Attribute-style declaration in Go is still open (O-1) — the samples land when the carrier is decided.
// the declaration rides inside the engine's own reflection macros, in the specifier position —
// UHT reads it from the header text, and the member is a reflected property at the same time
UCLASS(PSEntity = "tank")
class UTank : public UObject
{
GENERATED_BODY()
UPROPERTY(PSSync)
FVector3f Position;
// walls slide, pickups report the contact and let motion pass through —
// multi-entry values are one quoted list (a specifier value is a single token)
UPROPERTY(PSBody = (Shape = "Capsule", Radius = "0.6", Layer = "vehicles"),
PSCollidesWith = "walls:Slide, pickups:Pass")
FPSBody Body;
};
// declarations compile into the same pushed model — playserv push from the UE project or CI[Entity("tank")]
public class Tank
{
[Sync] public Vector3 Position;
[Body(Shape.Capsule, Radius = 0.6f, Layer = "vehicles")]
[CollidesWith("walls", Response.Slide)]
[CollidesWith("pickups", Response.Pass)] // reported, motion passes through
public Body Body;
}A contact is an event, and modules subscribe to it. There is no hook on a contact: by the time one exists the step has already resolved it, so there is nothing left to reject. Where a studio needs different rules, it overrides the admissibility and path checks as an implementation — see Extensibility — and the response stays declared.
The model
What a body declares.
| Declares | What it is |
|---|---|
shape | a primitive from a closed set — sphere, capsule, box — with declared dimensions. An arbitrary mesh is not on offer, the same constraint and the same reason as the server's world model in map |
where it lives | on an aspect, together with the transform: that is the unit of policy, and a body shares one fate with its transform |
how its path is checked | stepwise: the step's final position is checked; fast. swept: the segment between positions is checked; more expensive, and tunnelling is excluded within a step. Declared, never chosen by an implementation from the speed |
areas it participates in | which volumes it is counted inside |
its relation to the art model | none is required: a body is a simplification, and divergence from the art model is admissible within declared bounds |
A fast stepwise body passes through thin obstacles
stepwise checks only where a step ends, so a fast body can pass through a thin obstacle. swept checks the segment between positions and excludes tunnelling within a step. Whether a projectile can fly through a wall is a property of your game, and you declare it.
The response is declared on a pair — an obstacle's passability kind × a body type — and it comes from a closed set:
| Response | What it means |
|---|---|
stop | movement ceases at the last admissible position |
slide | movement continues along the obstacle by whatever component is admissible |
bounce | the direction is reflected and the speed multiplied by a declared coefficient |
damp | movement continues with the speed multiplied by a declared fraction |
pass | the obstacle does not affect movement, but the contact is still observable |
cease to exist | the entity ends — a projectile against a wall |
The coefficients are declared values rather than computed from masses and materials — there are neither in this contract.
What is true of every check.
| Always | What it is |
|---|---|
every pair | has a response: a missing pair is a declaration defect, refused at deploy rather than met in combat |
the response table | is readable by the client: the same table the authority computes by, so a client and a server given one declaration answer one contact the same way |
reproducible within one authority, not across platforms | the same input in the same order gives the same result within one process and one build. Bit-identical results on different platforms and builds are not promised |
simultaneity | is declared: when two moving bodies collide inside one step the order of resolution is declared and deterministic. The storage traversal order, the order input arrived and randomness may not be the ground for it |
one contact, one fact | a contact between two bodies is observable by both sides as a single fact with a single identifier, not as two independent events |
extension points sit on the step, not on a contact | before the step the transform may be changed, after it there is observation. An override of the admissibility and path checks must also be available to the client |
the module | moves nothing itself: it answers whether a position is admissible and what the response is; applying that is locomotion's |
a contact is an event | which is why modules subscribe rather than couple: a trap's state machine binds a transition to a trigger-volume entry, drops collects on overlap, and projectiles resolve hits through this module's sweep |
Errors
- "Inadmissible" is an answer, not an error, and it names which of three reasons: outside the bounds, occupied by a static obstacle, or occupied by another entity's body. A client reacts to the three differently: turn round, go round, or wait.
- Declaration failures land at deploy, never on the first contact: a body shaped outside the closed set, a body on an aspect with no transform, and a pair with no declared response are all refused at deploy.
- The entity or the location is not found answers not found, and repeating is pointless.
- The check rate exceeded answers in the rate-limit category, with the deadline before which a retry is pointless.
Limits
The numbers arrive with the platform limits chapter; what happens at each ceiling is fixed now.
- Bodies in a room: declaring another is refused as a conflict; existing bodies are never removed to make room.
- Contacts per step: the excess is never discarded silently. Either the step is refused, or the order of cut-off is declared.
- A body's size against the map's grid step: refused at deploy, because a body smaller than the height field's step falls through the terrain.
- Areas one body may be inside: an excess is refused at deploy.
- The check rate per actor: a rate limit with a deadline.
- Bodies in a "who is in this area" answer: truncated by a declared order, and the truncation flag is obligatory.