C# occasionally fails to find Rigidbody2D

What we intended to do was when our player revives he escapes a net and the net moves off screen with the pace of the background (Creating a illusion that the net is still, other wise it would look like it the net was moving forward). We have a error that happens about 10% of the time. The error we get is a null reference error, object is not set to an instance of a object. The error points to this line:

NetsBody = GameObject.Find("NetCollision").GetComponent<Rigidbody2D>();

if there is a problem with this line why does the error only come up every so often and not constantly everytime?

Rest of the revive function:

 //Revives the Player
    public void Revive()
    {
        StartCoroutine("ReviveProcess");
        GetComponent<Animator>().Play("SwimmingTurtlePlayer");
        GetComponent<BoxCollider2D> ().enabled = true;
        IsDead = false;
        //Debug.Log ("player is alive");
        NetsBody = GameObject.Find("NetCollision").GetComponent<Rigidbody2D>();
        //Debug.Log ("PlayerManager: Net's rigidbody2d has been found");
        NetsBody.velocity = new Vector2 (-1, 0);
        //Debug.Log ("Net Is Moving");
        Time.timeScale = 1.0f;
        TurtleBackgroundOffset2.enabled = true;
        Turtle.isKinematic = false;
        normalCollider.enabled = true;
        //BackgroundStop.enabled = true;
        BackgroundStop.speed = 1.0f;
        //Waterline.enabled = true;
        Waterline.speed = 1.0f;
        Waterline2.speed = 1.0f;
        AirBar script = gameObject.GetComponent<AirBar>();
        if (script.Airbar.fillAmount <= 0f)
        {
            script.Start ();
        }
    }

you’re misinterpreting the error. You get a null reference error when you try to use an object reference that is not set to something. In this case you are attempting to get a component from the gameobject returned by the find.

So at some points in your game the gameobject called “NetCollision” doesn’t exist when this code attempts to be called. I assume it’ll be the frame after the “NetCollision” gameobject is destroyed.

for the record, GetComponent doesn’t error if there isn’t a component of the specified type on the gameobject, it just returns null… which usually causes a null reference error later on in the code if not handled.

1 Like

If the NullReferenceException actually points to the line with GetComponent, then the problem isn’t with GetComponent - it’s with GameObject.Find. GameObject.Find is returning null, therefore your .GetComponent triggers the exception. (If GetComponent were returning null, you’d see an exception at line 11 when you try to actually access part of it.)

There are many reasons not to use GameObject.Find, and this is one of them - one of a dozen conditions can cause it to fail to find the thing. Maybe the name was changed, maybe it was instantiated (which causes the name to change, since it tacks on “(Clone)”), maybe the object is inactive (which GameObject.Find doesn’t search for), and any of a half dozen other reasons I couldn’t think of without seeing the project.

Basically I can count the times in my entire career to date where GameObject.Find was the correct way to locate an object, on one finger (excluding debugging code anyway). You’ll almost always be better off with a singleton, a manager class, or any of a dozen other ways of grabbing references to arbitrary objects. If you’d like I can advise you on what a better way to get that reference would be, but I’d need a little more information about the way the scene is set up to do so.

The upshot is, it’s GameObject.Find’s fault.

1 Like

Well we are making an infinite runner, full of different obstacles. Including a net that catches the player. This net is where the problem comes from. Also the fact that the net is a instantiated object spawned from an object pool. We need the Player manager to access the nets rigid body when the player revives to move the net offscreen before it head back to too the object pool. I did a attempt to do this inside of the nets manager script but the block of code that was moving the net offscreen, kept being skipped completely. This lead me to try within the player managers script.

If you want to see more, we will give it to you We just wanted to give what we thought was relevant.

(also See Player manager above).

Net Manager (Note: Lines 166 -182):

using UnityEngine;
using System.Collections;

public class NetsManager : MonoBehaviour {
   
    public Rigidbody2D NetBody;
    private Rigidbody2D PlayerBody;
    private GameObject SecondaryPlayerBody;
    private DistanceJoint2D PlayerDistance;
    private MoveNetCoillsions movenetcoillsions;
    private PlayerManager playermanager;
    private float CollisionCount = 0;
    private AreaEffector2D NetForce;
    bool IsPlayerDead;

