im trying to add force to overlapping bodies in area3D
however they dont get recognized, they print out nothing
print > didexplode works

extends Node3D
@export var area : Area3D
@export var force = 5.0

func addexplosionforce():
	print("didexplode")
	for body in area.get_overlapping_bodies():
		if body is RigidDynamicBody3D:
			print(body.name)
			var direction_vector = body.global_transform.origin - area.global_transform.origin
			var distance = direction_vector.length()
			var collision_force = (force / distance) * body.mass
			body.apply_impulse(Vector3.ZERO, direction_vector.normalized() * collision_force)


func _on_visible_on_screen_notifier_3d_screen_exited():
	self.queue_free()




rigid bodies to detect are set to layer 4

  • The arguments are in the order (force, position), so what you want is

    body.apply_impulse(direction_vector.normalized() * collision_force, Vector3.ZERO)

Does "didexplode" print? I believe physics events happen on the next frame. So if you show/enable a physics body, you have to wait until the next frame to check for collision.

call_deferred("addexplosionforce")
  • DJM replied to this.

    cybereality
    'didexplode' prints correct yes
    im calling it from another script

    brokenModel1.addexplosionforce()

    can i do ?>

    brokenmodel.call_deferred("addexplosionforce")

    strange, it prints 'didexplode'
    but not the overlapping bodies in the area3D

    That code might have to be in _physics_process() actually. So something like this:

    extends Node3D
    @export var area : Area3D
    @export var force = 5.0
    var check_bodies = false
    
    func addexplosionforce():
    	print("didexplode")
    	check_bodies = true
    
    func _physics_process(_delta):
    	if not check_bodies: 
    		return
    	for body in area.get_overlapping_bodies():
    		if body is RigidDynamicBody3D:
    			print(body.name)
    			var direction_vector = body.global_transform.origin - area.global_transform.origin
    			var distance = direction_vector.length()
    			var collision_force = (force / distance) * body.mass
    			body.apply_impulse(Vector3.ZERO, direction_vector.normalized() * collision_force)
    	check_bodies = false
    
    func _on_visible_on_screen_notifier_3d_screen_exited():
    	self.queue_free()

    same result, might be an issue with my layer and mask settings
    cause it prints 'didexplode' and 'should explode'

    extends Node3D
    @export var area : Area3D
    @export var force = 5.0
    var check_bodies = false
    
    func addexplosionforce():
    	print("didexplode")
    	check_bodies = true
    
    func _physics_process(_delta):
    	if not check_bodies: 
    		return
    	print("should explode")
    	for body in area.get_overlapping_bodies():
    		if body is RigidDynamicBody3D:
    			print(body.name)
    			var direction_vector = body.global_transform.origin - area.global_transform.origin
    			var distance = direction_vector.length()
    			var collision_force = (force / distance) * body.mass
    			body.apply_impulse(Vector3.ZERO, direction_vector.normalized() * collision_force)
    	check_bodies = false
    func _on_visible_on_screen_notifier_3d_screen_exited():
    	self.queue_free()

    Yeah, I would double check the layers most likely.

    ive checked my masks
    every rigid bodie is on layer 4

    what am i doing wrong?

    anyone got an idea what issue is causing it not detecting the bodies?

    The arguments to apply_impulse are in the wrong order,
    but that shouldn't be stopping them from being detected at all.

    It seems to be working for me. Either something is off with the layers (check both the area and the rigid bodies) or maybe you are not re-enabling the area properly. I used process_mode and that seems to work good.

    extends Node2D
    
    @export var area : Area3D
    var touch = 0
    
    func _ready():
    	area.process_mode = Node.PROCESS_MODE_DISABLED
    
    func _physics_process(_delta):
    	for body in area.get_overlapping_bodies():
    		if body.name == "Cube":
    			touch += 1
    			print("Touched the Cube ", touch)
    
    func _input(event):
    	if event.is_action_pressed("start"):
    		area.process_mode = Node.PROCESS_MODE_ALWAYS

    so it now prints out the bodies, my layers where correct.
    i dont understand i need to put the code in physics process, and cant just call it from a func.
    however the apply impulse code is wrong, just like @spacecloud said, what should go there?

    extends Node3D
    @export var area : Area3D
    @export var force = 5.0
    const EXPLOSION_TIME = 0.5
    var explosion_timer = 0.0
    var exploded = false
    func _ready():
    	set_physics_process(false)
    	
    func addexplosionforce():
    	set_physics_process(true)
    	print("didexplode")
    	exploded = true
    
    func _physics_process(delta):
    	if not is_instance_valid(area):
    		return
    	for body in area.get_overlapping_bodies():
    		if body is RigidDynamicBody3D:
    			print(body.name)
    			var direction_vector = body.global_transform.origin - area.global_transform.origin
    			var distance = direction_vector.length()
    			var collision_force = (force / distance) * body.mass
    			body.apply_impulse(Vector3.ZERO, direction_vector.normalized() * collision_force)
    	
    	if exploded:
    		explosion_timer += delta
    		if explosion_timer >= EXPLOSION_TIME:
    			area.monitoring = false
    			area.queue_free()
    			
    func _on_visible_on_screen_notifier_3d_screen_exited():
    	self.queue_free()

    Physics process is synced to the physics engine (that is why it has the name). If you call or query any aspect of the physics engine, it is not guaranteed to work unless in physics process. This is because it may be on the wrong frame (maybe before the collision has been detected) or if you try to apply a force, it may be overwritten on the next physics tick (since it didn't get fully applied at the correct time). Not sure about the impulse, I can look at it later.

    The arguments are in the order (force, position), so what you want is

    body.apply_impulse(direction_vector.normalized() * collision_force, Vector3.ZERO)
    • DJM replied to this.