Hi, I'm having some issue with area 3D detections. Basically the on_body_exit signal takes too long to emit. I have 4 separate area 3D with on_body_enetered and on_body_exit signals attached to them. If I drag an object across multiple areas, the exit signal from the previous area would emit after the entered signal from the new area. (like shown below)

I've tried quadrupling physics ticks per second and max physics steps per frame (240, 32), and turning on ccd for the object.

Here's the code attached to each area 3D.

  • xyz replied to this.
  • You set the new dragged position directly and then tween it to that position. That makes no sense. Do only one of those.
    It should be either:

    if result:
    	var new_position = result.position + offset
    	selected_object.global_transform.origin = new_position
    	selected_object.force_update_transform()

    Or:

    if result:
    	var new_position = result.position + offset
    	var tween = selected_object.create_tween()
    	tween.tween_property(selected_object, "global_position", new_position, 0.05)

    Yuewu Can it be that the body's collider is large enough to simultaneously overlap with multiple areas?

    Thank you for responding. For some more detail, the object is a rigid body being dragged by mouse using ray cast, and moved by tweening it's position.

    I've tried increasing the gap between areas to twice the size of the collider. It helps so that the error happens less. I thought the issue is that there is a slight lag between collider entering/leaving and signal emission. But if that's the case both enter and exit would be delayed so there shouldn't be double enter/exit situation. I think the issue might be with tweening so I'm going to look into that. If tweening happens to be the issue, is there a way to apply force so that the object moves smoothly towards certain coordinates?

    • xyz replied to this.

      xyz It needs to be a rigid body. It's... It's complicated...

      • xyz replied to this.

        Yuewu Rigid bodies are not supposed to be manipulated directly. You can always use area for dragging and rigid body for everything else. The entity doesn't have to be represented by a single setup. You can use different setups for different states.

        One thing is certain. The signal emission is not magically "lagging" behind the actual event. It's more likely there's a bug in your code or setup. It's hard to debug without seeing the whole thing. Make a minimal reproduction project and post it.

        The thing you can initially try is to not use tweening at all to see if the tween is somehow causing it.

        I've also included a video demonstrating the problem along with the project

        • xyz replied to this.

          Yuewu Make a minimal project from scratch, and attach it to a post. The project itself should demonstrate the problem and do nothing else except that. Posting your whole ongoing project for people to hunt bugs in - is not posting a minimal example project.

          Hi, I've built a demo from scratch.

          Scene set ups.
          Main Scene has 4 detection areas, 4 objects to be dragged around, floor, camera, light, and a static body 3D to keep the object on the same height as detection areas when dragging.

          Detection Scene is a Area 3D with mesh as visual indicator and a 5x1x7 collision shape 3D. Collision mask set to 3.

          3D Obejct is a Rigid Body 3D with 2x2x2 collision shape and mesh. Collision layer set to 1, 2, 3

          Scripts
          3D object
          Stores a 3d coordinate that the object will return to
          Check to see if the object is inside of a detection area

          class_name Collider
          
          var detected: bool = false
          var memorized_position: Vector3 = Vector3.ZERO
          
          func _ready():
              memorized_position = global_transform.origin

          Detection Area
          Check if the body entered is desired object
          Set the condition accordingly and print to check for the correct interaction

          
          func _on_body_entered(body):
              if body is Collider:
                  body.detected = true
                  print(body.name, " entered: ", self.name)
          
          func _on_body_exited(body):
              if body is Collider:
                  body.detected = false
                  print(body.name, " Left: ", self.name)

          Script for main scene
          Camera reference and variables

          @onready var camera_3d = $Camera3D
          var selected_object : Node3D = null
          var is_dragging : bool = false
          var offset : Vector3 = Vector3.ZERO

          Input function

          func _input(event):
              # Clicking on 3D object
              if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
                  if event.pressed:
                      # Selecting the object
                      var mouse_pos = event.position
                      var ray_origin = camera_3d.project_ray_origin(mouse_pos)
                      var ray_direction = camera_3d.project_ray_normal(mouse_pos)
          
                      # Create the PhysicsRayQueryParameters3D
                      var ray = PhysicsRayQueryParameters3D.new()
                      ray.from = ray_origin
                      ray.to = ray_origin + ray_direction * 1000
                      ray.collide_with_bodies = true
                      ray.collide_with_areas = false
                      ray.collision_mask = 2
                      var space_state = get_world_3d().direct_space_state
                      # Perform the raycast
                      var result = space_state.intersect_ray(ray)
                          if result:
                              var collider = result.collider
                              if collider:
                                  selected_object = collider
          					
                                  # Adjust the offset to account for the die's floating position
                                  var ground_position = result.position
                                  offset = selected_object.global_transform.origin - ground_position
                                  is_dragging = true
                  else:
                      #Releasing the object
                      if selected_object:
                          var tween = selected_object.create_tween()
                          tween.tween_property(selected_object, "position", selected_object.memorized_position, 0.5)
          				
                          #delete dragged die
                          if selected_object.detected:
                              selected_object.queue_free()
          
                          selected_object = null
                          is_dragging = false
          
              # Dragging the selected object
              if event is InputEventMouseMotion and is_dragging and selected_object:
                  var mouse_pos = event.position
                  var ray_origin = camera_3d.project_ray_origin(mouse_pos)
                  var ray_direction = camera_3d.project_ray_normal(mouse_pos)
          
                  # Recalculate ray
                  var ray = PhysicsRayQueryParameters3D.new()
                  ray.from = ray_origin
                  ray.to = ray_origin + ray_direction * 1000
                  var space_state = get_world_3d().direct_space_state
                  var result = space_state.intersect_ray(ray)
                  if result:
                      var new_position = result.position + offset
                      selected_object.global_transform.origin = new_position
                      var tween = selected_object.create_tween()
                      #selected_object.global_transform.origin = start_position + position_offset ##Line up instantly
                      tween.tween_property(selected_object, "position", new_position, 0.05)

          The issue can be replicated by dragging one object into an area then quickly moving it to another area then letting go of the left mouse button. I've included a video with the project here

          • Edited
          • Best Answerset by Yuewu

          You set the new dragged position directly and then tween it to that position. That makes no sense. Do only one of those.
          It should be either:

          if result:
          	var new_position = result.position + offset
          	selected_object.global_transform.origin = new_position
          	selected_object.force_update_transform()

          Or:

          if result:
          	var new_position = result.position + offset
          	var tween = selected_object.create_tween()
          	tween.tween_property(selected_object, "global_position", new_position, 0.05)

          Yep, that fixed it. Thanks a lot for solving the issue and showing me minimal reproducible example!