Generic Component Access
When using Context.query() to find game objects by tag, you get back generic objects where you don’t know the specific type. Unit modules provide a type-safe way to access component methods on these generic objects.
Using Existing Unit Modules
Section titled “Using Existing Unit Modules”Many components in the library provide a Unit module that you can use when querying for objects by tag. For example, if you need to access position methods on generic objects:
let getMovableObjects = (k: Context.t): array<Pos.Unit.t> => { k ->Context.query({ include_: ["movable"], hierarchy: Descendants, }) ->Array.filterMap(Pos.Unit.fromGameObj)}
// Now you can call Pos methods on generic objects:let getObjectPosition = (obj: Pos.Unit.t) => { let worldPos = obj->Pos.Unit.worldPos // ... use worldPos ...}The fromGameObj() function performs a runtime check to ensure the object has the required component, then safely casts it to the Unit type.
Combining Multiple Components
Section titled “Combining Multiple Components”When you need multiple components together on generic objects, create a custom combined module in your game code:
module Collidable = { module Unit = { type t include GameObjRaw.Comp({type t = t}) include Pos.Comp({type t = t}) include Area.Comp({type t = t})
let fromGameObj = (obj: GameObjRaw.Unit.t): option<t> => { if obj->has("pos") && obj->has("area") { Some(Obj.magic(obj)) } else { None } } }}
// Usage:let getCollidables = (k: Context.t): array<Collidable.Unit.t> => { k ->Context.query({ include_: ["collidable"], }) ->Array.filterMap(Collidable.Unit.fromGameObj)}
// Now you can use both Pos and Area methods:let checkCollision = (obj: Collidable.Unit.t, point: Vec2.World.t) => { let worldPos = obj->Collidable.Unit.worldPos obj->Collidable.Unit.hasPoint(point)}This approach:
- Domain-specific: Tailored to your use case
- Composable: Uses the same
includepattern as regular game objects - Type-safe: You get all methods from all included components
- Flexible: Easy to add more components later
This pattern enables powerful abstractions for spatial queries, rule systems, and other scenarios where you need to work with objects generically.