this seems a simple task but has got me going crazy for the last week, i have searched and tried several ways but just wont work.i have a gameobject with SCRIPT A and a prefab with SCRIPT B, i need to call a function on SCRIPT A from the instantiated prefab with SCRIPT B, whatever way i try comes back with null reference error or other errors, i really didnt think this would be so hard to do, i know that you cant drag a gameobject into a prefab slot for reference and have tried using public static void on the function on SCRIPT A that SCRIPT B needs to call but still gives an error. is there a way in unity 5 to get this to work as i have not found a working way yet.
What you are trying to do in the first place?
And how are you trying to get the GameObject with script A on it in script B?
Script to script communication is the hardest thing to learn to do in Unity. Not that it’s especially hard, just that it comes very early in the learning process, and is pretty critical.
It’s a three step process
- Get a reference to the GameObject the script is on
- Get a reference to the script
- Access the variable/method
For you it might look like this
void Start (){
// Step one
GameObject clone = (GameObject)Instantiate(myPrefab);
// Step two
MyComponent myComponent = clone.GetComponent<MyComponent>();
// Step three
myComponent.DoSomething();
}
It may be helpful to clarify how that example relates to the question’s “SCRIPT A”:
void Start (){
// Step one
GameObject clone = (GameObject)Instantiate(myPrefab);
// Step two
SCRIPTA myComponent = clone.GetComponent<SCRIPTA>();
// Step three
myComponent.DoSomething();
}
In that case the class name in SCRIPT A would be literally “SCRIPTA”.
Also, the code above wouldn’t really be in “SCRIPT B” – it would be some third thing since it creates an instance of the prefab (which is where SCRIPT B is located that needs to call SCRIPT A). But the important part is the GetComponent line which would go in SCRIPT B.
script to script is not a problem as i can get that working it is when a prefab script needs to call a function on a gameobject that is not another prefab. so it it is script on a prefab to a non prefab gameobject script, i cant get the link to work, let me try give a simple example of the problem,
i have enemy aliens that are prefabs with enemyalien script atached, in the script when the alien dies it adds 10 points to the score, i have a gameobject called gamemanager with the manager script on it, in the manager script is the gui to display the score, it has a function that is called that will update the score, the score is set to 0 in the manager script, in the manager script is a function to update the score to the display, this function needs to be called from the alienscript on the alien prefabs when they die, now because you cant drag a game object onto a prefab public gameobject slot how do i get the script on the prefab to call the function on the manager script on the gamemanager object which is not a prefab,
so to be basic, how does a prefab script call a function on a non prefab gameobject script?
i will give the above help a try.
A script on an active instance of a prefab doesn’t work any different than any other script-to-script call.
The “GetComponent<script_name>” is how you do this from code instead of doing “public script_name” so that you can drag a reference in the Inspector. When a script is dropped on an object (or prefab) you’ll notice it shows up in the Inspector – it is a component. The script’s filename, its class name, and its component name are all the same thing.
From your example, I’m guessing what you’re really asking is how does your prefab find the object with the needed script on it. You can do a Find, which is an expensive operation. I prefer to use a single static class that exposes game elements that need to be located by many other scripts. Using your example of a GameManager and EnemyAlien and a third class I’ll call GameManagerStatic might look something like this:
using UnityEngine;
using System.Collections;
public static class GameManagerStatic {
public static GameManager gameManager;
}
Notice the GameManagerStatic does not inherit from MonoBehaviour and it is not dropped on any object. It is simply a static class in the game’s namespace, which means other code can refer to the GameManagerStatic type. Because it is a static class, you can’t create an instance of it, and the one static field in the class sort of “always exists” and is there and ready to use automatically.
Singletons There is a similar approach called singletons (search, it is explained in the forums frequently) but I think a static class is cleaner most of the time. Briefly, singletons can use inheritance and can be passed as parameters so if you can leverage interfaces for your singleton they’re more flexible. But for this example I think getting into singletons would just be a distraction.
The GameManager script is attached to some scene object, as you described in your example. When it first starts, it makes sure the GameManagerStatic class has a reference to it:
public class GameManager : MonoBehaviour {
void Start() {
GameManagerStatic.gameManager = this;
}
public void UpdateScore(int PointsToAdd) {
// update counter, gui, etc.
}
}
Notice we don’t create the GameManagerStatic class anywhere, it always exists and is ready to use by virtue of the static keywords. Now your EnemyAlien is able to quickly and easily talk to the GameManager with a single line of code:
public class EnemyAlien : MonoBehaviour {
public void Die() {
GameManagerStatic.gameManager.UpdateScore(10);
}
}
Is that what you were trying to accomplish?
i will give it a go and report back, thanks
what i will do is replicate the problem i have in a simple project and upload it here and il explain it.
here is project in rar file
There is 3 objects in the scene, OBA, OBB, GameObject
OBA is a gameobject with ScriptA
OBB is a prefab with ScriptB
GameObject just instantiates OBB into the scene
there is a call from OBB to a function on OBA this is what i cant get to work
thanks
2541397–176562–PREFAB TO OBJECT SCRIPT TEST 4.rar (183 KB)
The problem with that setup is that you’re trying to access instance values (ScriptA’s ScoreText) from a static method (SetScoreText). ScoreText “belongs” to a specific instance of the class, whereas static members belong to the class definition, so to speak. Static methods can’t refer to instance methods or properties because there is no way for the static method to know which instance it should choose. Edit: Also, static members can be accessed even if no instances of the class exists.
The solution I presented above works as follows:
2541419–176563–Assets.zip (11.6 KB)
And technically there’s no reason for “count” to be static here, either, unless you’ll truly have multiple instances of ScriptA that need to share one score. But if ScriptA was meant to be a player script in a multiplayer game, then you’d want each one to have their own score (instanced, not static).
@MV10 thank you, it works like a charm… just one question, so the sharedrefs script does not have to be atached to a game object, it can just sit in the scripts folder or where ever you put your scripts?
Correct. Although Unity doesn’t normally expose it to you by default, all of your “scripts” are actually just C# classes and they live in a “namespace” that is shared between your classes. (You can use different namespaces but that’s a more advanced topic than you probably need to worry about right now.) So any class is visible to all the other classes – and note that I’m referring to class definitions here, not necessarily instances of those classes. The instance of a class is owned by whatever created it. When you drop a MonoBehaviour script on an object, you’re just creating an instance of that class and in that case the object owns it. This is why you have to go searching for an instance of a class (with GetComponent or Find, for example), but the class definition is always visible.
A class that is not a MonoBehaviour is still in the same namespace and still visible to the rest of your code, you just can’t use it as a component on an object. But other classes can create instances of it (with the new keyword). A non-MonoBehaviour class is useful for storing different types of data, for example. In one of my projects I have a class called ShipLibrary. Another script uses a dictionary of ShipLibrary instances to define shield strength, hull strength, engine details, and so on. ShipLibrary doesn’t do anything specific with Unity so it isn’t a MonoBehaviour so it’s just a plain old C# class.
A static class is just a special variation on that in which you can’t create instances of it, and everything in the class must also be static. You can think of it like a big storage container for other variables. A non-static class can also have static members, as you did with ScriptA, but it’s usually less confusing to keep the static and instance members in separate places.