Check if body is 100 % inside area?

Godot Version

4.2.1

Question

How can I check whether a 3D body is fully inside an area? _on_area_3d_body_entered only tells me when the body has entered the area but not when all of the body is inside the area.

Max

I wonder if you could create a bool called “entering_area” that is set true when colliding with the area shape. Then when this state is true keep checking the collision contacts for the area. When you stop seeing the area collision and your entering_area is still true (i.e. we haven’t exited the area ) we can then presume we are fully in the area.

This is just a hunch, not sure Godot actually works like this under the hood, that is if a collision shape just a hollow shell logically? I’m on a quest to understand it.

If it doesn’t work like this, you may need some fancy math to measure distance to origins of the body and area to calculate if the object should be inside the area.

I get where you are going but as far as I can tell, Godot is considering the whole collision shape and not just its borders for collision detection.

I fixed it by building a collision fence around the actual area and go by the logic: if you are not inside the fence area but inside the actual collision shape, you are considered all in.
That check then needs to happen in the _process() since the collision detection of body entered and exited is not continuous.

Dumping the code below for reference in case it is of use to anyone else:

extends Node3D

var isInsideFenceArea = false
var isInsideDropArea = false


# Called when the node enters the scene tree for the first time.
func _ready():
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	if !isInsideFenceArea && isInsideDropArea:
		var texture = load("res://tex/kenney/prototype/green/texture_10.png")
		var material = $MeshInstance3D.get_active_material(0).duplicate()
		material.albedo_texture = texture
		$MeshInstance3D.set_surface_override_material(0, material)

func _on_area_3d_body_shape_entered(body_rid, body, body_shape_index, local_shape_index):
	pass
	#pass # Replace with function body.


func _on_area_3d_body_entered(body):
	var bodyName = body.get_name()
	if bodyName == "Pallet3D":
		isInsideDropArea = true


func _on_area_3d_body_exited(body):
	var bodyName = body.get_name()
	if bodyName == "Pallet3D":
		isInsideDropArea = false
		var texture = load("res://tex/kenney/prototype/red/texture_10.png")
		var material = $MeshInstance3D.get_active_material(0).duplicate()
		material.albedo_texture = texture
		$MeshInstance3D.set_surface_override_material(0, material)


func _on_fence_area_3d_body_entered(body):
	var bodyName = body.get_name()
	if bodyName == "Pallet3D":
		isInsideFenceArea = true
		print("isInsideFenceArea = true")


func _on_fence_area_3d_body_exited(body):
	var bodyName = body.get_name()
	if bodyName == "Pallet3D":
		isInsideFenceArea = false
		print("isInsideFenceArea = false")
2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.