Colliders
Most game entities can declare their authoritative shape and layer in YAML. Golem then registers the collider when the entity spawns and removes it when the entity leaves, so gameplay code only chooses and enables the collision backend.
This page covers the 2D collision backends. For 3D projects using CollisionSphere or CollisionAABB3D, see 3D collision.
Declare layers and shapes
Section titled “Declare layers and shapes”Define the project matrix in golem.yaml:
collision: layers: [Player, Enemy, Wall, Projectile] collides: - [Player, Wall] - [Enemy, Wall] - [Projectile, Enemy] - [Projectile, Wall]Then add one shape to each entity type that participates:
entity: Playercollider: aabb: [0.6, 1.8] layer: Playervars: health: { tag: 1, type: int32 }Run golem-bake after changing either file. Pairs in collides are symmetric, self-pairs are supported, and up to 32 named layers can be defined. Invalid shapes, unknown layers, and duplicate pairs fail during baking.
Enable collision
Section titled “Enable collision”Choose a backend and give it to the generated runtime before restoring snapshots or creating collidable entities:
backend := collisioncp.New()srv, rt := generated.NewServer(config)rt.EnableCollision(backend)EnableCollision binds the backend, creates the named matrix as rt.Layers, and enables automatic shape lifecycle on srv. It panics immediately for a nil backend. Generated colliders are present when the entity’s OnSpawn runs and are already removed when OnRemove runs.
The optional trigger: true property reports overlaps without requesting push-out; contact Depth is always 0. Use triggers for pickups and damage zones.
Available shapes
Section titled “Available shapes”| Type | Fields | Description |
|---|---|---|
golem.CollisionCircle | R float64 | Circle centred on the entity’s position |
golem.CollisionAABB | W, H float64 | Axis-aligned bounding box centred on the entity’s position |
Override or register shapes manually
Section titled “Override or register shapes manually”A gameplay wrapper inherits the generated Collider() method. Override it when one wrapper needs a different initial shape:
func (p *Player) Collider() (golem.CollisionShape, string, bool) { return golem.CollisionCircle{R: 0.5}, "Player", false}Entities without schema colliders can still use rt.Layers.Add in OnSpawn and rt.Layers.Remove in OnRemove. This is useful when shape selection depends on runtime data.
Prefab geometry without entities
Section titled “Prefab geometry without entities”World-streamed walls and decorations may need server collision without registry state or replication. Unity projects can mark those prefabs with GolemFootprint, export their supported colliders through Golem Scribe, and place them through golem/footprint from the server’s matching streaming logic. Each shape receives a negative collision-only ID and is removed through the returned placement handle.
Changing a collider at runtime
Section titled “Changing a collider at runtime”To replace an entity’s shape or trigger flag without removing it from the game, use rt.Layers.Set:
// Shrink the player's hitbox while crouching.rt.Layers.Set(player.EntityID(), golem.CollisionAABB{W: 0.6, H: 0.9}, "Player", false)
// Restore the standing shape.rt.Layers.Set(player.EntityID(), golem.CollisionAABB{W: 0.6, H: 1.8}, "Player", false)Set preserves the entity’s current position. If the entity is not registered when Set is called, it is a no-op; call Add first.
Spatial queries
Section titled “Spatial queries”Layer, Mask, and MaskFor are still available when you need raw bitmask values for spatial queries:
ids := srv.OverlapCircle(x, y, 200, rt.Layers.MaskFor("Enemy"))hit, ok := srv.Raycast(x1, y1, x2, y2, rt.Layers.MaskFor("Wall", "Enemy"))Raw bitmasks: if you prefer not to use
CollisionLayers, plainuint32constants work fine. The underlying filter is just(A.layer & B.mask) != 0.CollisionLayersis a helper that derives and cross-checks those values for you.
Previous: Collision & physics. Next: Contacts & events, 3D collision.