godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.06k stars 20.19k forks source link

The raycast3d's module "is_colliding()" is true while "get_collider()" is null after using "queue_free()" on the "get_collider()". #87898

Open theyouknow opened 7 months ago

theyouknow commented 7 months ago

Tested versions

I'm not sure, I only have the v4.2.1 version of godot, so I haven't tried it in other versions of godot.

System information

Godot v4.2.1.stable - Windows 10.0.22631 - Vulkan (Forward+) - integrated AMD Radeon(TM) Graphics (Advanced Micro Devices, Inc.; 31.0.12044.3) - AMD Athlon Silver 3050U with Radeon Graphics (2 Threads)

Issue description

setting the variable i the code the error

Steps to reproduce

Here's the code:

@onready var i = $Indicator # The indicator is just a mesh 3d @onready var ray_cast = $RayCast3D # You'll also need to create a raycast3d

func _physics_process(_delta):

if Input.is_action_just_pressed("left click") and ray_cast.is_colliding():

    ray_cast.get_collider().queue_free()

if ray_cast.is_colliding():
    i.visible = true
    i.global_position = ray_cast.get_collider().position

Minimal reproduction project (MRP)

The bug.zip Open the project in editor mode, press run project, and then left click one of the cubes, the error should occur.

smix8 commented 7 months ago

A node does only update once each loop at the begin, usually before scripts, e.g. the RayCast3D updates its collider info only once at the begin of each physics process step. The deleting of queue_free() objects happen at different times in the main loop. In this case the colliding boolean of the node is set to true because by the time the node did the collision check it was true. That the collider object is marked for delete after and deleted, the node has no way to notice this before the next physics step update.

If you need immediate up-to-date info from the physics system use physics direct space queries. Nodes always add a processing delay and some update quirks because that is just how the SceneTree updates them. They also need to do their own internal book-keeping so are never in perfect sync with the server.

Lippanon commented 7 months ago

Perhaps the docs could be amended to accomodate this case, as currently they give the impression is_colliding and get_collider always match (same goes for other methods with similar descriptions): image

As a workaround for OP, you can use the following before setting the global_position in that code: if (ray_cast.get_collider() != null): or if is_instance_valid(ray_cast.get_collider()):

kleonc commented 7 months ago

If you need immediate up-to-date info from the physics system use physics direct space queries. Nodes always add a processing delay and some update quirks because that is just how the SceneTree updates them. They also need to do their own internal book-keeping so are never in perfect sync with the server.

There's also RayCast2D/3D.force_raycast_update method which can be used to force syncing RayCast2D/3D state according to the physics direct space state.