Ray-casting

    Godot stores all the low level game information in servers, while the scene is just a frontend. As such, ray casting is generally a lower-level task. For simple raycasts, node such as and RayCast2D will work, as they will return every frame what the result of a raycast is.

    Many times, though, ray-casting needs to be a more interactive process so a way to do this by code must exist.

    Space

    In the physics world, Godot stores all the low level collision and physics information in a space. The current 2d space (for 2D Physics) can be obtained by accessing . For 3D, it’s Spatial.get_world().space.

    The resulting space can be used in PhysicsServer and respectively for 3D and 2D.

    Godot physics runs by default in the same thread as game logic, but may be set to run on a separate thread to work more efficiently. Due to this, the only time accessing space is safe is during the Node._physics_process() callback. Accessing it from outside this function may result in an error due to space being locked.

    To perform queries into physics space, the and PhysicsDirectSpaceState must be used.

    Use the following code in 2D:

    GDscript

    C#

    1. {
    2. var spaceRid = GetWorld2d().Space;
    3. var spaceState = Physics2DServer.SpaceGetDirectState(spaceRid);
    4. }

    Or more directly:

    GDScript

    C#

    1. func _physics_process(delta):
    2. var space_state = get_world_2d().direct_space_state
    1. public override void _PhysicsProcess(float delta)
    2. {
    3. var spaceState = GetWorld2d().DirectSpaceState;
    4. }

    And in 3D:

    C#

    1. func _physics_process(delta):
    2. var space_state = get_world().direct_space_state

    Raycast query

    For performing a 2D raycast query, the method may be used. For example:

    GDScript

    C#

    1. func _physics_process(delta):
    2. var space_state = get_world_2d().direct_space_state
    3. # use global coordinates, not local to node
    1. public override void _PhysicsProcess(float delta)
    2. {
    3. var spaceState = GetWorld2d().DirectSpaceState;
    4. // use global coordinates, not local to node
    5. var result = spaceState.IntersectRay(new Vector2(), new Vector2(50, 100));
    6. }

    The result is a dictionary. If the ray didn’t hit anything, the dictionary will be empty. If it did hit something, it will contain collision information:

    GDScript

    C#

    1. if result:
    2. print("Hit at point: ", result.position)
    1. GD.Print("Hit at point: ", result["position"]);

    The result dictionary when a collision occurs contains the following data:

    The data is similar in 3D space, using Vector3 coordinates.

    A common use case for ray casting is to enable a character to gather data about the world around it. One problem with this is that the same character has a collider, so the ray will only detect its parent’s collider, as shown in the following image:

    To avoid self-intersection, the intersect_ray() function can take an optional third parameter which is an array of exceptions. This is an example of how to use it from a KinematicBody2D or any other collision object node:

    GDScript

    1. extends KinematicBody2D
    2. func _physics_process(delta):
    3. var space_state = get_world_2d().direct_space_state
    4. var result = space_state.intersect_ray(global_position, enemy_position, [self])
    1. class Body : KinematicBody2D
    2. {
    3. public override void _PhysicsProcess(float delta)
    4. {
    5. var spaceState = GetWorld2d().DirectSpaceState;
    6. var result = spaceState.IntersectRay(globalPosition, enemyPosition, new object[] { this });
    7. }
    8. }

    The exceptions array can contain objects or RIDs.

    Collision Mask

    While the exceptions method works fine for excluding the parent body, it becomes very inconvenient if you need a large and/or dynamic list of exceptions. In this case, it is much more efficient to use the collision layer/mask system.

    The optional fourth argument for intersect_ray() is a collision mask. For example, to use the same mask as the parent body, use the collision_mask member variable:

    GDScript

    C#

    1. func _physics_process(delta):
    2. var space_state = get_world().direct_space_state
    3. var result = space_state.intersect_ray(global_position, enemy_position,
    4. [self], collision_mask)
    1. {
    2. public override void _PhysicsProcess(float delta)
    3. {
    4. var spaceState = GetWorld2d().DirectSpaceState;
    5. var result = spaceState.IntersectRay(globalPosition, enemyPosition,
    6. new object[] { this }, CollisionMask);
    7. }
    8. }

    See Code example for details on how to set the collision mask.

    Casting a ray from screen to 3D physics space is useful for object picking. There is not much need to do this because has an “input_event” signal that will let you know when it was clicked, but in case there is any desire to do it manually, here’s how.

    To cast a ray from the screen, you need a Camera node. A Camera can be in two projection modes: perspective and orthogonal. Because of this, both the ray origin and direction must be obtained. This is because origin changes in orthogonal mode, while normal changes in perspective mode:

    ../../_images/raycast_projection.png

    To obtain it using a camera, the following code can be used:

    GDScript

    C#

    1. private const float rayLength = 1000;
    2. public override void _Input(InputEvent @event)
    3. {
    4. if (@event is InputEventMouseButton eventMouseButton && eventMouseButton.Pressed && eventMouseButton.ButtonIndex == 1)
    5. {
    6. var camera = (Camera)GetNode("Camera");
    7. var from = camera.ProjectRayOrigin(eventMouseButton.Position);
    8. var to = from + camera.ProjectRayNormal(eventMouseButton.Position) * rayLength;
    9. }

    Remember that during _input(), the space may be locked, so in practice this query should be run in _physics_process().