Area3D.get_overlapping_areas().get_parent() does not match the Globals object

Godot Version

v4.3 stable.mono.official

Question

I have a Character (which is Player) and a NPC Node (named as Block). My Player will detect collision thru a InteractionLayer to interact (for example, initiate dialogue) with the Block.

But I notice that the Block object I obtained thru the collision detection is different with my actual Block in the node.

I wonder why and how to make it so that I can detect the exact Block using the collision detection. I read about how using get_node() or $... is not ideal, so I want to avoid those too.

Character Node

Block Node

image

character.gd

@onready var interaction_check: Area3D = get_node("Direction/InterationLayer")
const SPEED = 5.0
var input_vector: Vector3 = Vector3.ZERO 

func _unhandled_input(_event: InputEvent) -> void:
	
	if Input.is_action_just_pressed("ui_accept"):
		var interaction = interaction_check.get_overlapping_areas()
		if interaction.size() > 0:
			interaction[0]._interaction()
			return

Current Result

*I am new to this so I am sorry if some terms that I used is wrong or not suitable.

When using get_overlapping_areas the object you get is the Area3D itself, if you want to get the root, you need to either:

  • do that through the Area3D itself
  • use get_overlapping_bodies() on the character’s interaction area, and setup Block so that it is visible

For example, in a game where I had an “interaction area” I set it up such that:


The character’s area was on mask 24

The items are RigidBody with a CollisionShape3D

The item is on layer 24 so it can be seen by the character’s interaction area

This way, get_overlapping_bodies() will return the RigidBody as expected

Thanks @vonpanda , now I see why the Interactions[0] is not the same object. But I noticed that I missed out one of the key point lead to my post. I will add an edit to my post. (Edit: Apparently I am not able to upload more image to my original post, so I decided to keep it that way)

I tried the fiollowing, but it also didn’t get me the same Object.

var interaction = interaction_check.get_overlapping_areas()
	if interaction.size() > 0:
		var temp = interaction[0].get_parent()

Then it might be linked to the layer and mask setup that you have?
I can’t be sure - I suggest you use print_tree_pretty() to get a clearer idea of what you are getting.

@onready var interaction_check: Area3D = get_node("Direction/InterationLayer")
const SPEED = 5.0
var input_vector: Vector3 = Vector3.ZERO 

func _unhandled_input(_event: InputEvent) -> void:
	
	if Input.is_action_just_pressed("ui_accept"):
		var interaction = interaction_check.get_overlapping_areas()
		if interaction.size() > 0:
			interaction[0].print_tree_pretty()
			interaction[0]._interaction()
			return

This will output the tree of the Node and its children, so you can check what exactly you are getting

1 Like

I been trying to play around with the layer and mask. It still doesn’t work, and I start to think is this a bug from the Godot Engine itself.

I tried to change my layer and mask as the following, as attempt to directly detect the Block thru the collision.

Character > InteractionLayer

  • Layer > 8
  • Mask > 2

Block

  • Layer > 2

As result, .get_overlapping_areas() doesn’t return anything, which makes sense as the method should be detecting Area3D only.

I will continue to experiment with it. If i have any findings I will update here.

I am kinda using this post as place to record my journey of troubleshooting, just in case. Please let me know if I am not suppose to do this.

Troubleshooting Update:

I tried the following (suggested by @vonpanda) to see the different between the node.get_parent() and the Globals variables.

	if Input.is_action_just_pressed("ui_accept"):
		var interaction = interaction_check.get_overlapping_areas()
		if interaction.size() > 0:
			interaction[0]._interaction()
			
			print("interaction:")
			var temp = interaction[0].get_parent()
			print(temp)
			temp.print_tree_pretty()
			
			print("global:")
			var temp_g = Block
			print(temp_g)
			temp_g.print_tree_pretty()

And it is found out that, the Globals actually return the Node object and the node.get_parent() return the RigidBody3D object.

interaction:
Block:<RigidBody3D#37228643666>
 ┖╴Block
    ┠╴MeshInstance3D
    ┠╴CollisionShape3D
    ┖╴InteractionLayer
       ┖╴CollisionShape3D

global:
Block:<Node#33957086478>
 ┖╴Block

It could be as my Block is actually an instance created from another scene. So I proceed to break it down and create a complete Block node.


Running the same code give me the following.


interaction:
RigidBody3D:<RigidBody3D#28756149520>
 ┖╴RigidBody3D
    ┠╴Area3D
    ┃  ┖╴CollisionShape3D
    ┠╴MeshInstance3D
    ┖╴CollisionShape3D

global:
RigidBody3d_obj:<RigidBody3D#28051506444>
 ┖╴RigidBody3d_obj

Which now return the Globals one as RigidBody3D, but still not the same object.

Findings:

So apparently, the node.get_parent() will not able to return the variables that are registered as Globals, since the Globals didn’t recognize (or I should say didn’t have) the child nodes. And I only then realize my question is actually something else from the Area3D.get_overlapping_areas().get_parent(), but it could be Globals related.
Went on to research that part, and in here [Singletons (Autoload) — Godot Engine (4.3) documentation in English] it says:

Godot’s scene system, while powerful and flexible, has a drawback: there is no method for storing information (e.g. a player’s score or inventory) that is needed by more than one scene.

Which seems to be related to my case. Apparently, Globals or the Singletons feature is actually created as the other method (node.get_parent(), get_node(), or $... are not able to be a place to store value.

Make sense now, so gonna tweak a bit on my approach.

1 Like