Hi, relatively new to godot here. As I've gone through a few tutorials in regards to Godot and GDScript I have seen a lot of references when changing the state of Collision to use set_deferred("disabled", true) And similar code.

However, in practice I always get it to set 'disabled' to false.

Example code that I'm using it in (Apologies about possibly unusual formatting... I find it's what makes it best for me to organize):

onready var collision = $StaticBody2D/CollisionShape2D

export (bool) var enabled_on_start = false

# Called when the node enters the scene tree for the first time.
func _ready():
	checkIfEnabledOnStart()

func checkIfEnabledOnStart():
	if enabled_on_start:
		enableArea()
	else:
		disableArea()
	print(collision.disabled)

func enableArea():
	collision.set_deferred("disabled", false)
	print("Area Enabled")

func disableArea():
	collision.set_deferred("disabled", true)
	print("Area Disabled")`

However, I get the following output from the print statements from 2 objects each with enabled_on_start set to true/false respectively:

Area Enabled
False
Area Disabled
False

This is a recurring theme anytime I've tried using set_deferred(), and as such for now I'm just setting disabled manually, but from what I gather that can have unexpected collision consequences.

If there's something obvious I'm missing I'm all ears, because everywhere I have looked they say simply use set_deferred as I'm using it here.

EDIT: While the print statements might be getting called in the same frame, and therefore aren't accurate. However, the collision when I go to interact with the object IS solid.

Yeah, that is expected output. When you use a set/call deferred, the property or function happens at some later time when it is safe to do so (usually at the end of the frame, but I don't think there are any guarantees). So you printing a value after a deferred call will just show the original value, the change doesn't happen for 1 (or more) frames later. In this case, I don't think set_deferred is even needed, not sure what tutorial you are following.

Deferred is usually used during gameplay, like when you need to delete an object, so that it doesn't mess things up (for example, if the object you are deleting is currently running code). But here you are setting it at start, so it is safe to change the values (at least that is what I assume from my brief understanding).

@cybereality said: Yeah, that is expected output. When you use a set/call deferred, the property or function happens at some later time when it is safe to do so (usually at the end of the frame, but I don't think there are any guarantees). So you printing a value after a deferred call will just show the original value, the change doesn't happen for 1 (or more) frames later. In this case, I don't think set_deferred is even needed, not sure what tutorial you are following.

Deferred is usually used during gameplay, like when you need to delete an object, so that it doesn't mess things up (for example, if the object you are deleting is currently running code). But here you are setting it at start, so it is safe to change the values (at least that is what I assume from my brief understanding).

Unfortunately my situation the collision is as the output says (When I go to interact with the object in question, they are both solid. It definitely isn't the same frame as this is during runtime and me using the player object to go to the object in question).

Granted in this specific instance I'm calling it during _ready, I call the same functions during gameplay, so it's best if I have it as the function.

That said, it probably is worth mentioning in my main post that the collision is as this reads.

Just as a check, do you get the same result if you just use call_deferred directly in _ready? I doubt this is the case, but maybe something with the function(s) is causing the issue?

Another thing that could be part of the problem is the node being a StaticBody2D. As far as I know, StaticBody2D collision is saved into the collision world for faster collision detection, though this comes with the downside of being more process intensive if moved. Have you tried using a RigidBody2D with call_deferred? It could be that because the code is called in _ready and the node is a StaticBody2D, the collision shape being disabled in _ready is not triggering a rebuild in the physics world and so it's not disabling the collision. Using a RigidBody2D might work around the issue since it's not saved into the physics world.

You could also try calling it in the first _physics_process call using code similar to this:

var initial_setup_complete = false
func _physics_process(delta):
	if initial_setup_complete == false:
		initial_setup_complete = true
		checkIfEnabledOnStart()

That might also fix the issue if it has something to do with being called in _ready.

@TwistedTwigleg said: Just as a check, do you get the same result if you just use call_deferred directly in _ready? I doubt this is the case, but maybe something with the function(s) is causing the issue?

Another thing that could be part of the problem is the node being a StaticBody2D. As far as I know, StaticBody2D collision is saved into the collision world for faster collision detection, though this comes with the downside of being more process intensive if moved. Have you tried using a RigidBody2D with call_deferred? It could be that because the code is called in _ready and the node is a StaticBody2D, the collision shape being disabled in _ready is not triggering a rebuild in the physics world and so it's not disabling the collision. Using a RigidBody2D might work around the issue since it's not saved into the physics world.

You could also try calling it in the first _physics_process call using code similar to this:

var initial_setup_complete = false
func _physics_process(delta):
	if initial_setup_complete == false:
		initial_setup_complete = true
		checkIfEnabledOnStart()

That might also fix the issue if it has something to do with being called in _ready.

Sadly this is a persistent issue in a lot of objects; Whether it's Rigidbody2D's, KinematicBody2D's, Area2D's... This code on this specific object is just 1 example.

Usually in my 'dead' function calls on either players or enemies.

I've only had 1 random instance where it works as intended, but that was one specific instance and I don't know what the different qualifier for it is.

a year later