Area2D's CollisionShape2D positioning with unintended offset

Godot Version

v4.3.stable.official on Debian Linux, “Bookworm”

Question

Hi all! :godot:
I’m trying to make a selection shape for an RTS prototype, by using a panel to draw on screen for the player, and an Area2D with rectangular collision shape for the detection of units that get selected.
My problem is, as you can see in the video, that the collisionShape2D keeps getting positioned half-up, half-left from the position it should be, which is calculated with the panel’s position and dimensions.
As you can see, the size is set correctly, since the shapes are always the same, but the offset is also always half of each axis less.
I made sure that all initial positions and the transform of every child node is reset, yet I still can’t crack this.
Any thoughts on what it could be?

In case its relevant, code for the UI node that has the Panel child (cleaned up for visibility):

signal area_selection(upper_left, lower_right)
@onready var selection_box: Panel = $SelectionBox
var is_dragging: bool = false
var initial_drag_coord: Vector2 = Vector2.ZERO
var final_drag_coord: Vector2 = Vector2.ZERO

func _process(_delta: float) -> void:
	if Input.is_action_just_pressed("INPUT_LEFT_CLICK"):
		is_dragging = true
		initial_drag_coord = get_local_mouse_position()
		print("started dragging at " + str(initial_drag_coord))
	
	if Input.is_action_just_released("INPUT_LEFT_CLICK"):
		is_dragging = false
		final_drag_coord = get_local_mouse_position()
		print("finished dragging at " + str(final_drag_coord))
		emit_selection_data()
		
	if is_dragging:
		var mouse_pos = get_local_mouse_position()
		selection_box.position = Vector2(min(initial_drag_coord.x, mouse_pos.x), min(initial_drag_coord.y, mouse_pos.y))
		selection_box.size = Vector2(max(initial_drag_coord.x, mouse_pos.x), max(initial_drag_coord.y, mouse_pos.y)) - selection_box.position

func emit_selection_data():
	area_selection.emit(selection_box.position, selection_box.position + selection_box.size)

And the relevant code from the main Game scene:

[...]
var currently_selected: Array[Node] = []
var area_selection_ocurred: bool = false

func _ready() -> void:
	[...]
	$UI.area_selection.connect(_on_area_selection)
	$Area2D.monitoring = true
	$Area2D.body_shape_entered.connect(_print_collision)

func _on_area_selection(upper_left, lower_right) -> void:#deberia ser bool
	print("Selected area: " + str(upper_left) + str(lower_right))
	print("Box size is: " + str(lower_right - upper_left))
	$Area2D/CollisionShape2D.position = upper_left
	$Area2D/CollisionShape2D.shape.size = lower_right - upper_left
	area_selection_ocurred = true

func _print_collision(_body_rid: RID, body: Node2D, _body_shape_index: int, _local_shape_index: int) -> void:
	if area_selection_ocurred:
		print(body)
		print(body.get_parent())
		if body.is_in_group("selectable"):
			currently_selected.append(body)
		area_selection_ocurred = false

Collisions shapes are centered, you must set the position to upper_left + size/2

1 Like

Hadn’t thought of that! Thank you so much! :gdparty: :gdparty:

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