Reputation: 301
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
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
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
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);
}
Upvotes: 1