Running a Method from One Script in a Separate Script

I have run into the error code:

“NullReferenceException: Object reference not set to an instance of an object

StarterAssets.ThirdPersonController.YesIsAttacking () (at Assets/Scripts/ThirdPersonController.cs:37)”

This happens whenever I try to run the Method “Damage()” (this is within the “TrainingDummy” script) from another script “ThirdPersonController”.

public GameObject objectTD;

        public void YesIsAttacking()
        {
            _animator.SetBool("IsAttacking", true);



            // set triggerStay to true if the katana is already in the Training Dummy hitbox or false if not
            triggerStay = GameObject.Find("katana").GetComponent<Sword>().IsTriggerStay();
            if (triggerStay == true)
            {
                // assign ObjectTD to the training_dummy in the scene
                objectTD = GameObject.Find("training_dummy");

           

            }
        }

        public void NotIsAttacking()
        {
            _animator.SetBool("IsAttacking", false);
        }

I have looked online and double and triple checked that all the code I am using is exactly as it should be. I have even used the exact same code in another script in the same project to run my “HitSound()” method (this is within the “Sword” script) from the “TrainingDummy” script and it works perfectly.

public void Damage()
    {
        GameObject.Find("katana").GetComponent<Sword>().HitSound();
        health++;
        Debug.Log("Enemy Health: " + health);
        enemAnim.SetTrigger("Hit");
    }

I can get the “training_dummy” as a GameObject in the “ThirdPersonController” script. I only get the error when I then use that GameObject to get “TrainingDummyScript” and run the “Damage()” method. When I ran the code shown below I got back “No Training Dummy” in the console.

public GameObject objectTD;

        public void YesIsAttacking()
        {
            _animator.SetBool("IsAttacking", true);



            // set triggerStay to true if the katana is already in the Training Dummy hitbox or false if not
            triggerStay = GameObject.Find("katana").GetComponent<Sword>().IsTriggerStay();
            if (triggerStay == true)
            {
                // assign ObjectTD to the training_dummy in the scene
                objectTD = GameObject.Find("training_dummy");

                // if the script can't find the TrainingDummy Script then return "No Training Dummy" in log
                if (objectTD.GetComponent<TrainingDummy>() == null)
                {
                    Debug.Log("No Training Dummy");
                }
                // if the script can find TrainingDummy script then run Damage() function in that script
                else
                {
                    objectTD.GetComponent<TrainingDummy>().Damage();
                }

            }
        }

        public void NotIsAttacking()
        {
            _animator.SetBool("IsAttacking", false);
        }

I’ve attached images of the error code I got as well as the Hierarchy, and the inspectors of the sword, player, and training dummy.

I am sure I could code a work around to solve the problem I am trying to fix in another way, but being able to run a method from another script is so fundamental I want to figure out why it’s not working now for future reference.





wow, that’s a lot to take in. Please paste code into the code button at the top(tabs/button sections) of making posts, one for readability, and two it’s easier for us to copy, fix, paste back a fix. :slight_smile:

May I ask why you’re not using OnCollisionEnter/Stay? Because with getting the collider from the hit, and then using GetComponent() is actually more performant than other methods. And easier to communicate between scripts, like your instance here.

Nothing matters until you fix it.

The answer is always the same… ALWAYS!

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Three steps to success:

  • Identify what is null ← any other action taken before this step is WASTED TIME
  • Identify why it is null
  • Fix that

After you fix that, if you still have an issue:

How to report your problem productively in the Unity3D forums:

http://plbm.com/?p=220

This is the bare minimum of information to report:

  • what you want
  • what you tried
  • what you expected to happen
  • what actually happened, log output, variable values, and especially any errors you see
  • links to documentation you used to cross-check your work (CRITICAL!!!)

The purpose of YOU providing links is to make our job easier, while simultaneously showing us that you actually put effort into the process. If you haven’t put effort into finding the documentation, why should we bother putting effort into replying?

Do not TALK about code without posting it. Do NOT retype code. Copy/paste and post code properly. ONLY post the relevant code, and then refer to it in your discussion. Do NOT post photographs of code.

If you post a code snippet, ALWAYS USE CODE TAGS:

How to use code tags: https://discussions.unity.com/t/481379

Referencing variables, fields, methods (anything non-static) in other script instances:

https://discussions.unity.com/t/833085/2

https://discussions.unity.com/t/839310

It isn’t always the best idea for everything to access everything else all over the place. For instance, it is BAD for the player to reach into an enemy and reduce his health.

Instead there should be a function you call on the enemy to reduce his health. All the same rules apply for the above steps: the function must be public AND you need a reference to the class instance.

That way the enemy (and only the enemy) has code to reduce his health and simultaneously do anything else, such as kill him or make him reel from the impact, and all that code is centralized in one place.

