Godot v4.4.stable
I have two Area3D’s with collision shapes. I want to know where the collision occurs. I found sample code for Godot 3.x, and made the simple modifications for 4.4, which I put into the handler for the area_shape_entered()
signal handler:
func processAreaEntered(area_rid: RID, area: Area3D, area_shape_index: int, local_shape_index: int) -> void:
var collision_points : Array
var area_space : RID = PhysicsServer3D.area_get_space(get_rid())
var space_state : PhysicsDirectSpaceState3D = PhysicsServer3D.space_get_direct_state(area_space)
var query : PhysicsShapeQueryParameters3D = PhysicsShapeQueryParameters3D.new()
query.set_shape(area.shape_owner_get_owner(area_shape_index).shape)
collision_points = space_state.collide_shape(query)
But the returned collision_points array is empty. Does anyone know why this doesn’t work in Godot 4.4?
Both colliding objects are instances of the same Area3D
class.
What exactly are you trying to accomplish? There might be another way of doing this. Your approach is likely overcomplicated for most applications.
When a player swings his sword in VR, I need to be able to detect when the sword collides with another weapon or with a person. I do so by extending the collision areas in the direction(s) of motion. I want to know where the two areas collided, so I can respond appropriately.
move_and_collide()
and move_and_slide()
cannot be used, as they fail on fast and/or simultaneous movement. Continuous collision detection is inefficient and slow, and still fails on fast and/or simultaneous movement.
ShapeCast3D seemed promising, but the docs say it is expensive. This leads me to think that it will be unusable more quickly than Area3D.
It’s probably best to use a ShapeCast3D, they aren’t that much more expensive, get it working then check on performance.
I haven’t done this in VR, but for 3D in general this is the approach I take:
- Make the Target a CharacterBody3D.
- Put the Target on its own collision Layer, let’s say 1.
- Add a CollisionShape3D to it that covers the Target.
- Put an Area3D on the Target’s weapon.
- Put the TargetWeaponArea3D on another Layer, let’s say 2.
- Add a CollisionShape3D to the Area3D that covers the sword.
- Put an Area3D on the Player’s weapon.
- Give the PlayerWeaponArea3D a Mask for both layers 1 & 2.
- Connect the Player’s weapon to its Area3D’s
body_entered
signal.
- Connect the Player’s weapon to its Area3D’s
area_entered
signal.
Whenever body_entered
is triggered, you will know it is because it’s dealing damage, and it will give you the target that was hit as an argument. Whenever area_entered
is triggered, you will know it hit another weapon, and you can apply physics, stop momentum, whatever, and you will know the Area3D connected to the weapon that was hit.
If that’s not enough detailed information for the collisions, you can hook up body_shape_entered
and area_shape_entered
in the same way and get more detailed collision data.
The benefit of using layers and masks in this way with bodies and areas is that it reduces the number of conditionals you have to have with a hit.
After thinking about it some more, what I’d probably do is make the swords a RigidBody3D, and have two areas and collisions shapes on the player’s sword, one each with a mask and tied to different methods. The reason for this is if I wanted to do VR sword fighting, I’d let the physics engine handle the collisions of the swords altogether. Then I don’t have to calculate which direction the sword goes when it hits the other one. I can just pla with the physics materials.
I already handle collisions in mostly the same way as you describe, and that generally works for most games, but VR introduces additional complications.
Godot’s collision detection fails on fast moving objects, which is the whole reason I am trying to avoid it for my VR combat system. I started a VR batting practice game years ago, which demonstrated Godot’s physics shortcomings when using the built-in physics in VR (as well as my own developer shortcomings).
The solution in the game physics books I have is to extend the collision objects to account for the motion of both moving objects. However, GDScript introduces a performance penalty over C++ just due to the nature of not being compiled, so I was looking to offload as much as possible to the engine rather than having to write the collision point detection calculations in GDScript.
The code I posted supposedly works in Godot 3.x, but something is apparently different in 4.x that breaks at the last line.
Honestly based on what you’re telling me, you should probably be doing this in C++. Godot has a something called GDExtension which allows you to write performant code and hook it into your game. You can also consider upping physics/common/physics_ticks_per_second
above 60. More processing per second means more data, but you’ll also want to up physics/common/max_physics_steps_per_frame
to keep up with it.
However if that code works you have two options. First, is to go back to 3.5 for now and see what you can get working. Then post a bug on the GodotEngine GitHub for 4.5. Second is to debug it.
Put a break point on this line:
query.set_shape(area.shape_owner_get_owner(area_shape_index).shape)
Then go through the debugger and see what values you are sending, and make sure all that is what you expect. Then, step into the execution and see what’s hapepning inside the collide_shape() function.