• Godot Help
  • Trying to make a grenade - collision detection fails sometimes

Trying to create a grenade, but collision is detected 50/50 only. Contibuous CD is checked for my grenage, contact monitor as well, tried setting max collisions reported to different number from 2 to 10, even adding a raycast - problem still exists.

Unable to attach the gif showing the problem. Grenade code is below.

extends RigidBody3D

@onready var collision = $CollisionShape3D
@onready var raycast = $RayCast3D

func _ready():
	pass # Replace with function body.


func _process(delta):
	pass
	
func _physics_process(delta):
	if raycast.is_colliding():
		destroy()

func _integrate_forces(state):	
	for i in state.get_contact_count():
		var cpos = state.get_contact_collider_position(i)
		var target = state.get_contact_collider_object(i)
		print("contact: " + str(target))
		destroy()
		Events.explosion.emit(cpos, target)

func _on_body_entered(body):
	print(body)
	pass
	#destroy()
	#Events.explosion.emit(cpos, target)	

func destroy():
	queue_free()

kuligs2
Yes, I'm trying to detect when grenade will hit the ground
Firstly tried to achieve this using state.get_contact_count(), then switched to raycasting since get_contact_count() wasn't always working reliably

I've just added RayCast3D looking forward from my grenade,and using code like

func _physics_process(delta):
	if raycast.is_colliding():
		print("ray colliding")
		Events.explosion.emit(raycast.get_collision_point(), raycast.get_collider())
		destroy()

But still - sometimes this work as expected, but sometimes grenage hits the wall and fastly fly back instead

    32kda you know that ray is linear? if your nade is tumbling in air, then it will never collide if its pointing in the sky

      kuligs2 Even when it goes directly into the wall - it's still sometimes missed and "grenade" just fastly fly back, so I think that's not the case.

      Modified code a little bit - using 3 methods of raycasting - programmatic raycast, Raycast3D node and on_body_entered signal. Still no reliable result - sometimes works as expected, sometimes - grenade flies forward, hits the wall and just flies back, nothing reported by all the checks

      func _physics_process(delta):
      	
      	var query = PhysicsRayQueryParameters3D.create(position, to_global(Vector3.FORWARD))
      	var from_ray = get_world_3d().direct_space_state.intersect_ray(query)
      	if from_ray:
      		print("from_ray " + str(from_ray["collider_id"]))
      		Events.explosion.emit(global_position, from_ray["collider"])
      		destroy()	
      	elif raycast.is_colliding():
      		print("from_ray " + str(from_ray["collider_id"]))
      		Events.explosion.emit(raycast.get_collision_point(), raycast.get_collider())
      		destroy()
      
      func _on_body_entered(body):
      	Events.explosion.emit(global_position, body)
      	destroy()
      	pass

      Here's grenade scene configuration, maybe I'm doing smth wrong in it?

      • xyz replied to this.

        32kda Ray direction should coincide with body's linear velocity, not some random direction caused by rotation.

          xyz
          Changed

          var query = PhysicsRayQueryParameters3D.create(position, to_global(Vector3.FORWARD))

          to

          var query = PhysicsRayQueryParameters3D.create(position, to_global(linear_velocity.normalized()))

          But still has the same problem

            32kda why does a grenade needs a raycast? why not use area3d?

              32kda linear_velocity is already in global space.

              8 days later

              kuligs2 Tried Area3D also, still the same problem
              Seems for some particles physics_process was not called in time

                32kda as @"xyz" stated, linear velocity is already in global space. However, raycasting is point to point in global space, so you need the global_position of the grenade as your start point, and the end point is calculated via an offset from this point.
                The offset can be estimated via current speed of the grenade and the physics time delta. So something like:
                var destination = global_position + (linear_velocity * delta)
                var query = PhysicsRayQueryParameters3D.create(global_position, destination)