-
-
Notifications
You must be signed in to change notification settings - Fork 21.7k
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
PhysicsShapeQueryParameters.sphere_cast #2217
Comments
It is possible and you can cast any shape, not just spheres using
|
Well, as I mentioned, 1) the documentation is non-existent (also here) so nobody except you knows how to do that exactly, 2) SphereCast is enough for many use cases and a nice high-level API function. "Whenever you want to cast a sphere, prepare a a CapsuleShape in advance and then feed it into the (undocumented) PhysicsShapeQueryParameters, and now you can use intersect_shape" isn't very user-friendly for such an elementary task. |
Feel free to contribute the doc
|
You can ask for docs, ask how it works, ask for help if it doesnt work or
|
Uh-oh. Sorry, but I'm not to complaining. I just reiterated my point with more detail, because it seems like you missed it. I am essentially requesting a feature, along with the reason why I still think having a SphereCast function is something necessary. How can I contribute to the doc if I don't know how it works? Also, I would have contributed if I knew how it worked and if there was a way for ordinary users to contribute docs. I guess this system is still in the works, along with the new website. In any case, I'm speaking/making requests from a practical point of view. I am using Unity, and now that it's coming to Linux, I am 100% happy with it (especially since we have long paid the license fees). The community is huge and alive, there is vast documentation and how-tos. It has every single feature I need and more. Along with an immense archive of reusable prefabs and content. There is no practical incentive for me use godot, or get some feature implemented. I know you have your priorities, but the existence of a low-level (and undocumented) way of achieving the same effect doesn't change the fact that the current API to do a simple SphereCast (or anything similar) is more complicated than it should be, which is what I've been saying all along. I also don't think brushing tested-and-proven Unity features, or user-friendliness, away as "complaints" will get you anywhere either. |
well, if you are not using something, you have no incentive to know how If you want to see Godot succeed, the best you can do is contribute to it, On Tue, Jun 30, 2015 at 2:02 AM, seadra [email protected] wrote:
|
I surely would have done it had I know how it worked. OK, so you don't think having a few higher-level functions such as SphereCast would be better, like, at all? |
there are high level functions like that, in fact for 2D there is On Tue, Jun 30, 2015 at 12:01 PM, seadra [email protected] wrote:
|
Thanks! I will definitely contribute to the documentation (as long as I know what I'm writing about). So, for now, we can write a SphereCast polyfill something like this? func sphere_cast(origin, radius, direction, hit_info, max_distance, exclude):
var shape = SphereShape()
shape.set_radius(radius)
var params = PhysicsShapeQueryParameters()
params.set_shape(shape)
params.set_transform(get_transform().translated(origin)) # same transform as parent, just translate
params.set_motion(direction*max_distance) # is "motion" the sweep distance?
if exclude != null:
param.set_exclude(exclude) # here exclude is an array of... RID??
var res = PhysicsServer.intersect_shape(params, 1)
if hit_info != null: # and extends Object
hit_info = res # res is an array containing...?
return res.size() > 0 Does this look correct? By the way, is it possible to add new method to external classes in GDScript? |
What does |
to get the same functionality in Godot as the one you mentioned in Unity, On Wed, Jul 1, 2015 at 1:03 AM, seadra [email protected] wrote:
|
I've been tinkering about that. Would it work it I used a CapsuleShape rather than a SphereShape and set its height to max_distance? After all, the volume swept by a sphere going in a straight line is a capsule, and unless we are interested in the normal vector, it should give the same result (using cast_motion and rest_info [get_rest_info?] sounds a bit complicated & everything you mentioned is completely undocumented so I have no idea how to do that). BTW I suppose I shouldn't call set_motion (no such function exist for PhysicsShapeQueryParameters). And I think the line get_transform().looking_at(direction, Vector3(1,0,0)).translated(origin+direction*max_distance/2) # up shouldn't matter since capsule is axially symmetric Something like this: func sphere_cast(origin, radius, direction, hit_info, max_distance, exclude):
var shape = CapsuleShape()
shape.set_radius(radius)
shape.set_height(max_distance)
var params = PhysicsShapeQueryParameters()
params.set_shape(shape)
params.set_transform(get_transform().looking_at(direction, Vector3(1,0,0)).translated(origin+direction*max_distance/2)) # up shouldn't matter since capsule is axially symmetric
if exclude != null:
param.set_exclude(exclude) # here exclude is an array of... RID??
var res = PhysicsServer.intersect_shape(params, 1)
if hit_info != null: # and extends Object
hit_info = res # res is an array containing...?
return res.size() > 0 |
OK, after several hours trying to figure this out, I give up. Could you write a SphereCast polyfill? |
Pretty please? |
I'm pushing it now, but well, hope springs eternal :) |
Nobody (other than you) knows how to do it in godot (assuming that it can be done). |
just leave this issue open and will eventually fix/add this On Thu, Sep 10, 2015 at 2:09 PM, seadra [email protected] wrote:
|
Bump. |
New Godot user here. I've been looking for how to do the equivalent of unity's spherecast too. Ideally returning collision point(s) and normal(s). It'd be great if there was a convenient method for this. |
This is currently preventing me from implementing my 3D character properly. Any developments on this would be great, as I agree that it's quite an essential feature. Edit: I managed to get it somewhat working but I still don't know how to get back the CollisionShape node that has collided with the sphere cast. class SphereCastResult:
var hit_distance: float
var hit_position: Vector3
var hit_normal: Vector3
func sphere_cast(origin: Vector3, offset: Vector3, radius: float):# -> SphereCastResult: (type hint breaks GitHub syntax highlighting)
var space: PhysicsDirectSpaceState = get_world().direct_space_state as PhysicsDirectSpaceState
var shape: = SphereShape.new()
shape.radius = radius
var params: = PhysicsShapeQueryParameters.new()
params.set_shape(shape)
params.transform = Transform.IDENTITY
params.transform.origin = origin
var castResult = space.cast_motion(params, offset)
var result: = SphereCastResult.new()
result.hit_distance = castResult[0] * offset.length()
result.hit_position = origin + offset * castResult[0] # needs null check in godot physics
params.transform.origin += offset * castResult[1]
var collision = space.get_rest_info(params)
result.hit_normal = collision.get("normal", Vector3.ZERO)
return result |
I think the API should more or less closely represent This feature seems to be useful for people working on 3D projects. I only use 2D-related physics queries though. The proposal/issue is 5 years old so I might as well experiment with this? If I do end up implementing this for 2D specifically, I'm locked by the 3D side to be able to contribute, but might be easier done than said. 🙂 |
Feature and improvement proposals for the Godot Engine are now being discussed and reviewed in a dedicated Godot Improvement Proposals (GIP) (godotengine/godot-proposals) issue tracker. The GIP tracker has a detailed issue template designed so that proposals include all the relevant information to start a productive discussion and help the community assess the validity of the proposal for the engine. The main (godotengine/godot) tracker is now solely dedicated to bug reports and Pull Requests, enabling contributors to have a better focus on bug fixing work. Therefore, we are now closing all older feature proposals on the main issue tracker. If you are interested in this feature proposal, please open a new proposal on the GIP tracker following the given issue template (after checking that it doesn't exist already). Be sure to reference this closed issue if it includes any relevant discussion (which you are also encouraged to summarize in the new proposal). Thanks in advance! |
Super late, but I want to thank you for this code, it's really helped me understand how to do these queries. You might be able to do: class SphereCastResult:
var hit_distance: float
var hit_position: Vector3
var hit_normal: Vector3
var hit_collider
func sphere_cast(origin: Vector3, offset: Vector3, radius: float):# -> SphereCastResult: (type hint breaks GitHub syntax highlighting)
var space: PhysicsDirectSpaceState = get_world().direct_space_state as PhysicsDirectSpaceState
var shape: = SphereShape.new()
shape.radius = radius
var params: = PhysicsShapeQueryParameters.new()
params.set_shape(shape)
params.transform = Transform.IDENTITY
params.transform.origin = origin
var castResult = space.cast_motion(params, offset)
var result: = SphereCastResult.new()
result.hit_distance = castResult[0] * offset.length()
result.hit_position = origin + offset * castResult[0] # needs null check in godot physics
params.transform.origin += offset * castResult[1]
var collision = space.get_rest_info(params)
result.hit_normal = collision.get("normal", Vector3.ZERO)
collision = space.intersect_shape(params, 1)
result.hit_collider = collision[0].get("collider")
return result |
Can this please get documented somewhere? |
I'd like to, but I've never written documentation before and I'm not sure how to get started. For bonus info, here's how I've managed to get a shapecast from the center of the screen forwards (as far as the far clipping): export(NodePath) onready var cam = get_node(cam) as Camera
onready var distance = cam.get_zfar()
var sphere: = SphereShape.new()
sphere.radius = 0.5
var vp_size = get_viewport().size
var from = cam.project_ray_origin(vp_size * 0.5)
var to = cam.project_position(vp_size * 0.5, distance)
var space_state : PhysicsDirectSpaceState = get_world().direct_space_state as PhysicsDirectSpaceState
var param := PhysicsShapeQueryParameters.new()
param.collision_mask = player.collision_mask
param.set_shape( sphere )
param.transform = Transform.IDENTITY
param.transform.origin = from
param.margin = sphere.margin
param.exclude = [ self, player ]
var motion = to - from
var trace := space_state.cast_motion( param, motion )
if not (trace[0] == 1.0 and trace[1] == 1.0):
param.transform.origin += motion * trace[1]
var collision := space_state.intersect_shape(param, 1)
if collision != null:
var collider = collision[0].get("collider") Also, here's how to shapecast to an enemy (monster), first with a collide_shape to test already overlapping, then a shapecast (only on the enemy layer), then finally a confirmation raycast back to the player (all layers): func fire_shape():
var monster_mask = 1 << 3 #| 1 << 7
var sphere: = SphereShape.new()
var vp_size = get_viewport().size
var from = cam.project_ray_origin(vp_size * 0.5)
var to = cam.project_position(vp_size * 0.5, distance)
var space_state : PhysicsDirectSpaceState = get_world().direct_space_state as PhysicsDirectSpaceState
var param := PhysicsShapeQueryParameters.new()
param.collision_mask = monster_mask
param.set_shape( sphere )
param.transform = Transform.IDENTITY
param.transform.origin = from
param.margin = sphere.margin
param.exclude = [ self, player ]
sphere.radius = 0.2#sphere trace first
param.transform.origin = cam.project_position(vp_size * 0.5, 1.0) # 1.0 is slightly forward
var sphere_trace := space_state.intersect_shape(param,1)
if not sphere_trace.empty():
var collider = sphere_trace[0].get("collider")
if collider.is_in_group("monster"):
collider.get_parent().mesh.get_material().albedo_color = Color(randf(),randf(),randf())
sphere.radius = 1.0 # then sphere cast
var motion = to - from
var trace := space_state.cast_motion( param, motion )
if not (trace[0] == 1.0 and trace[1] == 1.0):
param.transform.origin += motion * trace[1]
var monster_point = space_state.get_rest_info(param).get("point")
var collision := space_state.intersect_shape(param, 1) #then final intersect at end
if not collision.empty():
var collider = collision[0].get("collider")
if collider.is_in_group("monster"): #final raycast back
var result = space_state.intersect_ray(monster_point, from, [ collider ], 2147483647, true, true )
if not result.empty():
var player_back = result.get("collider")
if player_back.is_in_group("Player"):
collider.get_parent().mesh.get_material().albedo_color = Color(randf(),randf(),randf()) |
(forum discussion)
Unity's SphereCast is quite an elementary and useful function.
To be fair, it seems it seems (I'm not sure though) is somehow possible to achieve a similar thing using the current API, but it is overly complicated and half of it isn't even documented.
Please add a similar high-level function to godot.
The text was updated successfully, but these errors were encountered: