How can I check if an instantiated object will overlap with an existing object?

Godot Version 4.3

I’m new to Godot, and I’m making a 3D game where you can place objects on a grid. However, I have run into a problem. One of the objects you can place is a brick. Because of it’s shape, it actually takes up 2 grid squares. The problem with this is that if you can place the bricks right next to each other so that they overlap, which I don’t want. I need some way to check if the new brick will overlap with an existing one, and if so, place it at the next nearest location instead. I’ve tried searching the documentation for a way to do this, but honestly I’m so new to Godot that I’m really not having any luck.

Here is my code so far if you need it:

extends RayCast3D

@onready var instancedObject = preload(“res://brick.tscn”)
@onready var brickHolder = get_node(“…/…/…/…/BrickHolder”)

func _ready() → void:
pass
hit_from_inside = false

func _process(delta: float) → void:
pass

func _input(event: InputEvent) → void:
if event.is_action_pressed(“RightClick”):
var brick = instancedObject.instantiate()
var pos = $“.”.get_collision_point()
if $“.”.is_colliding():
brick.global_position = pos.snapped(Vector3(0.5,0.5,0.5))
brickHolder.add_child(brick)

First some comments:

You can format your code in this forum by surrounding it with triple tick marks:
```
YOUR CODE HERE
```

Example:

extends RayCast3D

@onready var instancedObject = preload(“res://brick.tscn”)
@onready var brickHolder = get_node(“…/…/…/…/BrickHolder”)

func _ready() → void:
	pass
	hit_from_inside = false

func _process(delta: float) → void:
	pass

func _input(event: InputEvent) → void:
	if event.is_action_pressed(“RightClick”):
	var brick = instancedObject.instantiate()
	var pos = $“.”.get_collision_point()
	if $“.”.is_colliding():
		brick.global_position = pos.snapped(Vector3(0.5,0.5,0.5))
		brickHolder.add_child(brick)

$".".foo() is equivalent to foo(), if I’m understanding correctly. I assume the get_node(".../.../.../.../BrickHolder") is not what you actually have in your code as well. The variable hit_from_inside is never referenced outside _ready() AFAICT.

Anyhow, to your question: One thing you could do is add an Area3D with a CollisionShape3D to your brick scene, and connect the area_entered signal to your script to detect when your brick intersects another brick. If you have other Area3Ds in the game and don’t want to also detect those, you can select a collision layer and mask for bricks to use exclusively, or give the brick an empty method like func is_brick(): pass and condition your detection logic on area.has_method("is_brick"). As far as snapping into a valid location, I don’t know enough about your setup to know what this would look like.

If you share a github repo of your project, it will be easier to speak to specifics

1 Like

Thank you for your answer! Area3D indeed seems like what I’m looking for. I tried to add a bit of code so that if the brick enters another’s area, it gets removed, but that gives me the error “Invalid access to property or key ‘area_entered’ on a base object of type ‘Node3D’.”

‘’’
func _input(event: InputEvent) → void:
if event.is_action_pressed(“RightClick”):
var brick = instancedObject.instantiate()
var pos = $“.”.get_collision_point()
if $“.”.is_colliding():
brick.global_position = pos.snapped(Vector3(0.5,0.5,0.5))
brickHolder.add_child(brick)
if brick.area_entered == true:
brick.queue_free()
‘’’

If you have any idea what the correct way to do this is, please point me in the right direction. My apologies, I’m very new :sob:

The tick marks for code formatting are to the left of the “1” key on most keyboards - I think you found a different tick mark that doesn’t work :smiley:

area_entered is a signal emitted by Area3D, not a bool. Even if it were a bool, your Brick object won’t have this signal unless it inherits from Area3D (I imagine Brick is a Node3D).

I think what I would do here is, in the Brick script, you should connect the area_entered signal and the area_exited signal, and in the handlers for those signals, increment/decrement some variable like var num_bricks_currently_in_contact_with_this. Then replace your if brick.area_entered line with something like if brick.num_bricks_currently_in_contact_with_this > 0:.

I’m not close to a computer to check that this is what you want though. Just a thought.

1 Like

Thank you so much for all your help! That appears to work as intended