1
\$\begingroup\$

I'm not sure how everyone handles this, but I'm running into lots of instances where I want to call a nonstatic script from another script which forces me to add the nonstatic script to the gameobject that also handles the other script. Such as, I would have two classes in different scripts:

public class Example1:MonoBehaviour{
public void someMethod(){
}
}

    public class Example2:MonoBehaviour{
public void anotherMethod(){
}
}

if I wanted to call anotherMethod from someMethod, I would need to do this:

   public class Example1:MonoBehaviour{
    private Example2 exampleTwo;

void Awake(){
exampleTwo = gameObject.AddComponent<Example2>();
}
        public void someMethod(){
exampleTwo.anotherMethod();
        }
        }

Is this really how everyone is working? It just seems extremely long and complicated, making me attach a whole bunch of scripts to one gameobject at runtime, and then I run into a whole bunch of issues with multiple copies of each script (such as with mousedown functions or input functions).

\$\endgroup\$
  • \$\begingroup\$ In addition to the answers below, don't forget that Scripts in Unity are Classes...Classes are used to create instances of objects (static classes/methods/variables just referring to a single instance), and object instances "own" methods, classes don't. \$\endgroup\$ – XNargaHuntress May 21 '15 at 13:40
3
\$\begingroup\$

How exactly this is best handled depends on the exact use case. The two main use cases are: 1. You want to access a shared background object that persists throughout the game. 2. You want to access a specific object within the scene.

For situation 1, you could use one of the code patterns like Service Locator or singleton (justin's suggestion is basically a Unity flavored singleton). Alternatively you could use FindObjectOfType() to reference an existing object in the scene.

For situation 2, you can simply drag the object onto a variable in the Inspector. In other words, create a serialized variable at the top of the script (eg. public Example2 otherScript) and then that variable will appear in the Inspector so that you can drag in an object in the scene. Now you can call any public methods of that object.

(incidentally, as zee points out the AddComponent command does exactly what it says, it adds a new component, not give you access to an existing component. If you don't want a new component added, then use a different command like GetComponent)

\$\endgroup\$
2
\$\begingroup\$

Let me first question you on a few things.

exampleTwo = gameObject.AddComponent();

Do you really need to ADD a script to your object during runtime? Why? I mean I can understand adding a collider to an object that you didn't want to collide at some point, adding lots of things are explainable. But why Add a script? Why not just keep it attached to the object, and then it's your choice if you are going to use it or not.

I would have two classes in different scripts

The first question you should ask yourself is : "Can I get rid of one of them"? I once ran into a case where I had 3 scripts that would switch between themselves in a loop. I just sat down and thought, why do I need three? You will probably be able to merge all the methods you have in Example1 with Example2. I hope you consider it.

Now for your issue :

It just seems extremely long and complicated, making me attach a whole bunch of scripts to one gameobject at runtime, and then I run into a whole bunch of issues with multiple copies of each script (such as with mousedown functions or input functions).

That is exactly what I asked you. Why are you attaching scripts at runtime? If you want an object to have a script attached to him all the time, just Select him in the Hierarchy, Add Component > Scripts > Choose your desired script from the list. If that object does not appear from the start of the scene, and is instanciated from a prefab, just add the script(s) to the prefab.

Ultimately, if you were to remove the "AddComponent" method from your script, and wanted to address another script, it would be something like this :

public void someMethod(){
this.getComponent<Example2>().anotherMethod();
        }

Piece of cake? Addresing scripts that exist as component of the same object couldn't be easier this.getComponent<className>().methodName().

Other than that, if you have a variable/method that is relatively "unique" in your script, consider making that variable/method static, not the whole class. So instead of this.getComponent<className>().methodName(), you would simply use className.methodName(), or className.variableName. Cheers.

\$\endgroup\$
  • \$\begingroup\$ hey I appreciate the comment. I just want to clarify a few things -- I don't THINK i'm attaching a script at runtime. All scripts are attached to a game object. I just have a method in one script that I want to call in another script \$\endgroup\$ – Jeff Burghess May 21 '15 at 5:22
  • 1
    \$\begingroup\$ You ARE attaching a script at runtime. AddComponent is a method to ADD a component during runtime. The cases where you will need to use this are ever so rare, I have no idea how you know about the method in the first place. Anyhow, if you want to attach a script to an object in the scene, just select that object, Add component through editor, and select your script. And remove any lines in your code that contain AddComponent(). \$\endgroup\$ – Zee May 21 '15 at 5:24
  • \$\begingroup\$ I followed your advice but I'm still getting an error when I remove addcomponent. In one of my scripts attached to the gameobject, in awake I declared nWM = gameObject.AddComponent<NavigateWorldMap>(); and then I used nWM.FindClosestWaypoints();. This worked. I tried doing what you said. I deleted the addcomponent line (as well as the line where I declared what nWM was). I attached the NavigateWorldMap script to my gameobject (so now it has two scripts). so Now I only have NavigateWorldMap.FindClosestWaypoints();. \$\endgroup\$ – Jeff Burghess May 21 '15 at 5:41
  • \$\begingroup\$ Did you go to your hierarchy and add the script to your object? You can just drag your script and drop it on your object. \$\endgroup\$ – Zee May 21 '15 at 5:42
  • \$\begingroup\$ sorry I accidentally submitted my comment. I've updated my comment above with more pertinent information. The specific error I'm getting is:Assets/Scripts/MouseClick.cs(29,34): error CS0120: An object reference is required to access non-static member `NavigateWorldMap.FindClosestWaypoints()' I dragged my script onto the inspector \$\endgroup\$ – Jeff Burghess May 21 '15 at 5:46
0
\$\begingroup\$
 public class Example2:MonoBehaviour{
 public static Example2 Instance;
 void Awake()
 {
     Instance = this;
 }
  //Now you can access the public methods or variable of Example2 from any class by 
  Example2.Instance.YourMethodOrVariable;
 }  
 //---------------------------------------------------------------------------------
 //But if you have a Boolean in your Example1 and don't want to make a whole Instance of the class you can
 public static bool example1ClassBool = false;
 //then from any other class you can use
 Example1.example1ClassBool = true;
 //---------------------------------------------------------------------------------
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.