Physics
You can add physics to your game by adding the RigidBody component to your objects. See the documentation for RigidBody for details. Under the hood, it uses Jolt Physics.
Physics updates run in the same thread as logic. It has its own FPS, but tries to catch up with logic frames by simulating multiple sub-frames. Keep the following in mind:
You can set and get physical properties of actual physical bodies directly in the code. The changes will be applied immediately.
There are two types of external forces: continuous (force, torque) and singular (impulse). Continuous forces should be called every update and are applied at every physics sub-frame for the duration of an update.
Physics is provided by the engine.physics_core module, which is part of the engine.core module.
Physics is represented by components:
RigidBody - the main component that enables physics for objects.
Generic collider - a necessary component that represents a generic shape for physics. It can represent one or many shapes.
Joints - joints that connect two
RigidBodyobjects. Currently, only the simplest joints are available.Character - moves humanoid-like creatures with user-provided input
You can query the scene with traces and overlaps:
Raycasts: trace(RayCast), trace_all(RayCast)
SweepTest: sweep_test(NodeCast)
ShapeCasts:
Overlap with other objects (scene queries): overlap(BoxQuery), overlap(SphereQuery), overlap(CapsuleQuery)
You can also detect collisions between bodies with on_collision, on_collision_stay, on_collision_exit
With these global functions, you can also:
Apply forces and impulses to a rigid body: apply_rigid_body_impulse, apply_rigid_body_impulse, apply_rigid_body_angular_impulse, apply_rigid_body_force, apply_rigid_body_force, apply_rigid_body_torque
Get the local velocity of a body at any given point: get_rigid_body_velocity_at
Set up or disable gravity globally: set_gravity, get_gravity
Set up collision between physics layers: set_collision_layer_mask, set_collision_between_layers
Set default values for new physics bodies: set_default_friction, get_default_friction, set_default_restitution, get_default_restitution
Set up physics fixed frames-per-second: set_physics_fps, get_physics_fps
Friction and Damping Tweaking Guide
To simulate the loss of velocity of a body, the physics engine uses three parameters: friction, damping, and angularDamping.
These parameters represent two main concepts: friction and damping.
They both contribute to the result, so don’t forget to set them both.
Friction
A linear decrease in body speed when it is in contact with another body.
Setting friction values can be tricky. For simple games, consider setting friction = -1 for all bodies to use the default friction, and then set the desired friction with set_default_friction().
Note that friction is not calculated using the friction value of a single body, but with the Combined Coefficient of Friction (COF). The COF is calculated as:
Combined Coefficient of Friction = sqrt(friction_of_body_1 * friction_of_body_2)
Consider these values as guides to choose your own friction:
Body 1 |
Body 2 |
Combined Coefficient of Friction (approx.) |
|---|---|---|
Rubber, Tires |
Asphalt (dry) |
1.0 |
Rubber, Tires |
Asphalt (wet) |
0.3 |
Rubber, Tires |
Ice |
0.15 |
The COF can be determined in different scenarios:
Sliding Friction: If you know the time or distance it takes for a body to stop sliding on a horizontal surface, you can calculate the COF using the formulas:
Combined Coefficient of Friction = starting_velocity_of_body_1 / (strength_of_the_gravity * time_before_body_1_stops)or
Combined Coefficient of Friction = (starting_velocity_of_body_1)^2 / (2 * strength_of_the_gravity * distance_before_body_1_stops)Static Friction: To prevent a body from sliding on a slope, the COF should be greater than or equal to the tangent of the slope angle:
Combined Coefficient of Friction >= tan(angle_of_the_slope)Rolling Friction: There is no special implementation of rolling friction. When a body is rolling, the friction value only matters if the COF is too low, allowing the body to slide instead of roll. Otherwise, the body will move as if there is no friction, and the only velocity loss is due to damping.
Damping
An exponential decrease in body speed at every frame.
This can be used to add damping to a spring, or to decrease the speed of a moving body over time.
The damping value should be 0 or more, with higher values causing faster velocity loss.
Every frame, the velocity of a body is multiplied by (1 - damping * frame_time). This can be expressed with the formulas:
v(t) = v_0 * e^(-damping * t)x(t) = x_0 + v_0 * (-1 / damping) * (e^(-damping * t) - 1)
The body will travel a distance of v_0 / damping and reach half that distance in ln(2) / damping seconds.
To select the appropriate damping value, choose the desired distance the body should travel from a given initial velocity, and calculate the damping using the formula:
Damping = initial_velocity_of_a_body / distance_that_it_should_travel
The angularDamping works the same way as damping, but it affects the rotation of the body.
Physics Simulation in the Main Loop
See Main Loop
Physics Simulation
Simulate several physics frames
Physics calculations require precision, which is achieved by running multiple physics frames for a single logic frame, with a fixed FPS (see set_physics_fps()).
The overall principle is that the physics simulation tries to keep up with the logic. For example, if the logic simulates at 30FPS and the physics at 60FPS, there will be 2 frames of physics simulation for each logic frame.
Conversely, if the logic simulates at 30FPS and the physics at 15FPS, there will be logic frames with no physics update (every second logic frame in this case).
Collision callbacks
If there are any collisions, the corresponding callbacks are called in random order (in the order in which the simulation registers those collisions): on_collision(), on_collision_stay(), on_collision_exit().
If a node has both an on_collision() callback and a child component that is a CollisionListener component, the callbacks will be received in the order in which those components were added.
Type aliases
- bitfield AllowedDofs : uint8
Allowed degrees of freedom for a body component (Dofs = degrees of freedom)
- Fields:
AllowTranslationX (0x1) - Allow translation along the X axis
AllowTranslationY (0x2) - Allow translation along the Y axis
AllowTranslationZ (0x4) - Allow translation along the Z axis
AllowRotationX (0x8) - Allow rotation around the X axis
AllowRotationY (0x10) - Allow rotation around the Y axis
AllowRotationZ (0x20) - Allow rotation around the Z axis
AllowedDofsAll (0x3f) - All degrees of freedom allowed
AllowedDofs2D (0x23) - 2D degrees of freedom allowed
Constants
- MAX_PHYS_LAYER = 31
Maximum value for a collision layer
Enumerations
- CharacterState
The return value of the CharacterController.state and the state of a character’s contacts.
- Values:
OnGround = 0 - The character is standing firmly on the ground. Consider to allow jumping in this state only.
OnSteepGround = 1 - The character is standing on a steep slope, or touching a wall. The character cannot stay still and should slide down by adding the gravity to the character’s velocity.
NotSupported = 2 - The character is touching something, but not standing on it (hence “not supported by the ground”). Most likely it’s touching a ceiling. For most uses, it is like InAir.
InAir = 3 - The character is not touching anything.
- AxisDirection
Axis direction for capsule and cylinder colliders
- Values:
XAxis = 0 - X-Axis
YAxis = 1 - Y-Axis
ZAxis = 2 - Z-Axis
- CollisionDetection
Whether the body should integrate using Continuous Collision Detection (CCD) or not. See also Jolt Documentation
The discrete collision detection is the default method, and is faster but less precise, as it may not detect all collisions that occur between two objects.
The continuous collision detection method is more precise, as it can detect fast-moving objects passing through stationary thin objects. It works by casting the shape of a body in the direction of movement and checking for collisions along the way. This method is more computationally heavy but provides more accurate results.
- Values:
Discrete = 0 - Discrete integration
Continuous = 1 - Use Continuous Collision Detection
- Interpolation
Interpolation of a visual position of a body
None - No interpolation is performed, resulting in a visual jitter for fast-moving objects.
Extrapolate - The body’s visual position is predicted based on its previous movements, creating a smoother and more realistic appearance. However, this method can be less accurate for objects that change velocity often.
Interpolate - The body’s position and rotation are calculated based on its previous movements, but with a small lag in their movement. This method is more precise than Extrapolate, but may introduce a small lag to the body movement.
- Values:
None = 0
Interpolate = 1
Extrapolate = 2
- MotionType
Whether the body should be static, dynamic, or kinematic.
A Dynamic body reacts to collisions, has mass and velocity, and can be affected by gravity and other forces.
A Kinematic body has velocity but has no mass and does not react to collisions. Other objects can respond to these collisions, but the kinematic body will continue to move as if it were unaffected by the collision.
Note that to create a static, non-moving body you should only add Collider component. RigidBody component adds movement to the object.
- About collision callbacks:
When receiving collision callbacks with other bodies through the on_collision function or the CollisionListener component, the cheapest option would be a
Collider-only (static) body. However, a static body cannot detect collisions with other static bodies, and to detect collisions withKinematicbodies, it needs to be a sensor (see RigidBody.isSensor). If these limitations are unacceptable, consider using theKinematicorDynamicmotion type. Despite the fact thatKinematicbodies do not react to collisions, they will generate collision callbacks.Also, note that a
Dynamicbody will generate an exit event if it would go to sleep while inside a sensor. This is because sleeping bodies exit the simulation until something collides with them (the sensor does not count).In any case, you can always use the overlap function for a less cheap but more reliable collision handling.
- Values:
Dynamic = 0 -
DynamicbodyKinematic = 1 -
Kinematicbody
Structures
- RayCast
Represents a raycast request.
- Fields:
ray : Ray - The ray that will be casted
maxDistance : float = FLT_MAX - The maximum distance the ray can travel
collisionMask : uint = UINT_MAX - The collision mask to use for filtering collisions
- NodeCast
Represents a ShapeCast request with the shape of the node. ShapeCast is like raycast, but it doesn’t seep through small holes.
- Fields:
nodeId : NodeId - The node whose shape will be used for the cast
from : float3 - The starting position of the cast
to : float3 - The ending position of the cast
collisionMask : uint = UINT_MAX - The collision mask to use for filtering collisions
- BoxCast
Represents a ShapeCast request with a box shape. ShapeCast is like raycast, but it doesn’t seep through small holes.
- Fields:
position : float3 - The position of the box
size : float3 = float3(1f,1f,1f) - The lengths of sides of the box
rotation : quat4 = quat4() - The rotation of the box
rayDirection : float3 - The direction of the cast
maxDistance : float = FLT_MAX - The maximum distance the cast can travel
collisionMask : uint = UINT_MAX - The collision mask to use for filtering collisions
- SphereCast
Represents a ShapeCast request with a sphere shape. ShapeCast is like raycast, but it doesn’t seep through small holes.
- Fields:
position : float3 - The position of the sphere
radius : float = 0.5f - The radius of the sphere
rayDirection : float3 - The direction of the cast
maxDistance : float = FLT_MAX - The maximum distance the cast can travel
collisionMask : uint = UINT_MAX - The collision mask to use for filtering collisions
- CapsuleCast
Represents a ShapeCast request with a capsule shape. ShapeCast is like raycast, but it doesn’t seep through small holes.
- Fields:
position : float3 - The center of the capsule
height : float = 2f - The full height of the whole capsule (including the spherical caps)
radius : float = 0.5f - The radius of the spherical caps
axis : AxisDirection = public_components::AxisDirection.YAxis - The axis of the orientation of the capsule
rotation : quat4 = quat4() - The additional orientation of the capsule
rayDirection : float3 - The direction of the cast
maxDistance : float = FLT_MAX - The maximum distance the cast can travel
collisionMask : uint = UINT_MAX - The collision mask to use for filtering collisions
- BoxQuery
Represents a box for overlap queries.
- Fields:
position : float3 - The position of the box
size : float3 = float3(0.5f,0.5f,0.5f) - The lengths of sides of the box
rotation : quat4 = quat4() - The rotation of the box
collisionMask : uint = UINT_MAX - The collision mask to use for filtering collisions
- SphereQuery
Represents a sphere for overlap queries.
- Fields:
position : float3 - The position of the sphere
radius : float = 1f - The radius of the sphere
collisionMask : uint = UINT_MAX - The collision mask to use for filtering collisions
- CapsuleQuery
Represents a capsule for overlap queries.
- Fields:
position : float3 - The center of the capsule
height : float = 2f - The full height of the whole capsule (including the spherical caps)
radius : float = 0.5f - The radius of the spherical caps
axis : AxisDirection = public_components::AxisDirection.YAxis - The axis of the orientation of the capsule
rotation : quat4 = quat4() - The additional orientation of the capsule
collisionMask : uint = UINT_MAX - The collision mask to use for filtering collisions
Handled structures
- RaycastHit
The result of traces and overlaps.
- Fields:
nodeId : NodeId - NodeId of the hitted object
position : Point3 - the position of the hit
normal : Point3 - the normal of the surface at the hit position. Faced generally in the opposite direction of the ray
distance : float - the distance to the hit position
- OverlapHit
The result of an overlap query.
- Fields:
nodeId : NodeId - NodeId of the hitted object
pointOnShape : Point3 - the point on the surface of the overlap shape
pointOnBody : Point3 - the point on the surface of the object that was hit
normal : Point3 - the normal of the surface at the hit position
distance : float - the distance from the center of the overlap shape to the
pointOnBody
- ShapeCastHit
The result of a shape casts.
- Fields:
nodeId : NodeId - NodeId of the hitted object
offset : Point3 - the offset that the casted shape can move before it will collide with another object
normal : Point3 - the normal of the surface at the hit position. Faced generally in the opposite direction of the ray
distance : float - the length of the
offset
Functions
apply_rigid_body_impulse (rigidBody: RigidBody?; impulse: float3)
apply_rigid_body_impulse (rigidBody: RigidBody?; impulse: float3; worldPosition: float3)
apply_rigid_body_angular_impulse (rigidBody: RigidBody?; angularImpulse: float3)
apply_rigid_body_force (rigidBody: RigidBody?; force: float3)
apply_rigid_body_force (rigidBody: RigidBody?; force: float3; worldPosition: float3)
apply_rigid_body_torque (rigidBody: RigidBody?; torque: float3)
get_rigid_body_velocity_at (rigidBody: RigidBody?; worldPosition: float3) : float3
trace (req: RayCast; blk: block<(hit:RaycastHit):void>) : bool
trace_all (req: RayCast; blk: block<(hits:array<RaycastHit>#):void>) : int
sweep_test (req: NodeCast; blk: block<(hit:ShapeCastHit):void>) : bool
trace (req: BoxCast; blk: block<(hit:ShapeCastHit):void>) : bool
trace (req: SphereCast; blk: block<(hit:ShapeCastHit):void>) : bool
trace (req: CapsuleCast; blk: block<(hit:ShapeCastHit):void>) : bool
trace_all (req: BoxCast; blk: block<(hits:array<ShapeCastHit>#):void>) : int
trace_all (req: SphereCast; blk: block<(hits:array<ShapeCastHit>#):void>) : int
trace_all (req: CapsuleCast; blk: block<(hits:array<ShapeCastHit>#):void>) : int
overlap (req: BoxQuery; blk: block<(hits:array<OverlapHit>#):void>) : int
overlap (req: SphereQuery; blk: block<(hits:array<OverlapHit>#):void>) : int
overlap (req: CapsuleQuery; blk: block<(hits:array<OverlapHit>#):void>) : int
set_collision_layer_mask (layer: auto(TT)|int; collisionMask: uint)
set_collision_between_layers (layer1: auto(TT)|int; layer2: auto(TT)|int; shouldCollide: bool)
- apply_rigid_body_impulse(rigidBody: RigidBody?; impulse: float3)
Applies an impulse to the rigid body in the center of mass.
This function implies that the impact is singular. To apply a continuous force, consider using apply_rigid_body_force().
- Arguments:
rigidBody : RigidBody ? -
RigidBodycomponentimpulse : float3 - the impulse vector to apply
Usage example:
// Pushes the body in the positive X direction
get_component(nodeId) $(var rigidBody: RigidBody?) {
apply_rigid_body_impulse(rigidBody, float3(1, 0, 0))
}
- apply_rigid_body_impulse(rigidBody: RigidBody?; impulse: float3; worldPosition: float3)
Applies an impulse to the rigid body at a given point in world coordinates.
This function implies that the impact is singular. To apply a continuous force, consider using apply_rigid_body_force().
- Arguments:
rigidBody : RigidBody ? -
RigidBodycomponentimpulse : float3 - the impulse vector to apply
worldPosition : float3 - the point in world coordinates at which to apply the impulse
Usage example:
// Pushes the body in the positive X direction at the center of the body
get_component(nodeId) $(var rigidBody: RigidBody?) {
apply_rigid_body_impulse(rigidBody, float3(1, 0, 0), nodeId.worldPosition)
}
- apply_rigid_body_angular_impulse(rigidBody: RigidBody?; angularImpulse: float3)
Applies an angular impulse to the rigid body.
This function implies that the impact is singular. To apply a continuous force, consider using apply_rigid_body_torque().
- Arguments:
rigidBody : RigidBody ? -
RigidBodycomponentangularImpulse : float3 - the angular impulse to apply
Usage example:
// Pushes the body to rotate around X axis
get_component(nodeId) $(var rigidBody: RigidBody?) {
apply_rigid_body_angular_impulse(rigidBody, float3(1, 0, 0))
}
- apply_rigid_body_force(rigidBody: RigidBody?; force: float3)
Applies a continuous force to the rigid body in the center of mass.
This function should be called every frame while the force is active. For a singular impact use apply_rigid_body_impulse(), or just change the velocity.
- Arguments:
rigidBody : RigidBody ? -
RigidBodycomponentforce : float3 - the force vector to apply
Usage example:
// Applies a continuous force in the positive X direction
get_component(nodeId) $(var rigidBody: RigidBody?) {
apply_rigid_body_force(rigidBody, float3(1, 0, 0))
}
- apply_rigid_body_force(rigidBody: RigidBody?; force: float3; worldPosition: float3)
Applies a continuos force to the rigid body at a given point in world coordinates.
This function should be called every frame while the force is active. For a singular impact use apply_rigid_body_impulse(), or just change the velocity.
- Arguments:
rigidBody : RigidBody ? -
RigidBodycomponentforce : float3 - the force vector to apply
worldPosition : float3 - the point in world coordinates at which to apply the force
Usage example:
// Applies a continuous force in the positive X direction at the center of the body
get_component(nodeId) $(var rigidBody: RigidBody?) {
apply_rigid_body_force(rigidBody, float3(1, 0, 0), nodeId.worldPosition)
}
- apply_rigid_body_torque(rigidBody: RigidBody?; torque: float3)
Applies a continuos torque to the rigid body.
This function should be called every frame while the torque is active. For a singular impact use apply_rigid_body_impulse(), or just change the velocity.
- Arguments:
rigidBody : RigidBody ? -
RigidBodycomponenttorque : float3 - the torque vector to apply
Usage example:
// Applies a continuous torque in the positive X direction
get_component(nodeId) $(var rigidBody: RigidBody?) {
apply_rigid_body_torque(rigidBody, float3(1, 0, 0))
}
- get_rigid_body_velocity_at(rigidBody: RigidBody?; worldPosition: float3): float3
Gets the velocity of the rigid body at a given point in world coordinates.
- Arguments:
rigidBody : RigidBody ? -
RigidBodycomponentworldPosition : float3 - the point in world coordinates at which to get the velocity
- Returns:
float3 - the velocity vector at the specified position
Usage example:
// Gets the local velocity of the body at the given point
get_component(nodeId) $(var rigidBody: RigidBody?) {
let velocity = get_rigid_body_velocity_at(rigidBody, nodeId.worldPosition + float3(1, 1, 1))
}
- set_collision_between_all_layers(shouldCollide: bool)
Set whether collision should occur between all layers. By default, all layers collide with each other.
- Arguments:
shouldCollide : bool - whether collision should occur
Usage example:
enum CollisionLayer {
Layer1 = 0
Layer2 = 1
}
// Disable collision between all layers to then only allow collision between Layer1 and Layer2
set_collision_between_all_layers(false)
set_collision_between_layers(CollisionLayer Layer1, CollisionLayer Layer2, false)
- set_gravity(direction: float3)
Sets the gravity direction in the scene. Note: default gravity is float3(0.0, -9.8065, 0.0)
- Arguments:
direction : float3 - the gravity direction vector
Usage example:
// Sets the gravity to point downward
set_gravity(float3(0.0, -9.8, 0.0))
- get_gravity(): float3
Gets the gravity direction in the scene.
- Returns:
float3 - the gravity direction vector
Usage example:
let gravity = get_gravity()
- set_default_friction(friction: float)
Sets the default friction value for new colliders. Note: default friction is 0.5
See the guide on how to setup friction.
- Arguments:
friction : float - the friction value to set
Usage example:
set_default_friction(1.)
- get_default_friction(): float
Gets the default friction value for new colliders.
- Returns:
float - the default friction value
Usage example:
let friction = get_default_friction()
- set_default_restitution(restitution: float)
Sets the default restitution value for new colliders. Note: default restitution is 0.
- Arguments:
restitution : float - the restitution value to set
Usage example:
set_default_restitution(0.5)
- get_default_restitution(): float
Gets the default restitution value for new colliders.
- Returns:
float - the default restitution value
Usage example:
let restitution = get_default_restitution()
- trace(req: RayCast; blk: block<(hit:RaycastHit):void>): bool
Performs a raycast, and if there is a hit, calls the provided block for the resulting hit.
- Arguments:
req : RayCast - the raycast request
blk : block<(hit: RaycastHit ):void> - the block to call for the resulting hit
- Returns:
bool - true if any hits occurred, false otherwise
Usage example:
let hadHit = trace(RayCast(ray = Ray(float3(0), float3(1, 0, 0)))) $(hit) {
print("Resulted position: {hit.position}")
print("Resulted node: {hit.nodeId}")
print("Resulted normal: {hit.normal}")
print("Resulted distance: {hit.distance}")
}
- trace_all(req: RayCast; blk: block<(hits:array<RaycastHit>#):void>): int
Performs a raycast, collects all hits into an array, and calls the provided block for the array of hits. Hits are not sorted by distance.
- Arguments:
req : RayCast - the raycast request
blk : block<(hits:array< RaycastHit >#):void> - the block to call for the array of hits
- Returns:
int - the number of hits
Usage example:
trace_all(RayCast(ray = Ray(float3(0), float3(1, 0, 0)))) $(hits : array<RaycastHit>#) {
for (hit in hits) {
print("Resulted position: {hit.position}")
print("Resulted node: {hit.nodeId}")
print("Resulted normal: {hit.normal}")
print("Resulted distance: {hit.distance}")
}
}
- sweep_test(req: NodeCast; blk: block<(hit:ShapeCastHit):void>): bool
Checks if a node would collide with anything if it moved in a given direction, and if there is a hit, calls the provided block for the resulting hit. The node is required to have a Collider component.
Does not collide with the source body.
Returns the single nearest collision only, or none.
- Arguments:
req : NodeCast - the node shape cast request
blk : block<(hit: ShapeCastHit ):void> - the block to call for the resulting hit
- Returns:
bool - true if any hits occurred, false otherwise
Usage example:
sweep_test(NodeCast(nodeId=someNodeId, from=float3(0), to=float3(1, 0, 0))) $(hit) {
pos = pos + hit.offset
}
- trace(req: BoxCast; blk: block<(hit:ShapeCastHit):void>): bool
Performs a box shape cast, and if there is a hit, calls the provided block for the resulting hit.
- Arguments:
req : BoxCast - the box shape cast request
blk : block<(hit: ShapeCastHit ):void> - the block to call for the resulting hit
- Returns:
bool - true if any hits occurred, false otherwise
Usage example:
trace(BoxCast(position=float3(0), size=float3(1.0), rayDirection=float3(1, 0, 0))) $(hit) {
pos = pos + hit.offset
}
- trace(req: SphereCast; blk: block<(hit:ShapeCastHit):void>): bool
Performs a sphere shape cast, and if there is a hit, calls the provided block for the resulting hit.
- Arguments:
req : SphereCast - the sphere shape cast request
blk : block<(hit: ShapeCastHit ):void> - the block to call for the resulting hit
- Returns:
bool - true if any hits occurred, false otherwise
Usage example:
trace(SphereCast(position=float3(0), radius=0.5, rayDirection=float3(1, 0, 0))) $(hit) {
pos = pos + hit.offset
}
- trace(req: CapsuleCast; blk: block<(hit:ShapeCastHit):void>): bool
Performs a capsule shape cast, and if there is a hit, calls the provided block for the resulting hit.
- Arguments:
req : CapsuleCast - the capsule shape cast request
blk : block<(hit: ShapeCastHit ):void> - the block to call for the resulting hit
- Returns:
bool - true if any hits occurred, false otherwise
Usage example:
trace(CapsuleCast(position = float3(0), height = 2., radius = 0.5, rayDirection=float3(1, 0, 0))) $(hit) {
pos = pos + hit.offset
}
- trace_all(req: BoxCast; blk: block<(hits:array<ShapeCastHit>#):void>): int
Performs a box shape cast, collects all hits into an array, and calls the provided block for the array of hits. Hits are not sorted by distance.
- Arguments:
req : BoxCast - the box shape cast request
blk : block<(hits:array< ShapeCastHit >#):void> - the block to call for the array of hits
- Returns:
int - the number of hits
Usage example:
trace_all(BoxCast(position=float3(0), size=float3(1.0), rayDirection=float3(1, 0, 0))) $(hits : array<ShapeCastHit>#) {
sort(hits) $(a, b : ShapeCastHit) { return a.distance < b.distance; }
for (hit in hits) {
print("Hit: {pos + hit.offset}")
}
}
- trace_all(req: SphereCast; blk: block<(hits:array<ShapeCastHit>#):void>): int
Performs a sphere shape cast, collects all hits into an array, and calls the provided block for the array of hits. Hits are not sorted by distance.
- Arguments:
req : SphereCast - the sphere shape cast request
blk : block<(hits:array< ShapeCastHit >#):void> - the block to call for the array of hits
- Returns:
int - the number of hits
Usage example:
trace_all(SphereCast(position=float3(0), radius=0.5, rayDirection=float3(1, 0, 0))) $(hits : array<ShapeCastHit>#) {
sort(hits) $(a, b : ShapeCastHit) { return a.distance < b.distance; }
for (hit in hits) {
print("Hit: {pos + hit.offset}")
}
}
- trace_all(req: CapsuleCast; blk: block<(hits:array<ShapeCastHit>#):void>): int
Performs a capsule shape cast, collects all hits into an array, and calls the provided block for the array of hits. Hits are not sorted by distance.
- Arguments:
req : CapsuleCast - the capsule shape cast request
blk : block<(hits:array< ShapeCastHit >#):void> - the block to call for the array of hits
- Returns:
int - the number of hits
Usage example:
trace_all(CapsuleCast(position = float3(0), height = 2., radius = 0.5, rayDirection=float3(1, 0, 0))) $(var hits : array<ShapeCastHit>#) {
sort(hits) $(a, b : ShapeCastHit) { return a.distance < b.distance; }
for (hit in hits) {
print("Hit: {pos + hit.offset}")
}
}
- overlap(req: BoxQuery; blk: block<(hits:array<OverlapHit>#):void>): int
Gets all nodes that overlap with the box, collects them into an array, and calls the provided block for the array of hits. Hits are not sorted by distance.
- Arguments:
req : BoxQuery - the box query request
blk : block<(hits:array< OverlapHit >#):void> - the block to call for the array of hits
- Returns:
int - the number of hits
Usage example:
overlap(BoxQuery(position=float3(0), size=float3(1.0))) $(hits : array<OverlapHit>#) {
for (hit in hits) {
print("Collided with node: {hit.nodeId}")
}
}
- overlap(req: SphereQuery; blk: block<(hits:array<OverlapHit>#):void>): int
Gets all nodes that overlap with the sphere, collects them into an array, and calls the provided block for the array of hits. Hits are not sorted by distance.
- Arguments:
req : SphereQuery - the sphere query request
blk : block<(hits:array< OverlapHit >#):void> - the block to call for the array of hits
- Returns:
int - the number of hits
Usage example:
overlap(SphereQuery(position=float3(0), radius=0.5)) $(hits : array<OverlapHit>#) {
for (hit in hits) {
print("Collided with node: {hit.nodeId}")
}
}
- overlap(req: CapsuleQuery; blk: block<(hits:array<OverlapHit>#):void>): int
Gets all nodes that overlap with the capsule, collects them into an array, and calls the provided block for the array of hits. Hits are not sorted by distance.
- Arguments:
req : CapsuleQuery - the capsule query request
blk : block<(hits:array< OverlapHit >#):void> - the block to call for the array of hits
- Returns:
int - the number of hits
Usage example:
overlap(CapsuleQuery(position = float3(0), height = 2., radius = 0.5)) $(hits : array<OverlapHit>#) {
for (hit in hits) {
print("Collided with node: {hit.nodeId}")
}
}
- set_physics_fps(fps: float)
Sets the fixed frames-per-second for the physics.
This have no effect on the get_delta_time() and has influence only on the stability of the physics. The more FPS, the more stability.
Note that if you want to set the maximum FPS, you better use set_target_fps.
Minimum value is 30
Default value is 60
Maximum value is 120
Usage example:
set_physics_fps(100f)
- Arguments:
fps : float - the new fixed frames-per-second for the physics
- get_physics_fps(): float
Gets the fixed timestep for the physics. Note that if you want to get the frame time, you should use get_delta_time().
- Returns:
float - frames per second of the physics simulation
- on_collision(nodeId: NodeId; callback: lambda<(collision:Collision):void>): LambdaCollisionListener?
Registers a callback that is called when another node with a RigidBody component collides with this node.
The callback is called for every new collision.
Returns an added collision handler component.
Note
MotionType Static is a cheapest option to receive callbacks, but it has its limitations, see MotionType
Usage example:
on_collision(node, @(collision) {
print("Collision between {node} and {collision.node}")
})
- on_collision_stay(nodeId: NodeId; callback: lambda<(collision:Collision):void>): LambdaCollisionListener?
Registers a callback that is called when another node with a RigidBody component collides with this node.
The callback is called every frame for every collision that stays between frames.
Returns an added collision handler component.
Note
MotionType Static is a cheapest option to receive callbacks, but it has its limitations, see MotionType
Usage example:
on_collision_stay(node, @(collision) {
print("Collision stays between {node} and {collision.node}")
})
- on_collision_exit(nodeId: NodeId; callback: lambda<(otherNode:NodeId):void>): LambdaCollisionListener?
Registers a callback that is called when another node with a RigidBody component collides with this node.
The callback is called for every ended collision.
Returns an added collision handler component.
Note
MotionType Static is a cheapest option to receive callbacks, but it has its limitations, see MotionType
Usage example:
on_collision_exit(node, @(otherNode) {
print("Collision finished between {node} and {otherNode}")
})
- set_collision_layer_mask(layer: auto(TT)|int; collisionMask: uint)
Enables or disables collisions between the specified layer and all other layers using bitmask. Note that this function affects not only the collision mask of the specified layer but also the collision masks of all other layers with respect to the specified layer, because of the symmetric nature of collisions.
- Arguments:
layer : option<auto(TT)|int> - the collision layer to set
collisionMask : uint - the collision mask to set
Usage example:
enum CollisionLayer {
Default = 0
Layer1 = 1
Layer2 = 2
}
// After this call, Default layer will collide with Layer1 and Layer2 but not with other layers
set_collision_layer_mask(CollisionLayer Default, 1u << uint(CollisionLayer Layer1) | 1u << uint(CollisionLayer Layer2))
- set_collision_between_layers(layer1: auto(TT)|int; layer2: auto(TT)|int; shouldCollide: bool)
Sets whether collision should occur between two layers.
- Arguments:
layer1 : option<auto(TT)|int> - the first collision layer
layer2 : option<auto(TT)|int> - the second collision layer
shouldCollide : bool - whether collision should occur between the layers
Usage example:
enum CollisionLayer {
Layer1 = 0
Layer2 = 1
}
// Disable collision between Layer1 and Layer2
set_collision_between_layers(CollisionLayer Layer1, CollisionLayer Layer2, false)