2D Rect physics shape intersect returning strange results

Godot 4.3

In this situation, I create the walls for the house out of 16x16 segments, each a StaticBody2D with one or more rectangle shapes.

In order to make the bottom walls transparent when the player is in the room, I create an Area2D detector for each room. When the Area2D is instantiated, which I do the frame after creating the walls because otherwise they don’t appear in intersection calculations, I intersect a smaller room rect that is offset downwards in order to catch all the shapes at the bottom of the room. This is represented by the red rectangles in the image. Anything that can be cast to a wall that is returned goes into an array in that detector node and in _process I set all of them to be transparent if the player is overlapping the room rect. When the player leaves the room I set them back to opaque, but only once, so there’s no interference.

In the example above you can see the returned wall segments are not contained in a rect and have other segments between them that would have been picked up by the intersection call if my rect size or position were wrong. Additionally, I have checked that only one room rect is being overlapped by the player at this time, so it’s not the case that many of my room areas have messed up collider positions - the Area2D collider shapes are correct.

I have the feeling that there is something going on with referencing here, in that when I instantiate the wall segments from the scene resource, some kind of memory is being reused and this is why I’m getting the results I’m seeing. But I can’t figure out what.

Does anyone have any idea what’s happening here?

mb try that?
you can make invisible Polygon2D on place where is wall
and test in for cycle every wall polygon if player position is inside of wall polygon using

if Geometry2D.is_point_in_polygon(player_pos, wall_polygon): wall.hide()

fire check using $Timer with wait time of 0.33

Thanks for the reply, but I think you’ve misunderstood. I don’t need to detect collisions between the player and the walls, that’s working fine. The player is a rigid body and the walls are static bodies. What I’m trying to do (or was - I fixed this a different way, not using intersection tests) is build a list of walls by doing an rectangle intersection test. I’ll post my code, hold on.

edit: Oh wait I see what you mean. That’s an alright solution but it ends up being rather a lot of tests and also I want them to go transparent when the player is in any part of the room, not just behind the walls. Regardless, the problem itself isn’t really what I want to solve here, it’s why the rect intersection isn’t working as I expected.

room_detector.gd:


class_name RoomDetector

var player : Player
var room_pixel_rect : Rect2
var walls = []
var debug
var in_room = false

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	# get lower walls	
	var space_state : PhysicsDirectSpaceState2D = get_world_2d().direct_space_state
	var query : PhysicsShapeQueryParameters2D = PhysicsShapeQueryParameters2D.new()
	var rect = PhysicsServer2D.rectangle_shape_create()
	var col_rect = room_pixel_rect	
	col_rect.size -= Vector2(16,0)
	col_rect.position += Vector2(8,9)
	debug = col_rect
	PhysicsServer2D.shape_set_data(rect, col_rect.size)
	query.transform.origin = col_rect.get_center()
	query.shape_rid = rect
	query.collision_mask = CollisionTools.MakeMask([2])
	var results = space_state.intersect_shape(query)
	for obj in results:
		if obj.collider is Geo:
			walls.append(obj.collider as Geo)
	var shape : CollisionShape2D = CollisionShape2D.new()
	shape.shape = RectangleShape2D.new()
	shape.shape.size = room_pixel_rect.size
	shape.position = room_pixel_rect.size / 2
	add_child(shape)
	position = room_pixel_rect.position
	collision_mask = CollisionTools.MakeMask([1])

func _draw():
	var col = Color.AQUAMARINE
	col.a = 0.2
	draw_rect(Rect2(Vector2(0,0), room_pixel_rect.size), col, true)
	draw_rect(Rect2(debug.position-position, debug.size), Color.RED, false)

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if overlaps_body(player):
		in_room = true
		for wall : Geo in walls:
			wall.set_alpha(0.2)
	else:
		if in_room:
			for wall : Geo in walls:
				wall.set_alpha(1)
		in_room = false

well no that much of checks if you make them filtered using VisibleOnScreenNotifier2D that adds visible walls to filtering array or a check certain distance to player before making check. You may use set_meta() on wall if it not a node and add_to_group() if node to mark which wall to which room belongs. So when player enters room (polygon/Rect2) you may just cast show()/draw signal on group that contain walls that belong to room

Thank you, but I really just want to get to the bottom of why the rect intersection doesn’t work. As I say, I have already solved the problem another way.

1 Like