2

I have a simple touch/mouseclick script attached to a GameObject as a sort of "Master Script" i.e. the GameObject is invisible and doesn't do anything but hold this Touch script when the game is running.

How do I tell other named GameObjects that are generated at runtime to do things e.g. highlight when touched/clicked from this Master Script?

The script for highlighting seems to be: renderer.material.color= colorRed;

But I'm not sure how to tell the GameObject clicked on to become highlighted from the Master Script.

Please help! (am programming in C#) Thanks!

Adrian Krupa
  • 1,877
  • 1
  • 15
  • 24

3 Answers3

1

Alright so you'll want to use a ray cast if you're not doing it in GUI. Check out Unity Ray Casting and then use

hit.transform.gameObject.renderer.material.color = red;

You can have a switch that is like:

if (hit.transform.gameObject.CompareTag("tag")) {
    // turn to red;
} else {
    // turn to white;
}

Use the ScreenPointToRay or ScreenPointToWorld depending on what you're doing.

For touch, should look like:

void Update () {
    foreach (Touch touch in Input.touches)
    {
        Ray ray = Camera.main.ScreenPointToRay(touch.position);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 1000.0f))
        {
            if (hit.collider.gameObject.CompareTag("tag"))
            {
                hit.collider.gameObject.renderer.material.color = red;
            }
        }
    }
    // You can also add in a "go back" feature in the update but this will "go back" then when the touch ends or moves off
    // Also not so good to search for Objects in the update function but that's at your discretion.
    GameObject[] gObjs = GameObject.FindGameObjectsWithTag("tag");
    foreach (GameObject go in gObjs) {
        go.renderer.material.color = white;
    }
}

To answer your question about pinging the 'manager'

I would do one of two options. Either:

// Drop the object containing YourManager into the box in the inspector where it says "manage"

public YourManager manage;

// In the update and in the Ray Cast function (right next to your color change line):
manager.yourCall ();
// and
manager.yourString = "cool";

OR

private YourManager manage;

void Awake () {
    manager = GameObject.FindObjectWithTag("manager").GetComponent<YourManager> ();
}

// In the update and in the Ray Cast function (right next to your color change line):

// In your manager file have "public bool selected;" at the top so you can access that bool from this file like:
manager.selected = true;

I detail this a little in another one of my answers HERE

For mouse clicks, I would check out the MonoDevelop functions they have in store such as:

// This file would be on the game object in the scene
// When the mouse is hovering the GameObject
void OnMouseEnter () {
    selected = true;
    renderer.material.color = red;
}

// When the mouse moved out
void OnMouseExit () {
    selected = false;
    renderer.material.color = white;
}

// Or you can use the same system as above with the:
Input.GetMouseButtonDown(0))

Resolution:

Use a bool in your manager file true is selected, false isn't. Have all the objects you instantiate have a tag, use the ray cast from the master file to the game object. When it his the game object with that tag, swap colors and sap the bool from the master file. Probably better to do it internally from the master file. (All depends on what you're doing)

Community
  • 1
  • 1
iSkore
  • 7,394
  • 3
  • 34
  • 59
0

If you know what the name of the GameObjects will be at runtime, you can use GameObject.Find("") and store that in a GameObject variable. You can then set the renderer of that GameObject to whatever you like (assuming a renderer is linked to that GameObject).

Rahin
  • 943
  • 6
  • 21
  • 1
    Ehh, you don't really want to use the .Find. Rahin is right about the caching, but if you're doing an "on-off" selection switch with calls back or whatever to the manager and with the fact that the GameObjects are Instantiated, you will use this more than necessary to search every time you instantiate something. Unity say "For performance reasons it is recommended to not use this function every frame..." and then talks about the caching here: [GameObject.Find API Reference](http://docs.unity3d.com/ScriptReference/GameObject.Find.html) – iSkore May 20 '15 at 11:32
0

The most obvious way of doing this would be to use prefabs and layers or tags. You can add a tag to your prefab (say "Selectable") or move the prefab to some "Selectable" layer and then write your code around this, knowing that all selectable items are on this layer/have this tag.

Another way of doing this (And in my opinion is also a better way) is implementing your custom 'Selectable' component. You would search for this component on a clicked item and then perform the selection, if you have found that component. This way is better because you can add some additional selection logic in this component which would otherwise reside in your selection master script (image the size of your script after you've added a couple of selectables).

You can do it by implementing a SelectableItem script (name is arbitrary) and a couple of it's derivatives:

public class SelectableItem : MonoBehavior {

    public virtual void OnSelected() {
        renderer.material.color = red;  
    }
}

public class SpecificSelectable : SelectableItem {

    public override void OnSelected() {
        //You can do whatever you want in here
        renderer.material.color = green;
    }
}

//Adding new selectables is easy and doesn't require adding more code to your master script.
public class AnotherSpecificSelectable : SelectableItem {

    public override void OnSelected() {
        renderer.material.color = yellow;
    }
}

And in your master script:

// Somewhere in your master selection script
// These values are arbitrary and this whole mask thing is optional, but would improve your performance when you click around a lot.
var selectablesLayer = 8;
var selectablesMask = 1 << selectablesLayer;

//Use layers and layer masks to only raycast agains selectable objects.
//And avoid unnecessary GetComponent() calls.
if (Physics.Raycast(ray, out hit, 1000.0f, selectablesMask))
{
    var selectable = hit.collider.gameObject.GetComponent<SelectableItem>();
    if (selectable) {
        // This one would turn item red or green or yellow depending on which type of SelectableItem this is (which is controlled by which component this GameObject has)
        // This is called polymorphic dispatch and is one of the reasons we love Object Oriented design so much.
        selectable.OnSelected();
    }
}

So say you have a couple of different selectables and you want them to do different things upon selection. This is the way you would do this. Some of your selectables would have one of the selection components and others would have another one. The logic that performs the selection resides in the Master script while the actions that have to be performed are in those specific scripts that are attached to game objects.

You can go further and add OnUnselect() action in those Selectables:

public class SelectableItem : MonoBehaviour {
    public virtual void OnSelected() {
        renderer.material.color = red;
    }

    public virtual void OnUnselected() {
        renderer.material.color = white;
    }
}

and then even do something like this:

//In your master script:
private SelectableItem currentSelection;

var selectable = hit.collider.gameObject.GetComponent<SelectableItem>();
if (selectable) {
    if (currentSelection) currentSelection.OnUnselected();
    selectable.OnSelected();
    CurrentSelection = selectable;
}

And we've just added deselection logic.

DISCLAIMER: These are just a bunch of snippets. If you just copy and paste those they probably wouldn't work right away.

MarengoHue
  • 1,789
  • 13
  • 34