- Home /
Global selection structure
Apologies in advance if it's a bit long winded : I'm trying to create a component which allows me to select any object in my world. I'm not that experienced with Unity3D and tried do this first with sending messages. The problem I walked into is that I need to ensure that certain objects can be selected and have the same function calls. So I went with Interface classes. I want this game component to work globally.
For example, I have units that can move. But the moment I select them I need to show their walk range. ( As of right now this simply works ) This "Behavior" is different from, let's say, a crate you can click on to see any information on. Or an enemy for that matter ( like showing health/ATK ).
However I want them to have a common structure rather than throwing everything into different components. And have to ask whether GameObject A has Selection Component A and if not does he have selection Component B. Etc etc.
I have the feeling this can be solved by messages. But I simply can't figure it out. So I ask: How is selection for game objects usually handled and is the method I'm using completely alien to the intention of Unity's framework guidelines( see code snippets below)?
This is the "Selection" Component.
To identify what object can be selected I've created a ISelectable interface:
public interface ISelectable {
void selected();
void unselect();
bool selectable{get;set;}
}
This way gameobjects can handle their selection routine in their own components.
So in my selection component I do this ( note this isn't all the code):
if(firstSelectedObj == null)
{
ISelectable sObj = (ISelectable)hit.collider.gameObject.GetComponent(typeof(ISelectable));
if(sObj != null){
if(sObj.selectable){
firstSelectedObj = hit.collider.gameObject;
sObj.selected();
}
} else return;
}
So basically I check whether the object my ray hits is even relevant by checking if the getComponent method doesn't return a null object.
Because a second object can be selected In combination with the first I've also added an interface so that the second selected gameobject can be passed down.
else if(secondSelectedObj == null)
{
ISelectable firsStObj = (ISelectable)firstSelectedObj.GetComponent(typeof(ISelectable));
ISelectable secondSObj = (ISelectable)hit.collider.gameObject.GetComponent(typeof(ISelectable));
secondSelectedObj = hit.collider.gameObject;
IGObjectReceiver rObj = (IGObjectReceiver)firstSelectedObj.GetComponent(typeof(IGObjectReceiver));
if(rObj != null)
{
//Send second selection to first
rObj.receive(secondSelectedObj);
}
firstSelectedObj = null;
secondSelectedObj = null;
if(firsStObj != null){
//if(selectedObj.can)
firsStObj.unselect();
}
if(secondSObj != null){
secondSObj.unselect();
}
}
So by clicking on an object the select() method is called. Which handles stuff that needs to happen on a click. In this case it concerns a unit that needs to move from tile to tile. So in the receive(GameObject obj) the Tile is passed and checked by tag if it's indeed a tile object we need information from.
Answer by whydoidoit · Mar 13, 2013 at 02:33 PM
Right so I think you can probably do what you want using SendMessage.
You could have a static list of selected objects accessible from anywhere:
public static List< GameObject> selectedObjects = new List< GameObject>();
When an object is selected you .Add it to that list and .Remove it when the object is unselected
Then just send Selected, Selectable and Unselected messages to your objects when necessary
public class SelectionState
{
public static SelectionState default = new SelectionState();
public bool selectable;
}
void OnMouseDown()
{
//Example of selections - mouse down to select then also unselect
if(selectedObjects.Contains(gameObject))
{
Unselect();
return;
}
SelectionState.default.selectable = true;
SendMessage("Selectable", SelectionState.default, SendMessageOptions.DontRequireReceiver);
if(SelectionState.default.selectable)
{
selectedObjects.Add(gameObject);
SendMessage("Selected", SendMessageOptions.DontRequireReceiver);
}
}
void Unselect()
{
selectedObjects.Remove(gameObject);
SendMessage("Unselected", SendMessageOptions.DontRequireReceiver);
return;
}
Now on one of your object behaviours:
//Optional method for things that might not be selectable
void Selectable(SelectionState state)
{
state.selectable = true; //some calculation
}
void Selected()
{
//Do whatever
if(SelectionClass.selectedObjects.Any(o=>o is SomeClass)) //Using System.Linq
{
//Do something different when a SomeClass has been selected
}
}
void Unselected()
{
//Do something else
}
Thanks for taking your time. But how do I ensure that any object contains these methods? I would like to enforce it just like I did with the interfaces?