Intersect Shape - correct way to use it

There are multiple ways to check for collisions with a shape (see this):

  • PhysicsDirectSpaceState2D.CastMotion()
  • PhysicsDirectSpaceState2D.CollideShape()
  • PhysicsDirectSpaceState2D.GetRestInfo()
  • PhysicsDirectSpaceState2D.IntersectShape()

They exhibit minor differences and I can’t say I’ve used more than one of them. I’ve come across some problems with editor scripts (see post) but I am unaware of any problems at runtime. There’s evidence that the method(s) is inaccurate (#66072, #85314) but there’s not much to do about that as a rookie user.

Whether you should use nodes or scripted shapecasting depends entirely on what you’re comfortable with and what fits your solution. If this works for you then you’re all set!

Well, you’re not doing it wrong. It’s not the position of the shape, per-say, that you’re setting; it’s the position (and orientation) of the shape query. Shapes are resources and they don’t have a transform i.e. they don’t have a position and orientation. Transform data resides in the script/node/method using the shape.

Don’t worry - you won’t accidentally reposition a node in your game.


For your own sake, I would recommend you create an extension method so you don’t have to write 15 lines of code whenever you want to perform a shapecast. You can find the extension method I use below. Feel free to modify it to fit your needs.

Shapecast extension method

This method is for 3D use. Method must be rewritten for 2D use.

	/// <summary>
	/// A Node3D extension that simplifies the usage of shapecasts.<br />
	/// NOTE: Automatically excludes this node from the shapecast.
	/// </summary>
	/// <param name="n">A node fromt the target 3DWorld.</param>
	/// <param name="shape">The Rid of the shape used for the shapecast.</param>
	/// <param name="start">The start point.</param>
	/// <param name="end">The end point.</param>
	/// <param name="excludes">An array of specific objects to exclude from the collision query.</param>
	/// <param name="collisionMask">The physics layers that the collision query tests against.</param>
	/// <returns></returns>
	public static Godot.Collections.Array<Godot.Collections.Dictionary> Shapecast(this Node3D n, Rid shapeRid, Vector3 start, Rid[] excludes = null, uint collisionMask = uint.MaxValue)
	{
		// Create a raycast query
		var spaceState = n.GetWorld3D().DirectSpaceState;
		var query = new PhysicsShapeQueryParameters3D()
		{
			ShapeRid = shapeRid,
			CollideWithBodies = true,
			Transform = new Transform3D(Basis.Identity, start),
			Exclude = new Godot.Collections.Array<Rid>(excludes ?? new Rid[0]),
			CollisionMask = collisionMask,
			// Motion = end - start,       // Not used for IntersectShape
		};

		// Exclude this object from the raycast
		if (n is CollisionObject3D co3d)
			query.Exclude.Add(co3d.GetRid());

		var result = spaceState.IntersectShape(query);

		return result;
	}

Usage example

var shape = new BoxShape3D();
var pos = new Vector3(0f, 0f, 0f);
var result = this.Shapecast(shape.GetRid(), pos); 
1 Like