I pasted the code as you mentioned, I’m fairly new to this so pardon my mistake. I am using the OnCollisionEnter/Stay functions the problem I was trying to fix was the IsAttacking variable in the animation would sometimes start while inside the collider of the enemy and I wanted to make sure that still got counted as a hit. Not just if it started then collided with the enemy. The IsTriggerStay() function just lets the script know that the Sword is currently in a collider tagged Enemy not any other potential objects using the OnCollisionStay.

You are of cousre welcome to type as much as you like about this subject…

…but 100% of it is likely irrelevant until you fix the NullReferenceException.

I’m not exaggerating. Once the nullref happens, NOTHING else can be reasoned about.

That’s just how exceptions work. See my post above.

GameObject.Find() is just not picking up the object correctly. While it’s often found in tutorials and example code it’s generally not a good idea to use it as it leads to these kinds of headaches. Instead if you can you should make a public field in your script and manually link up the objects.

Alternatively, if these objects are being instantiated at runtime, have the code that is responsible for instantiating them hook them up too.

I believe I did fix my reporting errors sorry for the improper format at first. I am trying to fix the Null Reference that is what this post is about. I’ve identified it’s only getting the null reference when it tries to get the “TrainingDummy” script. The problem I’m running into is I can’t figure out why it’s reporting back null as everything is set to public and and every line of code seems to be exactly as it should. As I mentioned I’ve used the exact code before to run a different method from a different script and I can’t find the difference between the two (This is what I mentioned in my original post when talking about the “HitSound()” function). I am aware there are many ways to work around this problem so I don’t need to run this method from another script however since I am learning Unity and C# still I would like to find out how to run a method in another script correctly for future projects.

I am confused by how it’s not finding the object correctly. Forgive my potential ignorance but I don’t seem to run into any problems picking up the GameObject I only get the Null Reference Exception when I then try to get the Script. That’s what this code provided because I got no errors only the “No Training Dummy” in the console which is triggered when it runs into a problem getting the script.

public GameObject objectTD;
        public void YesIsAttacking()
        {
            _animator.SetBool("IsAttacking", true);
            // set triggerStay to true if the katana is already in the Training Dummy hitbox or false if not
            triggerStay = GameObject.Find("katana").GetComponent<Sword>().IsTriggerStay();
            if (triggerStay == true)
            {
                // assign ObjectTD to the training_dummy in the scene
                objectTD = GameObject.Find("training_dummy");
                // if the script can't find the TrainingDummy Script then return "No Training Dummy" in log
                if (objectTD.GetComponent<TrainingDummy>() == null)
                {
                    Debug.Log("No Training Dummy");
                }
                // if the script can find TrainingDummy script then run Damage() function in that script
                else
                {
                    objectTD.GetComponent<TrainingDummy>().Damage();
                }
            }
        }
        public void NotIsAttacking()
        {
            _animator.SetBool("IsAttacking", false);
        }

I do appreciate the suggestions of making a public field in my script instead and will look into how to do that. That is not something I believe I have tried before.

And… yet here we are. :slight_smile:

Don’t focus on the particulars of what you are doing. They aren’t relevant.

The problem is what you’re NOT doing.

Focus on the three steps.

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Three steps to success:

  • Identify what is null ← any other action taken before this step is WASTED TIME
  • Identify why it is null
  • Fix that

ALSO:

Remember the first rule of GameObject.Find():

Do not use GameObject.Find();

More information: https://starmanta.gitbooks.io/unitytipsredux/content/first-question.html

More information: https://discussions.unity.com/t/899843/12

In general, DO NOT use Find-like or GetComponent/AddComponent-like methods unless there truly is no other way, eg, dynamic runtime discovery of arbitrary objects. These mechanisms are for extremely-advanced use ONLY.
If something is built into your scene or prefab, make a script and drag the reference(s) in. That will let you experience the highest rate of The Unity Way™ success of accessing things in your game.

When GameObject.Find() fails to find an object it will return null, and then when you call GetComponent() it sees null rather than the object giving you the error.

That makes perfect sense thank you!

Well, to be fair, GameObject.Find(“x”) is horrible. The only .Find() that works for me is when getting children objects in your hierarchy(transform.Find("Player/metarig/spine.001/ ... /rightHand").gameObject;).

To which it looks like you could do for the katana, but it’d be much easier for katana.cs to say “player.katana = this;”.

Which first and foremost, I always use classes as the thing to branch from, or call/set to/from.
i.e.

//Player.cs
Katana katana;

void BuffKatanaDamage(float amount)
{
   katana.damageValue += amount;
}

or something along those lines…

So why I mentioned OnCollisionEnter(), would be when Katana.cs has that method, you would easily say something like

Enemy enemy = collider.GetComponent<Enemy>();
enemy.TakeDamage(damageValue);
didHitEnemy = true;
player.currentEnemy = enemy;
player.score += 50;

// other method
if (didHitEnemy)
{
   playSound("clink");
   TurnOnBlueAura();
   didHitEnemy = false;
}

But that’s just the way I do things, I always use class instances, and pass them around from script to script if needed. That way I’m not performance hogging the compiler with tons of “GetComponents” everywhere. :slight_smile: