Get all instances at a global coordinate

Godot Version

4.3

Question

I’m attempting to iterate through a number of global positions and return all instances found at each global coordinate.

The problem is that the instanced objects are procedurally generated terrain chunks and are 8x8x8 units in dimension. The instances contain a mesh object and a collisionobject3d which makes up the terrain surface layer however the rest of the chunk is empty space. The chunks overlap at the edges so for example, if there are two chunks next to each other with origins at (0,0,0) and (8,0,0), is it possible to return any instances with the coordinate (8,4,4)?

I tried adding a CollisionShape3D the same size as the chunk but detection inside was not working as I expected. Maybe I need a small primitive to test with instead of just a single point?

Wouldn’t it be easier to store references to your instances in an Array and iterate through that array checking each instance’s coordinates? That will take away the hassle of collisions and what not. Depending on your game, it might increase or decrease the amount of computing though, so you need to be aware of that.
Maybe you could store the array per each chunk separately and then iterate through the appropriate chunks only.

1 Like

Thanks wchc, that’s a great suggestion and one that I will play around with. I can see though how it can quickly become computationally expensive if not managed correctly.

I guess I was hoping for something a little more elegant. Something like check if the coordinate is within a box/area/bounds and return its parent. Then do a global to local coordinate conversion against the parent or something along those lines.

I’m convinced there is a way to do it but will require more tinkering.

Thanks again.

Update: I might have a solution using the method I described. I will post the code once I have done a few more tests.

Ok, so for anyone interested, this is what I came up with.

As a test, I created a new project. I then created a new Node3D called ‘World’. Camera and light optional.

As a child of ‘World’, I created a StaticBody3D. I renamed it to (1,1,1). I added a CollisionShape3D object to it as a child. I made the collision object a BoxShape and set the size to 8x8x8 and the position to 4x4x4. I positioned the static body at (0,0,0) in the scene.

I then duplicated the static body 3 more times and renamed them to (-1,1,1), (-1,1,-1) and (1,1,-1) and positioned them at (-8,0,0), (-8,0,-8) and (0,0,-8) respectively in the scene.

I attached a new script to the ‘World’ node with the following:

func _ready() -> void:
	print(get_colliders_at_many_points([Vector3(0,0,0)]))
	
func get_colliders_at_many_points(points: Array, collision_mask := 1):
	var space_state = get_world_3d().direct_space_state
	var shape := BoxShape3D.new()
	shape.size = Vector3(0.1, 0.1, 0.1)

	var query := PhysicsShapeQueryParameters3D.new()
	query.shape = shape
	query.collision_mask = collision_mask

	var results := []

	for point in points:
		query.transform = Transform3D.IDENTITY.translated(point)

		# I set 8 as the max number of collision objects to query
		var intersections = space_state.intersect_shape(query, 8)
		for result in intersections:
			results.append({
				"point": point,
				"name": str(result.collider.name),
				"local_position": (result.collider.global_transform.origin - point).abs()
			})
	return(results)

This can check an array of coordinates passed into it however I ended up just querying individual Vector3’s as needed.

If you would like to see an example of the final usage, check out /watch?v=4Iue6Yp3D2Q on Youtube. The video is an older version of the project but using the new method, it’s functionally the same.

Enjoy!

2 Likes