Colliders
Last updated
Last updated
Colliders define invisible 3-dimensional shapes that can collide. They can be attached to an entity or rigid body for hitboxes and relative sensors, or added directly to a world for things like an invisible wall, and much more.
Colliders can have a defined shape, bounciness, friction, mass, relative positioning & rotation to their parent, collision callbacks, and more. These properties together are partly responsible for how physical interactions in a game will happen.
By default, colliders will collide with other colliders when the HYTOPIA engine calculates physics each tick. You can make colliders not collide with each other and only sense intersections by using .
Collider creation starts with collider options. Whether you're creating a standalone collider, a block type with custom collider options, or a collider as a child of an entity or rigid body (most common), you'll want to get familiar with collider options.
Collider options define things like the colliders shape, dimensions, and how it interacts with the world upon colliding with something.
Here's a list of available collider options, you can find the most up-to-date list in the ColliderOptions API Reference here.
borderRadius?
number
(Optional) The border radius of the collider if the shape is a round cylinder.
bounciness?
number
(Optional) The bounciness of the collider.
bouncinessCombineRule?
CoefficientCombineRule
(Optional) The bounciness combine rule of the collider.
collisionGroups?
CollisionGroups
(Optional) The collision groups the collider belongs to.
enabled?
boolean
(Optional) Whether the collider is enabled.
friction?
number
(Optional) The friction of the collider.
frictionCombineRule?
CoefficientCombineRule
(Optional) The friction combine rule of the collider.
halfExtents?
Vector3Like
(Optional) The half extents of the collider if the shape is a block.
halfHeight?
number
(Optional) The half height of the collider if the shape is a capsule, cone, cylinder, or round cylinder.
indices?
Uint32Array
(Optional) The indices of the collider if the shape is a trimesh.
isSensor?
boolean
(Optional) Whether the collider is a sensor. Sensors do not collide, allow intersections of other colliders for collision callbacks.
mass?
number
(Optional) The mass of the collider.
onCollision?
CollisionCallback
(Optional) The on collision callback for the collider.
parentRigidBody?
RigidBody
(Optional) The parent rigid body of the collider.
radius?
number
(Optional) The radius of the collider if the shape is a ball, capsule, cone, cylinder, or round cylinder.
relativePosition?
Vector3Like
(Optional) The relative position of the collider. Relative to parent rigid body.
relativeRotation?
QuaternionLike
(Optional) The relative rotation of the collider. Relative to parent rigid body.
shape
ColliderShape
The shape of the collider.
simulation?
Simulation
(Optional) The simulation the collider is in, if provided the collider will automatically be added to the simulation.
tag?
string
(Optional) An arbitrary identifier tag of the collider. Useful for your own logic.
vertices?
Float32Array
(Optional) The vertices of the collider if the shape is a trimesh.
Here are some examples of how we use collider options to define colliders in different contexts.
Creating an entity with a custom collider.
const myEntity = new Entity({
modelUri: 'models/npcs/spider.gltf',
rigidBodyOptions: { //
colliders: [ // Array of collider options, results in a created collider when spawned
{
shape: ColliderShape.ROUND_CYLINDER,
borderRadius: 0.1,
halfHeight: 0.225,
radius: 0.5,
mass: 1, // if not provided, automatically calculated based on shape volume.
bounciness: 10, // very bouncy!
relativePosition: { x: 1, y: 0, z: 0 } // acts like an offset relative to the parent.
},
]
}
});
myEntity.spawn(world, {. x: 0, y: 1, z: 0 });
Creating a block type with custom collider options.
const myBlockType = new BlockType({
id: 123,
name: 'My Custom Block',
textureUri: 'blocks/dirt.png',
// block types are special, we cannot provide a shape or shape related
// collider options since they will be overriden and forced to a trimesh.
// with a 1x1x1 shape. We can however set things like friction, bounciness,
// etc.
customColliderOptions: {
friction: 100, // Very high friction block, acts "sticky"
}
});
Creating a standalone collider as an invisible wall with a callback when entities touch it
const myCollider = new Collider({
shape: ColliderShape.BLOCK,
halfExtents: { x: 1, y: 10, z: 10 },
// When not a child of rigid body,
// relative position is relative to the world,
// equivalent to a typical world position.
relativePosition: { x: 20, y: 0, z: -5 }
onCollision: (other: BlockType | Entity, started: boolean) => {
if (started) {
console.log('something touched!');
} else {
console.log('something stopped touching!');
}
}
});
myCollider.addToSimulation(world.simulation);
Creating a standalone sensor collider with a callback when an entity enters and exits the collider with their own collider.
const mycollider = new Collider({
shape: ColliderShape.BLOCK,
halfExtents: { x: 1, y: 10, z: 10 },
isSensor: true,
// When not a child of rigid body,
// relative position is relative to the world,
// equivalent to a typical world position.
relativePosition: { x: 20, y: 0, z: -5 }
onCollision: (other: BlockType | Entity, started: boolean) => {
if (started) {
console.log('something touched or entered/intersected!');
} else {
console.log('something stopped touching or exited/unintersected!');
}
}
});
myCollider.addToSimulation(world.simulation);