I have seen this same question asked a couple times but I was unable to get it to work for my setup after reading through several solutions.
Relevant: C#, 2D
My problem is I have a couple instances of a prefab that are selectable by mouse click. I want it so that when I select one of these objects, the previously selected object is de-selected. Currently I am attempting to do this with a static bool on the class that trips a deselect function, and using the OnMouseDown function to protect that certain instance from the deselect function. Here is my code: (Apologies for sloppy formatting)
public class spawnScript : MonoBehaviour {
public bool selected;
public bool notSelected = true;
//static bool for tripping deselect function
public static bool clear;
void Update () {
//if clear is tripped
if (clear) {
//run deslect method
clearSelection ();
//reset clear
clear = false;
}
}
public void OnMouseDown(){
//protect this gameObject from being cleared
notSelected = false;
//trips the clear boolean on all instances
spawnScript.clear = true;
//select this gameObject
selected = true;
}
public void OnMouseUp(){
//sets it up to be clearable in the future
notSelected = true;
}
//clears selection
public void clearSelection(){
//Instances not clicked are deselected
if (notSelected) {
selected = false;
}
}
}
currently, the deselect function isn’t tripping correctly. I am pretty new to all this, and suspect my problem is using a static bool and then manipulating that bool within the same class. Almost positive this is the issue, but I’ve tried so many things that I kind of lost myself and fear I am trying the same things over and over.
I tried several raycast2D methods instead and couldn’t get it to work… Most likely I need to change my logic to a single SelectManager class that these prefabs reference instead, but I haven’t tried that yet. Any advice to make this script work, or, advice pointing me in the best direction (retry raycasts, try a SelectManager, etc.) will be greatly appreciated.
I got something to work, not using static variables. I instead have the following script attached to a Player gameobject that manages the game. Here is the script for selection
public void Update(){
//On the units, I have an OnMouseDown that changes the tag to SelectMe
GameObject newSlot = GameObject.FindGameObjectWithTag ("SelectMe");
if (newSlot != null) {
//search for and store the Previously Selected Unit
GameObject oldSlot = GameObject.FindGameObjectWithTag("Selected");
//The last clicked unit becomes selected
spawnScript towerSelect = newSlot.GetComponent<spawnScript> ();
towerSelect.selected = true;
//Then becomes the latest Selected unit
newSlot.tag = "Selected";
//The previous Selected unit becomes de-selected
spawnScript towerDeselect = oldSlot.GetComponent<spawnScript>();
towerDeselect.selected = false;
//and is set back to Untagged
oldSlot.tag = "Untagged";
}
}
I have tested this and it works perfect. The obvious set back here is running several FindGameObjectWithTags. I know this is bad for overall performance, but for my current needs and Prototyping, it works. If you agree please upvote this answer I can use some reputation!
I tend to use a manager for this. The manager sends a message to each GameObject when it is selected and when it is deselected. This type of setup is very easily extendable for multiple selectable GameObjects.
Pseudo code:
public class SelectManager : MonoBehaviour {
public GameObject selectedObject {get; private set;}
public void ChangeSelection (GameObject newSelection){
if(selectedObject){
selectedObject.SendMessage ("Deselect");
}
selectedObject = newSelection;
selectedObject.SendMessage ("Select");
}
}
You can call ChangeSelection from a raycast or from OnMouseUp on the individual GameObjects. You should also consider the case where the selectedObject is destroyed while selected. I typically handle this by reverting the selection to the SelectManager if nothing else is selected.