Distraction Arrestor
Distraction Arrestor

Reputation: 301

Unity3D: Accessing a Method from the only script available in a transform

Scenario:

I have 10 objects in a scene. Each Object has a unique class attached. On clicking one object, Two methods need to be called.

What I've done:

if (Physics.Raycast(ray, out hit)) {
hit.transform.GetComponent(hit.transform.name+"").Show_status (true);
current_transform.GetComponent(current_transform.name+"").Show_status(false);
current_transform = hit.transform;
}

Here, I am trying to access the Script using the string as the script is named after the gameObject itself. A method named "Show_status()" is available for all the classes. The above code produces the below error.

"UnityEngine.Component' does not contain a definition for `Show_status"

Also, if this isn't possible the way I'm attempting it, it would be helpful to mention some other simple approaches to solving the scenario.

Upvotes: 1

Views: 279

Answers (3)

Programmer
Programmer

Reputation: 125315

Accessing GameObject by name is slow. hit.transform.name is slow and allocates memory each time it is called. Getting component by string name(GetComponent(string)) is slow too.

if this isn't possible the way I'm attempting it, it would be helpful to mention some other simple approaches to solving the scenario.

This can easily be done with an Interface.

Create a simple script called IClickable This is not a class. It is an interface.

public interface IClickable
{
    void Show_status(bool value);
}

Your 10 Scripts(Implement IClickable in each one):

Script1 called ObjectToClick1.

public class ObjectToClick1 : MonoBehaviour, IClickable
{
    //Implement your interface function
    public void Show_status(bool value)
    {
        //Your implementation here
    }
}

Script2 called ObjectToClick2.

public class ObjectToClick2 : MonoBehaviour, IClickable
{
    //Implement your interface function
    public void Show_status(bool value)
    {
        //Your implementation here
    }
}

Script3 called ObjectToClick3.

public class ObjectToClick3 : MonoBehaviour, IClickable
{
    //Implement your interface function
    public void Show_status(bool value)
    {
        //Your implementation here
    }
}

...

...

Now, for the clicking part and detecting which Object is clicked:

public class ObjectTest : MonoBehaviour
{
    Transform current_transform;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //Raycast from mouse cursor pos
            RaycastHit rayCastHit;
            Ray rayCast = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(rayCast, out rayCastHit))
            {
                IClickable tempIClickable = rayCastHit.transform.GetComponent<IClickable>();
                if (tempIClickable != null)
                {
                    tempIClickable.Show_status(true);
                    current_transform.GetComponent<IClickable>().Show_status(false);
                    current_transform = rayCastHit.transform;
                }
            }
        }
    }
}

You can add as many interface as possible. This is very flexible and can be used to detect types of enemies available.

Upvotes: 2

Serlite
Serlite

Reputation: 12258

You need to cast the result of GetComponent() to a class to access its methods - but in your situation, you don't know which script is attached to the GameObject being clicked.

This is one of those cases where inheritance provides a possible solution (the alternative would be to make the status tracking a separate component entirely). Since you have a method which is common between multiple classes, why not just have them all inherit from a class which has that method? Then you don't need to differentiate between which one specifically is on the GameObject being clicked.

So your base class might look like:

public class StatusTracker : MonoBehaviour {
    public virtual void Show_status(bool status){
        // Status-changing code
    }
}

Then the classes you'd actually attach to your GameObjects as components would inherit from StatusTracker and have the form of:

public class SpecializedStatusTracker : StatusTracker {
    public override void Show_status(bool status){
        // Alternative status-changing code
    }
}

Note: You only need to override Show_status() if your class implements it differently from the generic Show_status() - otherwise, you don't even need to define the method in the child class(es)!

Adapting your raycast code accordingly, you can then cast the returned Component to the parent class StatusTracker (using the generic variant of GetComponent()) like so:

if (Physics.Raycast(ray, out hit)) {
    hit.transform.GetComponent<StatusTracker>().Show_status (true);
    current_transform.GetComponent<StatusTracker>().Show_status(false);
    current_transform = hit.transform;
}

Hope this helps! Let me know if you have any questions.

Upvotes: 1

ssell
ssell

Reputation: 6597

The error tells you exactly what is wrong, the Unity Component class does not have a method named Show_status.

You must cast the Component returned by GetComponent to your custom class. Example:

CustomClass yourClass = hit.transform.GetComponent(hit.transform.name) as CustomClass;

if(yourClass) {
    yourClass.Show_status(true);
}

See: GameObject.GetComponent

Upvotes: 1

Related Questions