I'm trying to call a function called dieAnim() in one script from another script, called Magnum.
This is in my Fire function in the Magnum script:
if (hit.collider.tag == "Alien1")
{
Alien.dieAnim();
}
In the Alien script:
public void dieAnim()
{
Destroy(gameObject);
}
Everytime i try to run this, it says Object reference not set to an instance of an object.
To run this more efficiently do
if(hit.collider.CompareTag("Alien1")){
//either
Destroy(hit.gameObject);
//or if there is logic in dieAnim()
hit.collider.GetComponent<Alien>().dieAnim();
}
The reason your code was not working was because you were calling the dieAnim() function as if it were on a static component. That means you were trying to call it on all scripts basically. You have to have a reference to that instance of the alien that you hit. The CompareTag is just a special function that allows you to compare tags of gameobjects more quickly and efficiently than a string == string comparison.
In the above it looks like you're trying to call dieAnim() from the Class name of Alien
You'll want to use
hit.collider.gameobject.GetComponent<desiredcomponent>().dieAnim();
In this you're accessing the instance of the Alien class as a component.
Edit for clarity.
In the editor when you add a script you're adding a new monobehavior. These are attached to a game object as components. So when you want to access one, you have the access the components of the game object.
So in your case to get the other script you need to call get component on your the game object your colliider hit. The tag is also attached to the game object itself
Just re-write your code to the following
if (hit.collider.tag == "Alien1")
{
hit.collider.GetComponent<Alien>().dieAnim();
}
But if the the only thing that dieAnim is doing is destroying the alien that was hit, you don't need to call a function inside of another script for that - that's overkill.
Just do this
if (hit.collider.tag == "Alien1")
{
Destroy(hit.gameObject);
}
Related
I the user to be able to select an object then a script which is within and then a void which is within the script.
So basically, inside the inspector of script1 I want to user to be able to select an object, then a script which is within it and then a void of the script.
The player has to select functions the same way as in UI button.
Implementing such a Drawer for the Inspector yourself requires reflection and is quite complicated (see the source code of UnityEventDrawer).
Anyway, I guess you are actually talking about simply using your own UnityEvent (That's exactly what the Button.onClick uses) in your script like e.g.
public class Example : MonoBehaviour
{
public UnityEvent OnSomethingHappened;
// And invoke it where needed
private void Update()
{
if(Input.GetKeyDown(KeyCode.Space)) OnSomethingHappened?.Invoke();
}
}
I am trying to understand why I am getting a missing reference exception after a scene change when using singletons.
So, I have two GameObjects in the first scene. A main camera with a GameManager script attached and another shop object with a Purchaser script attached. Both scripts are also singletons created like this for example:
public static Purchaser Instance
void Awake(){
Instance = this
}
They then both reference each other in the Start() function, again like this for example:
void Start(){
game = GameManager.Instance
}
Before a scene change, both scripts use each others singleton references to call methods from one another and everything seems to be working fine. Once I change scenes neither of those objects is in the next scene so they both get destroyed. However, once I go back to the main scene I receive a missing reference exception when the purchaser script attempts to call a method from GameManager using the singleton reference it gets from Start(), that changes the text of a text object attached to the main camera. This function is called after a button is pressed that is attached to the shop object that calls this function in the Purchaser script:
UpdateMoney(){
game.UpdateMoney(100);
}
I read around and was seeing that this may be because Start() will only being called once throughout the whole game run. Which meant the GameManger singleton instance of the Purchaser script was still the old one from before the scenes changed and that instance was destroyed. But, I just tested to see if this was true by putting a debug log in each scripts Start() function, and saw that after each scene change back to the main scene the debug log would go through from both scripts Start(). So, would it be right to say Start() is only ever called once for the life of script but not for the whole game run right? Shouldn't this also mean that once the game changes back to the main scene and both GameObjects are created again, the Purchaser script should now have an updated reference to the newly created GameManager script since Start() was called again?
What I also found was that this worked instead of using the game reference in UpdateMoney():
UpdateMoney(){
GameManager.Instance.UpdateMoney(100);
}
So, why does this work instead of using the game reference retrieved in Start()? Does this mean when Start() is called GameManager.Instance is still the old GameManager.Instance which is why game = GameManager.Instance does not work? Sorry this is very wordy. Any help is much appreciated.
Based on what I understand, you have a singleton made in the main scene. The game object where the singleton is attached to is destroyed after switching scenes.
First of all, is there a reason why you need the singleton to be a MonoBehaviour and attached to a game object? Because you can just make a class with
private static MyClass instance = null
public static MyClass Instance
{
get {
if(instance == null)
instance = new MyClass();
return instance;
}
}
This way, your singleton will always have a value and can be passed thru scenes unless instance is set to null.
Second, Start() is called once only. However, I encountered issues before that if the MonoBehaviour is attached to a disabled game object, the Start() will not be called. You can check if this is what's happening to you when you switch back to the main scene.
Third, if you really need the singleton to be a MonoBehaviour, you can use DontDestroyOnLoad(instance.gameObject) so the game object of the singleton will not be destroyed even after a scene switch. However. I assume the game objects are set on the scene. If it is not from a prefab, you can just do something like this
private static MyClass instance = null;
public static MyClass Instance
{
get {
if(instance == null){
GameObject inst = new GameObject("MyClass Singleton");
instance = inst.AddComponent<MyClass>();
DontDestroyOnLoad(inst);
}
return instance;
}
}
If you do this, then you can remove the preset game objects from the main scene and let the first call to MyClass.Instance make the game object for you.
Lastly, if you do not want to do that, you should set instance = null; on the game object's OnDestroy() so that when you enter the main scene, the new instances will be set to the singleton. This would mean the singleton will not have a value after you switch scenes outside of the main scene.
Example: GameObject A has a script attached to it called MakeItRain. Inside that script is a public void Drizzle();
GameObject B also has a script and wants to tell MakeItRain to do Drizzle();
Inside the script of GameObject B, I can do this:
public GameObject makeitrain;
and then I have to use GetComponent to reach Drizzle(); in my code.
In the inspector, I drop GameObject A into the slot of makeitrain and I'm done.
However, I could also do this in the script of GameObject B:
public MakeItRain makeitrain;
and then just call makeitrain.Drizzle(); in my code of GameObject B's script, without GetComponent.
In both cases, in the Inspector, I have to drag and drop GameObject A into the slot of GameObject B.
Is there a difference or reason why I should definitely not do the last option? I understand that the first method gives me more flexibility because I could call other components of GameObject A as well and not just the script's stuff. Just wondering if there is any other rationale for not doing the second method.
The answer depends if you need to call any function or use variable from the MakeItRain script.
If you don't need to to call any function in the MakeItRain script or access any variables from it then it is better to use GameObject as the reference. Also, if what you need to do is activate, de-active, rotate the GameObject then use the GameObject as reference.
On the other hand, if you need to be able to call a function such as Drizzle or access a variable from the MakeItRain script from multiple places, then you need to use the MakeItRain reference. At this time, it doesn't make sense to use the GameObject reference since by using it, it's required to use GetComponent every-time you need to call a function or access a variable from the MakeItRain script attached to it.
Finally, when using the MakeItRain script to reference your object, you can directly and easily access the GameObject it is attached to without using the makeitrain.gameObject. This doesn't require the use of the GetComponent function.
Just wondering if there is any other rationale for not doing the
second method.
Performance issue due to the required use of the GetComponent function is the reason. Using it once in the Start or Awake function and initializing your MakeItRain variable is better.
For example, this is better:
public MakeItRain makeitrain;
void Start()
{
makeitrain = GetComponent<MakeItRain>();
}
void Update()
{
makeitrain.Drizzle();
}
than this:
public GameObject makeitrain;
void Update()
{
makeitrain.GetComponent<MakeItRain>().Drizzle();
}
And should be used to avoid having to search for the component on the native side every frame.
Using MakeItRain and explicitly defining the type is better than using GameObject.
As #hacksalot commented, using MakeItRain offers strong typing. One of the benefits of this is related to your comment:
In both cases, in the Inspector, I have to drag and drop GameObject A
into the slot of GameObject B.
If you explicitly set the public variable type to MakeItRain rather than GameObject, it is not possible to drag and drop a GameObject A into the slot of GameObject B unless GameObject A is has a script of the correct type. This gives you a compile-time/editor-time check that you are linking to the correct GameObject in the Unity Editor inspector.
Also, while not necessarily so, using GameObject references often encourages messier code, whether because of unnecessary chaining of methods together (e.g. GetComponent) just because the type wasn't specified, or because it adds a bit of friction to writing & using helper methods. Consider even in a simple example which one reads better:
makeitrain.Drizzle()
makeitrain.GetComponent<MakeItRain>().Drizzle()
I understand that the first method gives me more flexibility because I
could call other components of GameObject A as well and not just the
script's stuff.
Note that you still have the flexibility to access GameObject, it's just a bit more verbose (which is one downside of this approach):
public MakeItRain makeitrain;
void Start()
{
makeitrain.gameObject.SetActive(false)
}
However, you'll likely be using helper methods anyway (for anything more than basic calls), or even wrapper methods (which are inconvenient to write but sometimes helpful for readability).
In most cases, the benefits of linking to the class rather than the GameObject outweigh the downsides.
If u don't want to use GetComponent(), you can simply use SendMeassage(), like this
public Gameobject makeItRain;
void Start(){
makeitrain.SendMeassage("Drizzle");
}
Another way to link a script is that use FindObjectOfType(), which do not need to drag and drop GameObject into the slot, here is the sample
void Start(){
MakeItRain makeitrain = FindObjectOfType("MakeItRain");
}
Also you can use Gameobject.Find() to link a GameObject instead of dragging into slot, but I don't recommand this way, it cost a lot performance since you need to find every single GameObject in scene.
Like in here, but the difference is that it's supposed to be done from an instantiated prefab, so I can not drag the GameObject, that has the script with the variable I want to access, into this script.
This was working
public ScriptA script;
void Update() {
if (script.varX < 0) {
// . . .
}
}
But now I'm getting "Object reference not set to an instance of an object" error, which I think comes from the fact that the script trying to access ScriptA, is attached to an instantiated prefab.
How do I attach scripts and/or GameObjects at runtime?
Looks like you need to find your script type first, if it already exists in the scene:
public ScriptA script;
void Start()
{
script = GameObject.FindObjectOfType<ScriptA>();
}
void Update()
{
if(script.variable...)
}
You want to use AddComponent, like:
ScriptA script = gameObject.AddComponent<ScriptA>() as ScriptA;
See the docs here:
https://docs.unity3d.com/ScriptReference/GameObject.AddComponent.html
Best way to satify the links is fill the fields in the very next lines after you instantiate, that way you can avoid ugly and expenstive Find* calls (I am assuming the script that does the instancing can be made aware of what the target objects are, after all it knows what and where to instantiate)
Its worth noting that newly instantiated scripts' Awake() method will be called before Instantiate() returns, while its Start() will be called at the start of following frame, this is a major difference between the two calls, so if your instantiated script needs the refectences in Awake() you should either refactor (move stuff to Start()) or use Find* as suggested earlier.
Is there anyway I can be notified (possibly through some method/event raised) when a Component is added to a GameObject (and even child GameObject)?
I'd like to be notified(possibly in some editors scripts) when some events occurs in the editor for example:
A Component has been attached to a GameObject instance
A Component has been attached to a Prefab
A GameObject has become child of another GameObject istance
Is this possible?If yes how?
EDIT
I found out a delegate for what concern parenting:EditorApplication.hierarchyWindowChanged
Accordingly to the doc it's called :
Called whenever the scene hierarchy has changed.
This is transform.parent changed, gameObject.name, creating a new game
object, etc.
I still don't understand if there's a convinient way to understood which Object in the hierarchy has been changed.
You can add a component to an object in your (editor-only) level-editing scene:
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
public class LevelEditorHelper : MonoBehaviour
{
LevelEditorHelper()
{
EditorApplication.hierarchyWindowChanged -= MyHierarchyChangedCallback;
EditorApplication.hierarchyWindowChanged += MyHierarchyChangedCallback;
}
private static void MyHierarchyChangedCallback()
{
Debug.Log("Hierarchy has changed");
}
}
#endif
Then within the callback you can access the current selected object (the added object will be the active selection):
GameObject activeObj = Selection.activeGameObject;
if(activeObj != null) {
...
And now you can check its parent to see if it matches whatever other object, and perform other checks to ensure this is actually the event you're interested in (remember it will be called for various other hierarchy changes too), then you can call another function to do whatever action you want.
Note: This won't work as-is for in-game scenes, if you edit your in-game scenes directly with your level-editor scripts then you'll need to use more careful placement of #if UNITY_EDITOR and consider how to remove the unnecessary component (perhaps in Start or at build-time if possible), or just leave it there doing nothing if you're happy with that. In my case my level editor is an editor-only scene, and it saves out a specific sub-set of the editor scene as a scene for use in-game.
There is no "built-in" way of doing this conveniently. However, you could simulate it in a couple of ways.
Utilize the Awake() function in your Component to call it's parent gameObject (SendMessage works very cleanly for this) [note: this only works if you're adding a NEW component instance]
OR
Create a variable to track it's parent. In the Update() method, check current parent to trigger the SendMessage to the new parent.
Here's just 2 examples of what could work for situation--there's plenty more. At the end of the day, nothing built is (as of yet), but certainly do-able from a work-around standpoint.