.. _stdlib_physics_core: ======= Physics ======= You can add physics to your game by adding the ``RigidBody`` component to your objects. See the documentation for :ref:`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: * :ref:`RigidBody ` - the main component that enables physics for objects. .. _stdlib_physics_core_colliders: * Generic collider - a necessary component that represents a generic shape for physics. It can represent one or many shapes. * :ref:`Collider ` * Joints - joints that connect two ``RigidBody`` objects. Currently, only the simplest joints are available. * :ref:`SpringJoint ` * :ref:`HingeJointComponent ` * :ref:`SixDofJointComponent ` * Character - moves humanoid-like creatures with user-provided input * :ref:`CharacterController ` You can query the scene with traces and overlaps: * Raycasts: :ref:`trace(RayCast) `, :ref:`trace_all(RayCast) ` * SweepTest: :ref:`sweep_test(NodeCast) ` * ShapeCasts: * :ref:`trace(BoxCast) `, :ref:`trace(SphereCast) `, :ref:`trace(CapsuleCast) ` * :ref:`trace_all(BoxCast) `, :ref:`trace_all(SphereCast) `, :ref:`trace_all(CapsuleCast) ` * Overlap with other objects (scene queries): :ref:`overlap(BoxQuery) `, :ref:`overlap(SphereQuery) `, :ref:`overlap(CapsuleQuery) ` * You can also detect collisions between bodies with :ref:`on_collision `, :ref:`on_collision_stay `, :ref:`on_collision_exit ` With these global functions, you can also: * Apply forces and impulses to a rigid body: :ref:`apply_rigid_body_impulse `, :ref:`apply_rigid_body_impulse `, :ref:`apply_rigid_body_angular_impulse `, :ref:`apply_rigid_body_force `, :ref:`apply_rigid_body_force `, :ref:`apply_rigid_body_torque ` * Get the local velocity of a body at any given point: :ref:`get_rigid_body_velocity_at ` * Set up or disable gravity globally: :ref:`set_gravity `, :ref:`get_gravity ` * Set up collision between physics layers: :ref:`set_collision_layer_mask `, :ref:`set_collision_between_layers ` * Set default values for new physics bodies: :ref:`set_default_friction `, :ref:`get_default_friction `, :ref:`set_default_restitution `, :ref:`get_default_restitution ` * Set up physics fixed frames-per-second: :ref:`set_physics_fps `, :ref:`get_physics_fps ` .. _stdlib_physics_core_friction_damping_guide: +++++++++++++++++++++++++++++++++++ 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 :ref:`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: .. csv-table:: :header: "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. .. _stdlib_physics_core_main_loop: +++++++++++++++++++++++++++++++++++ Physics Simulation in the Main Loop +++++++++++++++++++++++++++++++++++ See :ref:`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 :ref:`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): :ref:`on_collision() `, :ref:`on_collision_stay() `, :ref:`on_collision_exit() `. - If a node has both an :ref:`on_collision() ` callback and a child component that is a :ref:`CollisionListener ` component, the callbacks will be received in the order in which those components were added. ++++++++++++ Type aliases ++++++++++++ .. _alias-AllowedDofs: .. das:attribute:: 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 +++++++++ .. _global-public_physics-MAX_PHYS_LAYER: .. das:attribute:: MAX_PHYS_LAYER = 31 Maximum value for a collision layer ++++++++++++ Enumerations ++++++++++++ .. _enum-public_physics-CharacterState: .. das:attribute:: CharacterState The return value of the :ref:`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. .. _enum-public_components-AxisDirection: .. das:attribute:: AxisDirection Axis direction for capsule and cylinder colliders :Values: * **XAxis** = 0 - X-Axis * **YAxis** = 1 - Y-Axis * **ZAxis** = 2 - Z-Axis .. _enum-public_components-CollisionDetection: .. das:attribute:: 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 .. _enum-public_components-Interpolation: .. das:attribute:: 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 .. _enum-public_components-MotionType: .. das:attribute:: 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 :ref:`on_collision ` function or the :ref:`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 with ``Kinematic`` bodies, it needs to be a sensor (see :ref:`RigidBody.isSensor `). If these limitations are unacceptable, consider using the ``Kinematic`` or ``Dynamic`` motion type. Despite the fact that ``Kinematic`` bodies do not react to collisions, they will generate collision callbacks. Also, note that a ``Dynamic`` body 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 :ref:`overlap ` function for a less cheap but more reliable collision handling. :Values: * **Dynamic** = 0 - ``Dynamic`` body * **Kinematic** = 1 - ``Kinematic`` body ++++++++++ Structures ++++++++++ .. _struct-physics_core-RayCast: .. das:attribute:: RayCast Represents a raycast request. :Fields: * **ray** : :ref:`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 .. _struct-physics_core-NodeCast: .. das:attribute:: 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** : :ref:`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 .. _struct-physics_core-BoxCast: .. das:attribute:: 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** : :ref:`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 .. _struct-physics_core-SphereCast: .. das:attribute:: 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 .. _struct-physics_core-CapsuleCast: .. das:attribute:: 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** : :ref:`AxisDirection ` = public_components::AxisDirection.YAxis - The axis of the orientation of the capsule * **rotation** : :ref:`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 .. _struct-physics_core-BoxQuery: .. das:attribute:: 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** : :ref:`quat4 ` = quat4() - The rotation of the box * **collisionMask** : uint = UINT_MAX - The collision mask to use for filtering collisions .. _struct-physics_core-SphereQuery: .. das:attribute:: 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 .. _struct-physics_core-CapsuleQuery: .. das:attribute:: 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** : :ref:`AxisDirection ` = public_components::AxisDirection.YAxis - The axis of the orientation of the capsule * **rotation** : :ref:`quat4 ` = quat4() - The additional orientation of the capsule * **collisionMask** : uint = UINT_MAX - The collision mask to use for filtering collisions ++++++++++++++++++ Handled structures ++++++++++++++++++ .. _handle-public_physics-RaycastHit: .. das:attribute:: RaycastHit The result of traces and overlaps. :Fields: * **nodeId** : :ref:`NodeId ` - NodeId of the hitted object * **position** : :ref:`Point3 ` - the position of the hit * **normal** : :ref:`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 .. _handle-public_physics-OverlapHit: .. das:attribute:: OverlapHit The result of an overlap query. :Fields: * **nodeId** : :ref:`NodeId ` - NodeId of the hitted object * **pointOnShape** : :ref:`Point3 ` - the point on the surface of the overlap shape * **pointOnBody** : :ref:`Point3 ` - the point on the surface of the object that was hit * **normal** : :ref:`Point3 ` - the normal of the surface at the hit position * **distance** : float - the distance from the center of the overlap shape to the ``pointOnBody`` .. _handle-public_physics-ShapeCastHit: .. das:attribute:: ShapeCastHit The result of a shape casts. :Fields: * **nodeId** : :ref:`NodeId ` - NodeId of the hitted object * **offset** : :ref:`Point3 ` - the offset that the casted shape can move before it will collide with another object * **normal** : :ref:`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 +++++++++ * :ref:`apply_rigid_body_impulse (rigidBody: RigidBody?; impulse: float3) ` * :ref:`apply_rigid_body_impulse (rigidBody: RigidBody?; impulse: float3; worldPosition: float3) ` * :ref:`apply_rigid_body_angular_impulse (rigidBody: RigidBody?; angularImpulse: float3) ` * :ref:`apply_rigid_body_force (rigidBody: RigidBody?; force: float3) ` * :ref:`apply_rigid_body_force (rigidBody: RigidBody?; force: float3; worldPosition: float3) ` * :ref:`apply_rigid_body_torque (rigidBody: RigidBody?; torque: float3) ` * :ref:`get_rigid_body_velocity_at (rigidBody: RigidBody?; worldPosition: float3) : float3 ` * :ref:`set_collision_between_all_layers (shouldCollide: bool) ` * :ref:`set_gravity (direction: float3) ` * :ref:`get_gravity () : float3 ` * :ref:`set_default_friction (friction: float) ` * :ref:`get_default_friction () : float ` * :ref:`set_default_restitution (restitution: float) ` * :ref:`get_default_restitution () : float ` * :ref:`trace (req: RayCast; blk: block\<(hit:RaycastHit):void\>) : bool ` * :ref:`trace_all (req: RayCast; blk: block\<(hits:array\#):void\>) : int ` * :ref:`sweep_test (req: NodeCast; blk: block\<(hit:ShapeCastHit):void\>) : bool ` * :ref:`trace (req: BoxCast; blk: block\<(hit:ShapeCastHit):void\>) : bool ` * :ref:`trace (req: SphereCast; blk: block\<(hit:ShapeCastHit):void\>) : bool ` * :ref:`trace (req: CapsuleCast; blk: block\<(hit:ShapeCastHit):void\>) : bool ` * :ref:`trace_all (req: BoxCast; blk: block\<(hits:array\#):void\>) : int ` * :ref:`trace_all (req: SphereCast; blk: block\<(hits:array\#):void\>) : int ` * :ref:`trace_all (req: CapsuleCast; blk: block\<(hits:array\#):void\>) : int ` * :ref:`overlap (req: BoxQuery; blk: block\<(hits:array\#):void\>) : int ` * :ref:`overlap (req: SphereQuery; blk: block\<(hits:array\#):void\>) : int ` * :ref:`overlap (req: CapsuleQuery; blk: block\<(hits:array\#):void\>) : int ` * :ref:`set_physics_fps (fps: float) ` * :ref:`get_physics_fps () : float ` * :ref:`on_collision (nodeId: NodeId; var callback: lambda\<(collision:Collision):void\>) : LambdaCollisionListener? ` * :ref:`on_collision_stay (nodeId: NodeId; var callback: lambda\<(collision:Collision):void\>) : LambdaCollisionListener? ` * :ref:`on_collision_exit (nodeId: NodeId; var callback: lambda\<(otherNode:NodeId):void\>) : LambdaCollisionListener? ` * :ref:`set_collision_layer_mask (layer: auto(TT)|int; collisionMask: uint) ` * :ref:`set_collision_between_layers (layer1: auto(TT)|int; layer2: auto(TT)|int; shouldCollide: bool) ` .. _function-physics_core_apply_rigid_body_impulse_RigidBody_q__float3: .. das:function:: 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** : :ref:`RigidBody ` ? - ``RigidBody`` component * **impulse** : 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)) } .. _function-physics_core_apply_rigid_body_impulse_RigidBody_q__float3_float3: .. das:function:: 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** : :ref:`RigidBody ` ? - ``RigidBody`` component * **impulse** : 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) } .. _function-physics_core_apply_rigid_body_angular_impulse_RigidBody_q__float3: .. das:function:: 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** : :ref:`RigidBody ` ? - ``RigidBody`` component * **angularImpulse** : 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)) } .. _function-physics_core_apply_rigid_body_force_RigidBody_q__float3: .. das:function:: 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** : :ref:`RigidBody ` ? - ``RigidBody`` component * **force** : 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)) } .. _function-physics_core_apply_rigid_body_force_RigidBody_q__float3_float3: .. das:function:: 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** : :ref:`RigidBody ` ? - ``RigidBody`` component * **force** : 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) } .. _function-physics_core_apply_rigid_body_torque_RigidBody_q__float3: .. das:function:: 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** : :ref:`RigidBody ` ? - ``RigidBody`` component * **torque** : 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)) } .. _function-physics_core_get_rigid_body_velocity_at_RigidBody_q__float3: .. das:function:: 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** : :ref:`RigidBody ` ? - ``RigidBody`` component * **worldPosition** : 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)) } .. _function-physics_core_set_collision_between_all_layers_bool: .. das:function:: 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) .. _function-physics_core_set_gravity_float3: .. das:function:: 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)) .. _function-physics_core_get_gravity: .. das:function:: get_gravity() : float3 Gets the gravity direction in the scene. :Returns: * float3 - the gravity direction vector Usage example:: let gravity = get_gravity() .. _function-physics_core_set_default_friction_float: .. das:function:: set_default_friction(friction: float) Sets the default friction value for new colliders. Note: default friction is 0.5 See the :ref:`guide ` on how to setup friction. :Arguments: * **friction** : float - the friction value to set Usage example:: set_default_friction(1.) .. _function-physics_core_get_default_friction: .. das:function:: 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() .. _function-physics_core_set_default_restitution_float: .. das:function:: 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) .. _function-physics_core_get_default_restitution: .. das:function:: 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() .. _function-physics_core_trace_RayCast_block_ls_hit_c_RaycastHit_c_void_gr_: .. das:function:: 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** : :ref:`RayCast ` - the raycast request * **blk** : block<(hit: :ref:`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}") } .. note: Prefer passing a normalized ray direction to this function. If the direction is not normalized, the function will normalize it internally. .. _function-physics_core_trace_all_RayCast_block_ls_hits_c_array_ls_RaycastHit_gr__hh__c_void_gr_: .. das:function:: trace_all(req: RayCast; blk: block<(hits:array#):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** : :ref:`RayCast ` - the raycast request * **blk** : block<(hits:array< :ref:`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#) { for (hit in hits) { print("Resulted position: {hit.position}") print("Resulted node: {hit.nodeId}") print("Resulted normal: {hit.normal}") print("Resulted distance: {hit.distance}") } } .. note: Prefer passing a normalized ray direction to this function. If the direction is not normalized, the function will normalize it internally. .. _function-physics_core_sweep_test_NodeCast_block_ls_hit_c_ShapeCastHit_c_void_gr_: .. das:function:: 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 :ref:`Collider ` component. - Does not collide with the source body. - Returns the single nearest collision only, or none. :Arguments: * **req** : :ref:`NodeCast ` - the node shape cast request * **blk** : block<(hit: :ref:`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 } .. _function-physics_core_trace_BoxCast_block_ls_hit_c_ShapeCastHit_c_void_gr_: .. das:function:: 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** : :ref:`BoxCast ` - the box shape cast request * **blk** : block<(hit: :ref:`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 } .. _function-physics_core_trace_SphereCast_block_ls_hit_c_ShapeCastHit_c_void_gr_: .. das:function:: 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** : :ref:`SphereCast ` - the sphere shape cast request * **blk** : block<(hit: :ref:`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 } .. _function-physics_core_trace_CapsuleCast_block_ls_hit_c_ShapeCastHit_c_void_gr_: .. das:function:: 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** : :ref:`CapsuleCast ` - the capsule shape cast request * **blk** : block<(hit: :ref:`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 } .. _function-physics_core_trace_all_BoxCast_block_ls_hits_c_array_ls_ShapeCastHit_gr__hh__c_void_gr_: .. das:function:: trace_all(req: BoxCast; blk: block<(hits:array#):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** : :ref:`BoxCast ` - the box shape cast request * **blk** : block<(hits:array< :ref:`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#) { sort(hits) $(a, b : ShapeCastHit) { return a.distance < b.distance; } for (hit in hits) { print("Hit: {pos + hit.offset}") } } .. _function-physics_core_trace_all_SphereCast_block_ls_hits_c_array_ls_ShapeCastHit_gr__hh__c_void_gr_: .. das:function:: trace_all(req: SphereCast; blk: block<(hits:array#):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** : :ref:`SphereCast ` - the sphere shape cast request * **blk** : block<(hits:array< :ref:`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#) { sort(hits) $(a, b : ShapeCastHit) { return a.distance < b.distance; } for (hit in hits) { print("Hit: {pos + hit.offset}") } } .. _function-physics_core_trace_all_CapsuleCast_block_ls_hits_c_array_ls_ShapeCastHit_gr__hh__c_void_gr_: .. das:function:: trace_all(req: CapsuleCast; blk: block<(hits:array#):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** : :ref:`CapsuleCast ` - the capsule shape cast request * **blk** : block<(hits:array< :ref:`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#) { sort(hits) $(a, b : ShapeCastHit) { return a.distance < b.distance; } for (hit in hits) { print("Hit: {pos + hit.offset}") } } .. _function-physics_core_overlap_BoxQuery_block_ls_hits_c_array_ls_OverlapHit_gr__hh__c_void_gr_: .. das:function:: overlap(req: BoxQuery; blk: block<(hits:array#):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** : :ref:`BoxQuery ` - the box query request * **blk** : block<(hits:array< :ref:`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#) { for (hit in hits) { print("Collided with node: {hit.nodeId}") } } .. _function-physics_core_overlap_SphereQuery_block_ls_hits_c_array_ls_OverlapHit_gr__hh__c_void_gr_: .. das:function:: overlap(req: SphereQuery; blk: block<(hits:array#):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** : :ref:`SphereQuery ` - the sphere query request * **blk** : block<(hits:array< :ref:`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#) { for (hit in hits) { print("Collided with node: {hit.nodeId}") } } .. _function-physics_core_overlap_CapsuleQuery_block_ls_hits_c_array_ls_OverlapHit_gr__hh__c_void_gr_: .. das:function:: overlap(req: CapsuleQuery; blk: block<(hits:array#):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** : :ref:`CapsuleQuery ` - the capsule query request * **blk** : block<(hits:array< :ref:`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#) { for (hit in hits) { print("Collided with node: {hit.nodeId}") } } .. _function-physics_core_set_physics_fps_float: .. das:function:: 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 .. _function-physics_core_get_physics_fps: .. das:function:: 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 .. _function-physics_core_on_collision_NodeId_lambda_ls_collision_c_Collision_c_void_gr_: .. das:function:: 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 :ref:`MotionType ` Usage example:: on_collision(node, @(collision) { print("Collision between {node} and {collision.node}") }) :Arguments: * **nodeId** : :ref:`NodeId ` * **callback** : lambda<(collision: :ref:`Collision ` ):void> .. _function-physics_core_on_collision_stay_NodeId_lambda_ls_collision_c_Collision_c_void_gr_: .. das:function:: 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 :ref:`MotionType ` Usage example:: on_collision_stay(node, @(collision) { print("Collision stays between {node} and {collision.node}") }) :Arguments: * **nodeId** : :ref:`NodeId ` * **callback** : lambda<(collision: :ref:`Collision ` ):void> .. _function-physics_core_on_collision_exit_NodeId_lambda_ls_otherNode_c_NodeId_c_void_gr_: .. das:function:: 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 :ref:`MotionType ` Usage example:: on_collision_exit(node, @(otherNode) { print("Collision finished between {node} and {otherNode}") }) :Arguments: * **nodeId** : :ref:`NodeId ` * **callback** : lambda<(otherNode: :ref:`NodeId ` ):void> .. _function-physics_core_set_collision_layer_mask_autoTTint_uint: .. das:function:: 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 - 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)) .. _function-physics_core_set_collision_between_layers_autoTTint_autoTTint_bool: .. das:function:: 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 - the first collision layer * **layer2** : option - 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)