Shape Cast 3D

Godot C# Shape Cast 3D


Introduction

Shape cast detects collision objects within its designated region shape.
It can scan for multiple objects.
This page will focus on two main ways to create and use a shape cast.


First method: ShapeCast3D Node

A node that constantly sweeps a region of space to detect collisions.
With this node its easy to visualize exactly where the sweep region is.


Use ShapeCast3D

To begin, create a ShapeCast3D object in your scene.

Then add a shape to your ShapeCast3D,
for example, add a box:



To check whether the shape cast detected anything we can run this code:

public override void _Process(double delta)
{
    GD.Print(CollisionResult);
}

CollisionResult is an Array of dictionaries which contains all the information about the collider the shape cast detected.
For example, the next code prints all of the names of the objects that were detected by the shape cast:

public override void _Process(double delta)
{
    foreach (Dictionary result in CollisionResult)
    {
        GD.Print(((Node3D)result["collider"]).Name);
    }
}


Run in _Ready() method

There’s an issue with The ShapeCast3D node, where it won’t detect any colliders if its check runs through a _Ready() method:

public override void _Ready() // THIS IS BAD CODE DO NOT COPY
{
    foreach (Dictionary result in CollisionResult)
    {
        GD.Print(((Node3D)result["collider"]).Name);
    }
}

To fix this, turn _Ready() to an async method and wait for 1 frame, like this:

public async override void _Ready() // THIS IS GOOD CODE, FEEL FREE TO COPY ;)
{
    await ToSignal(GetTree().CreateTimer(0),"timeout");
    
    foreach (Dictionary result in CollisionResult)
    {
        GD.Print(((Node3D)result["collider"]).Name);
    }
}

Note: To get different information change the “collider” string in result[“collider”].


Result

Type Information Description
Vector3 position the position where the shapes collided.
Vector3 normal which side the collided object’s surface(face) is facing.
Object collider the object the shape cast detected.
ObjectID collider_id object’s id
RID rid object’s rid.
int shape object’s shape index.
Vector3 linear_velocity object’s linear velocity.


Second method: PhysicsShapeQuery

In some cases we would need a more dynamic approach like creating the cast in code.
For example when we want to scan an area dynamically only once.
For this we can use a PhysicsShapeQueryParameters3D.

3D Shape

First declare the Shape3D that the ShapeCast will use:

public void Scan_Collisions()
{
    var box = new BoxShape3D();
    box.Size = new Vector3(1,1,1);
}


3D Space

Every 3D component in godot is automatically assigned to the World3D class.
Before casting a shape we need to reference this class:

public void Scan_Collisions()
{
    var box = new BoxShape3D();
    box.Size = new Vector3(1,1,1);

    var spaceState = GetWorld3D().DirectSpaceState;
}

spaceState represents the interactions of objects and their state in our World3D.


Shape Query

To represent the Shape Cast and its properties use PhysicsShapeQueryParameters3D:

public void Scan_Collisions()
{
    var box = new BoxShape3D();
    box.Size = new Vector3(1,1,1);

    var spaceState = GetWorld3D().DirectSpaceState;
    PhysicsShapeQueryParameters3D query = new PhysicsShapeQueryParameters3D();
}

Set the query’s shape:

public void Scan_Collisions()
{
    var box = new BoxShape3D();
    box.Size = new Vector3(1,1,1);

    var spaceState = GetWorld3D().DirectSpaceState;
    PhysicsShapeQueryParameters3D query = new PhysicsShapeQueryParameters3D();
    query.Shape = box;
}

(Alternatively, instead of creating a shape in code, it is possible to take a shape from a separate node such as CollisionShape3D)


Result

Finally make the query sweep for collisions in our spaceState and print it:

public void Scan_Collisions()
{
    var box = new BoxShape3D();
    box.Size = new Vector3(1,1,1);

    var spaceState = GetWorld3D().DirectSpaceState;
    PhysicsShapeQueryParameters3D query = new PhysicsShapeQueryParameters3D();
    query.Shape = box;
    var results = spaceState.IntersectShape(query);

    GD.Print(results);
}

Note: the ‘results’ variable is the same as ‘CollisionResult’ from the previous section.


Exclude collision

To make the query ignore a certain collider use the Exclude property.
In this example the query ignores its parent (a RigidBody3D):

RigidBody3D ignoreThis = GetParent<RigidBody3D>();
query.Exclude = new Godot.Collections.Array<Rid> { ignoreThis.GetRid() };

The exceptions array can contain objects or RIDs.
Note: the ‘GetRid()’ method only works in classes that inherit from CharacterBody3D, StaticBody3D and such.


Collision Mask

In some cases using the Exception property could become inconvenient when excluding a lot of objects,
so instead we can use a collision mask.
In this example the query will only detect objects in Layer 1:

query.CollisionMask = 1;


Calculate Collision Masks

More about calculating collision masks and collision layers.


Run in _Ready() method

In a _Ready() method, unlike a ShapeCast3D node that will not detect anything unless it waits 1 frame, this method will work and detect colliders:

public override void _Ready()
{
    var spaceState = GetWorld3D().DirectSpaceState;
    PhysicsShapeQueryParameters3D query = new PhysicsShapeQueryParameters3D();
    query.Shape = new BoxShape3D{Size = new Vector3(1,1,1)};
    var results = spaceState.IntersectShape(query);

    GD.Print(results);
}


Extra references

Ray Cast
RayCasting Godot
PhysicsDirectSpaceState3D
ShapeCast2D
Physics Introduction


Last updated on: 08/23/2024. This page is up to date with Godot 4.3.
Please report any errors over to the relevant GitHub repository.
Documentation maintained by 000Daniel.