    void Awake()
    {
        NetForce = GetComponentInChildren<AreaEffector2D> ();

        Debug.Log ("Found Net's Effector");

        NetForce.enabled = false;

        movenetcoillsions = GetComponent<MoveNetCoillsions> ();

        //Debug.Log ("Found Component MoveNetCoillsion");

        playermanager = GameObject.Find ("Player").GetComponent<PlayerManager> ();

        //Debug.Log ("Found Component Player Manager");

        PlayerBody = GameObject.Find ("Player").GetComponent<Rigidbody2D> ();

        //Debug.Log ("Found Player's Rigidbody2d");

        SecondaryPlayerBody = GameObject.Find ("SecondaryPlayerBody");

        //Debug.Log ("Found GameObject Secondary Player Body");

        PlayerDistance = GameObject.Find ("SecondaryPlayerBody").GetComponent<DistanceJoint2D> ();

        //Debug.Log ("found Distance Joint");

        //IsPlayerDead = GameObject.Find ("player").GetComponent<PlayerManager>().IsDead;

        //Debug.Log ("Player Bool Found");

        PlayerDistance.enabled = false;

        //Debug.Log ("Distance Joint disabled");

        movenetcoillsions.enabled = true;

        //Debug.Log ("MovaNetCollisions Disabled");
    }

    public void OnTriggerEnter2D(Collider2D other)
    {
        //Debug.Log ("Player has collidied with the net");
        // if the player has collided with the net.

        CollisionCount++;

        if (other.tag == "Player")
        {
            movenetcoillsions.NetCoillidersSpeed = -240;
            //Debug.Log ("MoveNet at -240");

            PlayerDistance.enabled = true;
            //Debug.Log ("Distance joint is true");

            PlayerDistance.connectedBody = GameObject.FindGameObjectWithTag("Nets").GetComponent<Rigidbody2D>();
            Debug.Log ("Spawned Net has been found");

            PlayerBody.isKinematic =true;
            //Debug.Log ("Player's rigibody is now Kinematic");
           
            other.GetComponent<Rigidbody2D>().velocity = new Vector2(0, 0);
            //Debug.Log ("Player has no more velocity");

            other.GetComponent<Rigidbody2D>().angularDrag = 0;
            //Debug.Log ("Player has no more Angular drag");

            other.GetComponent<Rigidbody2D>().drag = 0;
            //Debug.Log ("Player has no more drag");

            other.GetComponent<Rigidbody2D>().isKinematic = true;
            //Debug.Log ("Player's rigibody is now Kinematic");

            Invoke("StopNetAnimator", 2.5f); //start the void stop net animator in 2 sceonds.
            //Debug.Log ("start the void stop net animator in 2 sceonds.");
        }
    }

    public void OnTriggerExit2D(Collider2D other)
    {
        CollisionCount--;
    }

    void Update ()
    {
        if (CollisionCount == 0)
        {
            Invoke("NetMissed", 2.5f);
            Debug.Log("No collision");
        }
    }

    void NetMissed ()
    {
        NetBody.velocity = new Vector2 (-1, 0);
       
        //NetBody.isKinematic = true;

        NetForce.enabled = false;
       
        NetBody.angularDrag = 0;
       
        NetBody.drag = 0;
       
        NetBody.gravityScale = 0;
       
        movenetcoillsions.enabled = false;

        Invoke ("ResetNet",10.5f);
    }

    public void StopNetAnimator ()
    {
        NetBody.velocity = new Vector2 (0, 0);

        NetBody.isKinematic = true;

        NetBody.angularDrag = 0;

        NetBody.drag = 0;

        NetBody.gravityScale = 0;

        movenetcoillsions.enabled = false;

        //Debug.Log ("Net is stopped");

        Invoke ("NetHitPlayer", 2f);
    }

