I am writing an RTS game with a typical “draw a rectangle to select multiple units” functionality. This works: I can select one or many units and I can give orders to them. I also started working on an ability system. I wanted to display ability buttons for selected units and launch these abilities for selected units.
However, a strange thing started happening - whenever I click a button, seemingly random units and even buildings get selected. I select one unit, click a button and other units are selected. This also happens with buttons that have no Events on them or even fresh, unconfigured buttons just added to the scene.
I am at a loss what might be causing this. If this is caused by some well known feature that I do not fully understand (like event propagation), I will be gratefull for pointing me in the right direction. If you would like to see some snippets or a video of the bug in action, I can do it. I am not giving any specifics yet, because I think I might be missing something really simple.
Curious note: when I launch abilities through hotkeys, they work as intended… there is some mischief going on in the UI I suspect.
My version of Unity is 2021.3.13
Most of the code is my own, I do not use any special addons apart from Enviro and Sensor toolkit (which is not used in unit selection).
From the looks of it, it doesn’t look like there’s any logic saying whether selection should be taking place.
You set a position on mouse down, if not over the UI, but then there doesn’t seem to be any logic that cares whether a new selection should be taking place. You wind up always continuing the last-started selection, regardless of whether the “StartSelectionArea()” function was run again.
(If it suits your preference for organization, setting “selectionActive” could just as easily be slotted into the functions themselves instead, but this example is intended to keep things compact and concise)
The whole code is quite long and complex - several classes involved. As for buttons, the hookup method doesn’t matter - this also happens on buttons that have no events hooked up - I mean newly added “naked” buttons trigger unit selection:/
The code below is on the Player object in a script that handles drawing of the rectangle and adding units that belong to the player to the player’s unit lists:
private void Update()
{
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
{
StartSelectionArea();
}
else if (Input.GetMouseButton(0))
{
UpdateSelectionArea();
}
else if (Input.GetMouseButtonUp(0))
{
ClearSelectionArea();
}
}
private void StartSelectionArea()
{
foreach (Unit selectedUnit in selectedUnits)
{
selectedUnit.Deselect();
}
foreach (Unit selectedWorker in selectedWorkers)
{
selectedWorker.Deselect();
}
foreach (Building selectedBuilding in selectedBuildings)
{
selectedBuilding.Deselect();
}
selectedUnits.Clear();
selectedWorkers.Clear();
selectedBuildings.Clear();
unitSelectionArea.gameObject.SetActive(true);
startPosition = Input.mousePosition;
UpdateSelectionArea();
}
private void UpdateSelectionArea()
{
Vector2 mousePosition = Input.mousePosition;
float areaWidth = mousePosition.x - startPosition.x;
float areaHeight = mousePosition.y - startPosition.y;
unitSelectionArea.sizeDelta = new Vector2(Mathf.Abs(areaWidth), Mathf.Abs(areaHeight));
unitSelectionArea.anchoredPosition = startPosition +
new Vector2(areaWidth / 2, areaHeight / 2);
}
private void ClearSelectionArea()
{
unitSelectionArea.gameObject.SetActive(false);
//MULTI SELECT checks against all units in the player's list
Vector2 min = unitSelectionArea.anchoredPosition - (unitSelectionArea.sizeDelta / 2);
Vector2 max = unitSelectionArea.anchoredPosition + (unitSelectionArea.sizeDelta / 2);
foreach (Unit unit in player.GetMyUnits())
{
Vector3 screenPosition = mainCamera.WorldToScreenPoint(unit.transform.position);
if (screenPosition.x > min.x &&
screenPosition.x < max.x &&
screenPosition.y > min.y &&
screenPosition.y < max.y)
{
if (unit.GetComponent<UnitAI>().GetAIType().Equals(AIType.Worker))
{
if (!selectedWorkers.Contains(unit))
{
selectedWorkers.Add(unit);
unit.Select();
}
}
else
{
if (!selectedUnits.Contains(unit))
{
selectedUnits.Add(unit);
unit.Select();
}
}
}
}
foreach (Building building in player.GetMyBuildings())
{
Vector3 screenPosition = mainCamera.WorldToScreenPoint(building.transform.position);
if (screenPosition.x > min.x &&
screenPosition.x < max.x &&
screenPosition.y > min.y &&
screenPosition.y < max.y)
{
if (!selectedBuildings.Contains(building))
{
selectedBuildings.Add(building);
building.Select();
}
}
}
Could it be that when you click the button your cursor accidentally selects the units that are under it or closer to it as it thinks you are dragging over them somehow?