0

So i have this speech recognition code with a few commands that trigger animations in C# and Unity. So instead of having to activate each animation then deactivate it before switching to another animation I wanted to make it so that whatever animator is active it would automatically detect that, play the corresponding outro animation and go to the next animation all in one command. The solution I came up with is string interpellation.

The problem is I keep getting the error:

Object reference not set to an instance of an object.

In Unity pertaining to the line where (“{outro}”) is referenced and I’m not sure but maybe it’s because I’m trying to use string interpolation across 2 if statements?

P.S without the additional if statement this script works it still runs in Unity with the 2nd if statement but it doesn’t do what it’s supposed to.

if (word == “animator 2”)
{
    if (GameObject.Find(“animator 1”).activeSelf);
    {
        string outro = “animation”;
    }
    GameObject.Find(“animator 1”).GetComponent<Animator>
    ().SetBool(“{outro}”, true);
    GameObject.Find(“animator 2”).GetComponent<Animator>
    ().SetBool(“intro”, true);
}

So upon receiving many responses to this post I am able to narrow my problem down to one simple question.

Is it possible to reference a variable from an if statement?

Because I do need the if statement unless their is some other method that does the exact same thing. The only issue now is the variable “outro” is obviously not even a thing outside of the if statement. I believe if I could reference outro properly this code would work 100%

MasterJ
  • 69
  • 1
  • 1
  • 9
  • Make sure you are using a version of Unity that supports C# 6, then use `$“{outro}”` with the `$` in front. Also, what if the `if` didn't run? What would `outro` be? – Sweeper Sep 22 '19 at 11:16
  • I'm guessing the GameObject "animator 1" doesn't have an Animator component attached. – Fredrik Schön Sep 22 '19 at 11:17
  • The [GameObject.Find](https://docs.unity3d.com/ScriptReference/GameObject.Find.html) and [GameObject.GetComponent](https://docs.unity3d.com/ScriptReference/GameObject.GetComponent.html) documentation states that `.Find` and `.GetComponent` returns `null` if the object cannot be found. so either `animator 1` does not exist so calling `.activeSelf` will throw the exception or or these game objects do not have an `Animator` component so `.SetBool()` will throw the exception – Matt Sep 22 '19 at 11:20
  • Well Matt the only reason i don’t think that is the issue is because when I take out the “{outro}“ part and just replace it with the animations name everything works – MasterJ Sep 22 '19 at 11:23
  • might be since you're only initialising outro in the if statement? move the string outro outside of the if statement – Matt Sep 22 '19 at 11:24
  • Sweeper Thanks I just tried that and it says: The name outro does not exist in the current context. Let me check to see if C# 6 is supported – MasterJ Sep 22 '19 at 11:25
  • There are many basic problems here. To get started, never use "GameObject.Find" for any reason in this setting. Get yourself set up with ordinary variables pointing to those things. This is trivial to do. – Fattie Sep 22 '19 at 12:24

1 Answers1

0

Maybe it is just the formatting here but check your " symbols .. they are strange.

  • The reason your outro string isn't found is because you declare it within the if block ... it is not known outside of this scope. Declare the variable outside of the if block. You could/should even make it a const since it doesn't change anywhere between its declaration and usage.

  • If you would use a string interpolation it has to start with a $ symbol

    SetBool($"{outro}", true);
    

    However in this case you pass only exactly one simple string value so there is absolutely no need to use string interpolation at all. Rather simply pass in the variable itself

    SetBool(outro, true);
    
  • The NullReferenceExceptions comes either from your Find or GetComponent call.

    Since you are checking if the animator 1 object is activeSelf it seems pretty obvious that in some cases it might not be.

    In this case Find will return null. This is probably where the exception comes from mainly.

    This function only returns active GameObjects. If no GameObject with name can be found, null is returned. If name contains a '/' character, it traverses the hierarchy like a path name.

    Next it is also possible that the found object simply doesn't have an Animator attached so GetComponent returns null.

    Returns the component of Type type if the game object has one attached, null if it doesn't.

Best way to find out is debugging and do your stuff in single steps and check each retrieved reference for null.

private const string OUTRO = "animation";

// Personally in general as soon as you use strings that never change anyway I would recommend a const
private const string ANIMATOR_1 = "animator 1";
private const string ANIMATOR_2 = "animator 2";
private const string INTRO = "intro";
private const string ERROR_COMPONENT_NOT_FOUND = "The object {0} has no Animator Component!";
private const string ERROR_OBJECT_NOT_FOUND = "No object with name {0} was found! It Either doesn't exist or is not active in the hierarchy!";

...

    if (word == ANIMATOR_2)
    {
        // This is expensive! Do it only once or avoid it completely if possible!
        var animatorObj = GameObject.Find(ANIMATOR_1);

        // Not found?
        if(!animatorObj)
        {
            Debug.LogErrorFormat(this, ERROR_OBJECT_NOT_FOUND, ANIMATOR_1);
            return;
        }

        // You can completely skip the check for activeSelf!
        // If the object is not active it will never be found!

        // Also do this only once
        var animator = animatorObj.GetComponent<Animator>();

        // Component not found?
        if(!animator)
        {
            Debug.LogErrorFormat(this, ERROR_COMPONENT_NOT_FOUND, animatorObj.name);
            return;
        }

       // There is absolutely no sense of using string interpolation $""
       // If you pass in exactly one string value .. why not rather simply pass the variable itself directly? 
       animator.SetBool(OUTRO, true);
       animator.SetBool(INTRO, true);
    }
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • Well this is all good information that I can use but one thing I want to point out that I think you might have misunderstood is that the reason I want to use string interpolation is because the string for outro will change depending on what animator is active. Their might be better method for this but I’m not sure what it is called. So basically it would be like if animator 1 is active outro = animation 1 if animator 2 is active outro = animation 2 and so on.. basically outro is a placeholder. That way the program fills out the value of outro automatically depending on what animator is active – MasterJ Sep 22 '19 at 14:10
  • @MasterJ ok .. still you don't need any interpolation for this but rather pass in the according string value directly. The point is you don't even have to change the value of a variable called `outro` at all. If you already know which string to pass in - in your example it was "animation" - then simply pass in that string instead of storing it somewhere else ;) – derHugo Sep 22 '19 at 14:12
  • I think you are completely correct about the null reference part tho – MasterJ Sep 22 '19 at 14:12
  • Could you post an example if you haven’t already I’m still confused about that part in particular – MasterJ Sep 22 '19 at 14:13
  • @MasterJ I think it would help if you post the complete method in your question ... without your code it is hard to fully understand your requirements :) – derHugo Sep 22 '19 at 14:16