    public void NetHitPlayer()
    {
        SecondaryPlayerBody.SetActive (false);
       
        PlayerDistance.enabled = false;

        NetBody.isKinematic = false;

        if (PlayerManager.IsDead == true) {
            Debug.Log ("Player Bool Found T ");

            NetBody.velocity = new Vector2 (0, 0);
            Debug.Log ("Net is static");

            PlayerBody.isKinematic = false;

            PlayerBody.velocity = new Vector2 (0, 0);

        }
        //Orignal Attempt to move the net when the player revives.
        //But Unity seemed to have skipped this block of code.
        //the debug statments didn't even show up in the counsel.
        else if (PlayerManager.IsDead == false)
        {
            Debug.Log ("Player Bool Found F ");
           
            NetBody.isKinematic = false;
           
            PlayerBody.isKinematic = false;
           
            NetBody.velocity = new Vector2 (-1, 0);
            Debug.Log("Net is Moving");
        }

        Invoke ("ResetNet",10.5f);
    }

    void ResetNet ()
    {
        Debug.Log ("Net is reseting");
        NetBody.isKinematic = false;
       
        NetBody.angularDrag = 0.05f;
       
        NetBody.drag = 0;
       
        NetBody.gravityScale = 1;

        NetForce.enabled = true;
       
        movenetcoillsions.enabled = true;

        movenetcoillsions.NetCoillidersSpeed = -200;

        PlayerDistance.enabled = false;

        SecondaryPlayerBody.SetActive (true);
    }
}

you increment the collision count before checking what has been hit… so hitting anything means its “hit” and the invoke isn’t called… floor, wall, anything (based on the physics collision layers etc.)…

I think the singleton pattern is what you want for your code. A singleton simply means that there is an object in a scene, it’s expected to be the only one of that object in the scene at a time, and you would like to conveniently access that one object from anywhere.

In its simplest form, a singleton looks like this:

public static NetsManager main; //replace with whatever class name you're making into a singleton
void Awake() {
main = this;
}

I would put this code on your net manager and your player manager to start with. You can use PlayerManager.main to access the player manager object, and PlayerManager.main.GetComponent() to get its rigidbody. I would actually add a public member to the PlayerManager that references its own rigidbody - cache references in the most straightforward place you can. If you do that, you can access PlayerManager.main.myRigidbody directly, and the best part is, that call is ‘free’ performance-wise - no finding objects, nothing. It makes very performant, plus very readable code, and once you get the hang of correctly writing it, it’s also far more reliable than anything involving GameObject.Find.


Another strategy that would probably be useful to you in this project would be a static list. This is basically the same idea as a singleton, except that it works for items that you’ll have multiple instances of. It can also be slightly modified from this concept to work with an object pool, though I’ll leave that as an exercise for the reader. :slight_smile: It might look like this:

In this case I’ve made the public member a read-only property, mostly so that you’re guaranteed that YourClassName.all will never return null (if no objects exist, it’ll return an empty list instead).

using System.Collections.Generic; //at the top of your script
...
public static List<YourClassName> all {
get {
if (_all == null) _all = new List<YourClassName>();
return  _all;
}
}
private static List<YourClassName> _all;

void OnEnable() {
if (_all == null) _all = new List<YourClassName();
_all.Add(this);
}
void OnDisable() {
_all.Remove(this);
}
....
// in any other script
foreach (YourClassName thing in YourClassName.all) {
thing.DoSomething();
}

Well, the singleton worked like a charm and it was allot easier to use than I expected at first. Thanks allot for this tip I will be using it in all my future projects.

Thanks i missed that, It’s fixed now.

A word of warning: it’s easy to overuse singletons, and not realize until it’s too late that you’ve coded yourself into a corner. Drawing a line between when you should and should not be using singletons is tricky, but the basic rule of thumb is that, if you have other means of getting a reference to the object, you may want to not use the singleton. For example, in collision code, you may want to get access to the object through the parameters provided in the collision, and not rely on the singleton. This will make your code more versatile when you go to change things later. Let’s say that, right now, you may have coins which, when they collide with your player object, destroy themselves. You may want to make it possible later to add multiplayer, or to allow enemies to pick up the coins, or something. If you’ve hardcoded the coins to use Player.main, changes like these will be a more significant code rewrite than if the coins used the collider that is passed to the collision function.

Thanks, I will kept that in mind :).