-
-
Notifications
You must be signed in to change notification settings - Fork 21.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ShapeCast2D
node
#54803
Add ShapeCast2D
node
#54803
Conversation
e5ddacb
to
f0af051
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a few details to fix before merging, but otherwise it looks great. Thanks!
A few more things can be improved but they don't have to be part of this PR. I'm leaving a list here for the record:
- Improve debug draw by making a convex hull around the whole path
- Add a shape transform property to allow rotation/scale without changing the cast
- Add an equivalent node for 3D (still needs some tests to decide how to draw it)
4a2fb30
to
299ce1b
Compare
Done!
I have no idea what kind of drawing capabilities there are in 4.x, but perhaps there's a way to simply use an appropriate blending mode. Otherwise convex hull will require to refactor
I've tried to implement something like this myself but couldn't find a way to do this on the front-end side, I think shape transform should be done during In either case, yeah it would be nice to merge this sooner so that we don't lose motivation to work on all this stuff! |
There is a deluanlay tetrahedralize for 3d points can the 2d version be used? |
There's We could keep But this is something which touches core parts of the engine, so it's kind of out of scope for this PR, unless you think that implementing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left more comments after testing the ShapeCast2D node.
It generally works well, but there are some inconsistencies between what the documentation states and the results you get, so I've tried to suggest minimal changes to make it consistent until this node can be improved along with the physics API.
bool intersected = true; | ||
while (intersected && result.size() < max_results) { | ||
PhysicsDirectSpaceState2D::ShapeRestInfo info; | ||
intersected = dss->rest_info(params, &info); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using rest_info()
is not actually giving the results you're expecting. It's meant for contact detection and gives you the deepest collision point, so depending on the motion length and shape size you can get different results, not necessarily the nearest collision along the path.
Unfortunately there's currently no good API that gives you all the information you need for all collisions.
What I would suggest for now is:
-
You can keep using
cast_motion()
for the safe/unsafe distances, and later the physics server API can be improved to provide more information along with it, so you will be able to get more details about the closest collision. -
For the multiple collision results, you can call
intersect_shape()
just once instead ofrest_info()
multiple times to get information for all collision (but not contact points or normals). Later I think the best would be to usecollide_shape()
and modify the physics server API to provide more information than just contact positions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've found rest_info()
to be the best compromise in 3.x, because:
- You can detect multiple bodies along the cast given detected bodies get subsequently excluded from intersection:
- It does return useful information such as normal (and metadata which is removed in 4.x due to alternatives), but apparently incorrect. 😮
To be honest, I've mostly used this as a continuous collision detection area in 3.x, so yeah I get what you mean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree the position and normal would be good to have, but given the current API it just returns collisions in a random order and the positions are not correct so it's not really usable in common cases.
What you're trying to do makes sense. I would just rather wait for making the proper changes in the physics API before exposing the extra information to avoid confusing users, since it's not working as intended for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we keep rest_info()
when motion == Vector2()
, and use intersect_shape()
when motion != Vector2()
? Would that be a good compromise? If someone from contributors would want to port this PR to 3.x, I'd need this to be able to get normal/contact info in static collision case, I wouldn't want to create a different node just for this purpose in Goost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that could be a good compromise as long as it's clear and well documented. It does sound like a better solution than using a separate node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was all wrong from the start due to porting error, see #54803 (comment).
doc/classes/ShapeCast2D.xml
Outdated
[b]Note:[/b] [code]enabled == true[/code] is not required for this to work. | ||
</description> | ||
</method> | ||
<method name="get_closest_collider" qualifiers="const"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The get_closest_
functions are not going to return correct results until some changes are made in the physics server API, so better remove them for now (except for safe/unsafe distances).
By the way, given above suggestions, I'm fine for this PR to be postponed and be used as a reference point until physics backend is improved to match the proposed API, to be honest. I wouldn't want to remove those I'd personally like to see complete feature set, so I'm fine to wait, or somebody else could build upon my work. |
@Xrayez Ok, that makes sense! What I can propose is to make the adjustments to the physics server API in the next two weeks or so, and then you can update this PR to have the basic functionality work as intended and we can merge it. After that, other contributors will be able to help with adding functionalities and improving the rendering. And for now, this PR can be in draft mode until the API is ready. |
@pouleyKetchoupp @djrain so I thought I was losing my mind while porting the node to Godot 4.0, but I've checked the implementation in Goost I've made a year ago for Godot 3.x and figured that:
global_transform.set_origin(global_transform.get_origin() + to * collision_unsafe_fraction); Only then I use I have now properly ported implementation from 3.x to 4.x, it should work alright now (hopefully), sorry for confusion as I got confused by current API in Godot 4.0 while porting this. I have updated the test project according to suggested renames as well. Current code is compatible with Godot 3.x feature-wise, so if you think the result is satisfactory and decide to merge this now, it should be possible to just copy-paste existing 3.x implementation I have in Goost, if users express interest in this in Godot 3.x. If not, I've made this PR to work as intended, at least... 😅 |
Ok, the contact positions seem to work, although now it always only returns one collision result even if the shape cast goes through several bodies/areas. In order to get exactly the intended result, maybe you would need to use Here's the project I'm using for tests: |
The "intended" result I've shown at #54803 (comment) wasn't actually intended, sorry! The intended result was to hit a single object at the time of impact, but potentially return multiple collisions at point of impact in case there are multiple bodies there. This is consistent with The "closest" object in this case would be the one that first intersects with If you'll say that Due to above, and if #25695 is implemented, then That said, it's always possible to move Also, in your test project, |
Alright, makes sense to make it consistent with
Honestly, I would rather remove the I'm going to add more review comments for some details too, I think it's almost ready but I'd like to make sure the documentation is clear. |
That's good enough for me as long as multiple collisions are able to be detected at time of impact with contact info such as normals (that will be mostly useful for cases when shape cast starts in a colliding/stuck state at origin against other collision objects). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are a few last things that can be made clearer in the documentation. The code itself looks fine to me!
Glad I read this before going any further with my gdscript shapecasting system 😅 I have something working well enough for now, so I'm wondering @pouleyKetchoupp what fixes/changes you currently have in mind for the physics API and when/where they might actually be merged (if you have any idea)? |
b48b59f
to
63902e1
Compare
The physics API cannot provide needed functionality to ensure the correct behavior, which might lead to confusion (see `rest_info()`). However `get_closest_collision_safe/unsafe_fraction()` methods are not removed, because they return correct result from `cast_motion()`.
63902e1
to
6a67350
Compare
I have removed those methods now and pushed a separate commit to document this, because that's what differs from Goost implementation now, and that's something to keep in mind when new/updated API is planned for physics regarding dynamic collisions in general. |
I was thinking of making the different shape functions more consistent with each other, and allow all of them to return proper collision information (for example Given the state of this PR, it's not really needed anymore, but it might help with optimizing the queries, especially if we want to support getting different results along the motion later. Since it might include some compatibility breaking changes, I'll try to make a PR in the next few weeks, but I can't really give you a precise date. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to go!
Implements the 2D part of godotengine/godot-proposals#710.
Ported from Goost to Godot 4.0, implementation mostly equivalent to https://github.com/goostengine/goost/blob/46379f65c5bc9324dc0be1cb9c13f34c22b681b2/scene/physics/2d/shape_cast_2d.cpp, except collisions are processed regardless whether shape cast is already colliding or not.
Drawing could be improved, but perhaps that something @pouleyKetchoupp could build upon, as well as implementing the 3D counterpart based on this.
Test project:
shape-cast-2d.zip
(left mouse button click to set shape cast global position, right click to set target position)