Dragbox code adding units double to array

Godot Version

4.1

Question

Hey guys, (new into game development)

after doing the GDquest courses for the last weeks i am trying to get my hand starting a project of my own.

I have a selection manager node with an attached script
to on click create a dragbox and on release call a function that selects all units in the dragbox. (used this tutorial for the code: https://www.youtube.com/watch?v=TnL0i47QhqI)

now i also have a Game_manager node as the root of my main_scene. here i have an array that stores the selected units. I also debug print() the amount in the array when it gets changed with a setter function

the problem is that when i select a single unit it work as intended it selects it and adds a single unit to the array.

But when i use the drag select it doubles all units added to the array.
i cant seem to findout why it happens. Even chatgtp is not very helpfull in this regard.

I hope you guys can help a noob like myself!

below is the code im currently using:

extends Node
#reference to the colorrect dragbox node
@onready var ui_dragbox: ColorRect = %ui_dragbox

var mouse_dragging := false
var drag_start_position: Vector2

func _input(event: InputEvent) -> void:
	if event is InputEventMouseMotion and mouse_dragging:
		print("Dragging: ", event.position)
		
#region creating the selection dragbox
	#mouse drag start
	if event.is_action_pressed("left_mouse_click"):
		mouse_dragging = true
		drag_start_position = event.position
		ui_dragbox.show()
		ui_dragbox.position = drag_start_position
		ui_dragbox.size = Vector2.ZERO
		_clear_selected_units()
		update_selection()
		
	#mouse drag end
	elif event.is_action_released("left_mouse_click"):
		mouse_dragging = false
		ui_dragbox.hide()
		
		# select unit when mouse click released and nothing is selected
		if GameManager.selected_units.is_empty():
			var ray := _mouse_screen_to_world(get_viewport().get_camera_3d(), 1)
			if ray and ray["collider"] is player_unit:
				ray["collider"].selected = true
				GameManager.selected_units.push_back(ray["collider"])
				update_selection()
				
		#update selection gizmo
	if mouse_dragging and event is InputEventMouseMotion:
		var m_start := drag_start_position
		var m_end: Vector2 = event.position
		
		var diff = m_end - m_start
		var rect := Rect2(m_start, diff).abs() #to convert values instead of flip positions
		ui_dragbox.position = rect.position
		ui_dragbox.size = rect.size
		_select_units_2d_projected(rect)
#endregion


func _clear_selected_units() -> void:
	for unit in GameManager.selected_units:
		if not is_instance_valid(unit):
			continue
		unit.selected = false
	GameManager.selected_units = []
	update_selection()
	
func _select_units_2d_projected(rect: Rect2) -> void:
	var all_units = get_tree().get_nodes_in_group("units")
	var cam := get_viewport().get_camera_3d()
	for unit in all_units:
		if rect.has_point(cam.unproject_position(unit.global_position)):
			if unit.selected == false:
				unit.selected = true
			if unit not in GameManager.selected_units:
				GameManager.selected_units.append(unit)
			
			#if not unit.selected:
				#unit.selected = true
				#GameManager.selected_units.push_back(unit)
				#if unit not in GameManager.selected_units:
					#GameManager.selected_units.append(unit)
	update_selection()

#raycast to get mouse position on 3d world
func _mouse_screen_to_world(camera: Camera3D, collision_mask:int = 0xFFFFFFFF) -> Dictionary:
		var mouse_position = camera.get_viewport().get_mouse_position()
		var ray_origin = camera.project_ray_origin(mouse_position)
		var ray_end = ray_origin + camera.project_ray_normal(mouse_position) * 500
		
		var space_state = camera.get_world_3d().direct_space_state
		var query := PhysicsRayQueryParameters3D.new()
		query.from = ray_origin
		query.to = ray_end
		query.collision_mask= collision_mask
		var raycast = space_state.intersect_ray(query)
		
		return raycast

##updates the selection in the Game Manager and Game UI
func update_selection():
	if GameManager.selected_units.size() > 0:
		GameManager.unit_is_selected = true
		GameUi.update_selection_portraits()
	else:
		GameManager.unit_is_selected = false
		GameUi.update_selection_portraits()

in _ready() functions in both; game manager and selection manager scripts put prints(self.name, self.get_path()). What do you get printed?

set_unit_is_selected_label = called
SelectionManager /root/GameManager/SelectionManager
set_unit_is_selected_label = called
GameManager /root/GameManager
SelectionManager /root/@Node@2/SelectionManager
set_unit_is_selected_label = called

It’s weird that selection manager gets called 2 times right at the start. could this be part of the problem?

the set_unit_is_selected_label = called is a signal that the GameManager sends out when the variable unit_is_selected: bool = false gets changed.

It is. You’re running the script on two nodes, one of them is probably not wanted. Check what happens with your autoloads. Probably something you forgot to remove from there.

my autoload settings currently look like this.
I can’t seem to find anything wrong with it. i double checked if the script was attached to other nodes as well but this is also not the case.

could you specify in which areas i should look in?

Well those paths you printed are telling you exactly to which nodes the scripts are attached. If you have the same script on two nodes and you expect it to be only one one node, then that other node is the place to look at. Why is that script there if it’s not supposed to be there and who put it there?

Maybe I’m misunderstanding this, but it sounds like you have the same scene as main scene and as an autoload?

Autoloads are added on top of the scene you are running, so your whole game would be doubled then, including everything accessing the autoload.

1 Like

This was indeed the case. i added a diffrent node and made it root. changed the global script to use only the script. and changed a few references and now it works as planned. thank you both for the help!

edited the typos

@hyvernox You’re sabotaging my efforts to bring people to conclusions themselves :wink:

3 Likes