Godot-proposals: Add ShapeCast node for collision sweep and immediate overlap queries

Created on 15 Apr 2020  路  3Comments  路  Source: godotengine/godot-proposals

Aims to supercede #72, #709.
Helps #740.

Describe the project you are working on:
Goost Godot Engine C++ Extension.

Describe the problem or limitation you are having in your project:
Ray casting is not as flexible or robust when it comes to detecting collision bodies along the ray cast area/volume (can easily miss objects, for example beam weapons which has a notion of width of a beam, which raycast doesn't have). For that one needs to cast multiple ray cast in the same direction, which is a hacky thing to do.

It's also difficult to get collision overlaps with Area2D/3D and often requires waiting a couple of frames before collision information is available to these nodes, when immediate information is preferable. One can use signals for that, but that mostly leads to inconveniences because you have to ensure that no duplicate bodies is detected within the signal callback, and you need to collect a list of overlapped bodies manually. Using the low-level direct space state API is the only way to fetch immediate overlap information which is robust (with or without shape sweep test), but again it's quite cumbersome to use for most users.

Describe the feature / enhancement and how it helps to overcome the problem or limitation:
Creating ShapeCast2D and ShapeCast3D analogously to RayCast2D and RayCast3D nodes. Ability to assign any existing Shape2D or Shape3D is enough for this to overcome limitations of ray casting.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
I've managed to implement this via C++ modules in Goost, and replaced some GDScript classes already with it in my own projects.

Editor view

godot-shape-cast-2d

Inspector

godot-shape-cast-2d-inspector

API

godot-shape-cast-2d-api

The implementation is based on RayCast2D (copy-pasted and adapted), uses PhysicsDirectSpaceState.cast_motion along with PhysicsDirectSpaceState.get_rest_info internally, so in most cases it reflects RayCast2D API, with the following differences:

  • obviously you need to assign any Shape2D resource before using. For 2D, CircleShape2D is instantiated by default.
  • ability to configure collision margin for shapes.
  • casting can work with cast_to == Vector2(). In this case, such node can be used as a general-purpose, (continuous) collision detection area which can overcome limitations of Area2D. Immediate information can be forced with force_shapecast_update. Quite similar to PhysX Overlaps. Can also help workaround CCD issues: godotengine/godot#9071.
  • can return multiple results (the number of results is limited by max_results property for performance reasons). get_closest_* methods should be used instead if you come from RayCast2D. See also PhysX closest hit.
  • exposed collision_result as a property so that if there's a need to fetch more collision information not provided by the API by default (collider's linear_velocity, metadata etc).
  • get_closest_collision_safe/unsafe_distance used for querying the intersections exactly outside/inside collision. You can move the shapecast along safe distance to repeat the process from that point without the node being stuck inside the collider, for instance.
  • the ShapeCast node's own transform can be modified to alter the shape in any way by translating, rotating and scaling.

If this enhancement will not be used often, can it be worked around with a few lines of script?:
Cannot be worked around with a few lines of script.

Is there a reason why this should be core and not an add-on in the asset library?:
There's no particular reason why this should be part of the core. This can be implemented via plugin/module. Performance is the only reason why this might be needed for core. Some engines like Unity already provide similar functionality though, also the mentioned PhysX library.

In fact, given the same logic, the existing RayCast nodes can also be re-implemented via script.

If you think it's worth adding an entire ShapeCast2D/3D to Godot core and you feel like the described implementation is logical/fits the requirements, I can make a PR, but additional work is needed to port this to 3D.

physics

Most helpful comment

I've created a PhysicsTools module Goost containing the ShapeCast2D implementation for people to check out. As you see it's perfectly possible to maintain this outside of Godot. Of course if the proposal is approved, I could likely implement this already (2D only...). I'm not sure whether the implementation could also be backported to Godot 3.2, so the module will always be available there to support it.

All 3 comments

This is definitely a feature I've missed in Godot when migrating from other engines. I'm happy to lend my hand if/where/when it's wanted.

My use-case for this feature is primarily for the implementation of reactive character controllers, which requires scanning the environment to identify features, and then using the contact information to react to the feature. This requires management of multiple shape objects and the use of cast_motion and get_rest_info methods together in a non-intuitive manner, with unclear guarantees.

I wanted to suggest that the exclude api of the Raycasting nodes should be matched too (add_exception, add_exception_rid, remove_exception etc.), unless it's inclusion was already implied.

Might not be worth talking about yet, but I think that a dedicated path (ie. intersect_motion) in the direct space state classes may be also worth looking at? There seems to be a lot of repeated work done between both cast_motion and rest_info, and in repeated calls to them to discover up to 'x' collisions along a path. Edit2: Misunderstanding on my part, only casting to the first hit along the path solves a lot of my concerns. Edit1: Additionally it'll provide clear and strong-guarantees on results. I also haven't delved that deep into godot's physics implementation yet, so, I'm not sure what the cost/benefit actually is on that.

I wanted to suggest that the exclude api of the Raycasting nodes should be matched too (add_exception, add_exception_rid, remove_exception etc.), unless it's inclusion was already implied.

Yeah it's just not visible on the screenshot.

Might not be worth talking about yet, but I think that a dedicated path (ie. intersect_motion) in the direct space state classes may be also worth looking at?

Yeah with the current implementation I take the all bodies and do the intersections by excluding them one-by-one. This is also related to godotengine/godot#25695 I guess.

I've created a PhysicsTools module Goost containing the ShapeCast2D implementation for people to check out. As you see it's perfectly possible to maintain this outside of Godot. Of course if the proposal is approved, I could likely implement this already (2D only...). I'm not sure whether the implementation could also be backported to Godot 3.2, so the module will always be available there to support it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Dorifor picture Dorifor  路  3Comments

lupoDharkael picture lupoDharkael  路  3Comments

PLyczkowski picture PLyczkowski  路  3Comments

IllusiveS picture IllusiveS  路  3Comments

arkology picture arkology  路  3Comments