Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

MeshCollider (component)

Collision against mesh geometry. There are no size fields: the collider is the mesh, scaled by the entity's transform.

The two fits

fitShapeBodiesConcavity
"hull" (default)Convex hull of the mesh's pointsStatic and dynamicFilled in, so a doorway becomes a slab
"exact"The mesh's own trianglesStaticFollowed exactly

"exact" is for static bodies because a triangle mesh is a surface with no interior: rapier cannot derive a mass tensor from one, and a dynamic body built from it would fall through everything it touched. Setting fit = "exact" on a dynamic body raises an error naming "hull" rather than quietly substituting it.

Choosing the geometry

mesh names the asset to collide against. Left unset, the collider tracks whatever mesh the entity renders, including a later swap. Set it to collide against a cheaper proxy than the one on screen, which is the usual move for detailed scenery where the visual mesh carries far more triangles than collision needs.

entity.find("rock").component.add("MeshCollider", {})                          -- what you see
entity.find("level").component.add("MeshCollider", { fit = "exact" })          -- concave, static
entity.find("rock").component.add("MeshCollider", { mesh = "rock_collision" }) -- cheap proxy

Because mesh is an asset reference, a collision proxy is visible to the asset graph and survives a rename.

The collider follows the mesh's geometry. renderer.mesh.setVertices or renderer.mesh.update on the mesh it is built from rebuilds it by the next physics step, in edit mode and in play, once per changed mesh per frame however many times the mesh was written, and bodies asleep on it or within its reach wake. An edit is a new shape rather than a moving one, so it gives what touches it no velocity; the physics guide states what a rebuild costs.

The collider loads the mesh it names itself, so an entity that draws nothing collides all the same: an invisible wall, a trigger volume shaped like a mesh, a level whose collision is a separate simplified mesh. The engine keeps that mesh loaded for as long as a collider names it.

local wall = entity.spawn("invisibleWall")
wall.component.add("Physics", { kind = "static" })
wall.component.add("MeshCollider", { mesh = "@builtin::meshes.torus", fit = "exact" })

While a collider cannot be built, Physics.bodyState(entity) reads exists = false with waitingFor naming what it is waiting for, and a wait that lasts more than two seconds is logged as a warning naming the mesh.

Cost

Built shapes are shared: every collider asking for the same mesh, fit and scale gets the one built shape, so a field of a hundred identical rocks pays for one hull rather than a hundred.

Fields

FieldMeaning
meshMesh asset to collide against. Unset tracks the entity's renderable.
fit"hull" or "exact".
isTriggerReport overlaps without blocking.
frictionSurface friction.
restitutionBounciness.
rollingResistanceHow strongly the surface resists a body rolling on it: a rolling body slows at this many times gravity on level ground, so a ball rolled at v stops after v^2 / (2 * rollingResistance * 9.81). 0 rolls on.
spinningResistanceThe same for a body spinning on the surface about the contact normal. 0 spins on.
surfaceThe surface the collider is made of, by name: one Physics.defineSurface defined gives it its friction, restitution and resistances in place of the fields above, and contacts, contact events and ray and shape casts report the name either way. Empty names none.
oneWayThe direction, in the collider's own frame, bodies pass through it along: a body moving that way goes through, and a body meeting it from the side the direction points to stands on it (a jump-through platform is {0, 1, 0}). Physics.passThrough(entity) drops a standing body through. Unset blocks from every side.
surfaceVelocityThe velocity, m/s in the collider's own frame, its surface moves at along itself while the collider stays put: friction carries what rests on it (a conveyor belt, a treadmill, an escalator). Write it at runtime to change the speed or direction. Unset holds the surface still.
contactTagThe tag the world's contact filter reads this collider by: Physics.setContactFilter(tagA, tagB, mode) makes two tags pass through each other ("ignore"), report contacts and push nothing ("sensor") or collide ("solid"). Empty names none.