[SOLVED]NullReferenceException on a object that is already created?

I’m trying to load the values stored on a .json but it gives me an strange error in a certain line.
The error is:

NullReferenceException: Object reference not set to an instance of an object
DisplayShip.LoadValues (.StoredData toLoadData, UnityEngine.GameObject linkedSlot) (at Assets/_Scripts/ShipScripts/DisplayShip.cs:535)

    public void LoadValues(StoredData toLoadData, GameObject linkedSlot)
    {
        isLoaded = true;
        functionType = FunctionType.PrefabFolder;
        linkedShipSlot = linkedSlot;
        storedData = toLoadData.totalStats;
        // Load nas partes da nave exceto GUN
        for (int i = 0; i < toLoadData.eachPartSpritePath.Length; i++)
        {
            GameObject newPart = new GameObject(toLoadData.eachPartSpritePath[i]);
            newPart.transform.SetParent(transform);
            Sprite loadedSprite = Resources.Load<Sprite>("Sprites/" + toLoadData.eachPartSpritePath[i]);
           // Debug.Log(Application.dataPath + "/Sprites/" + toLoadData.eachPartSpritePath[i]);
            newPart.AddComponent<SpriteRenderer>().sprite = loadedSprite;
            newPart.GetComponent<SpriteRenderer>().sortingOrder = toLoadData.eachSpriteSortLayer[i];
            newPart.transform.position = toLoadData.eachPartPosition[i];
            newPart.transform.eulerAngles = toLoadData.eachPartRotation[i];
        }

        for(int i = 0; i < toLoadData.eachGunSpritePath.Length; i++)
        {
            List<GunsBehaviour.LaserType> laserList = new List<GunsBehaviour.LaserType>();
            GameObject newGun = new GameObject(toLoadData.eachGunSpritePath[i]);
            newGun.transform.SetParent(transform);
            Sprite loadedGunSprite = Resources.Load<Sprite>("Sprites/" + toLoadData.eachGunSpritePath[i]);
            newGun.AddComponent<SpriteRenderer>().sprite = loadedGunSprite;
            newGun.GetComponent<SpriteRenderer>().sortingOrder = toLoadData.eachGunSpriteSortLayer[i];
            newGun.transform.position = toLoadData.eachGunPos[i];
            newGun.transform.eulerAngles = toLoadData.eachGunRot[i];
            for(int o = 0; o < toLoadData.laserList.Length; o++)
            {
                if (toLoadData.laserList[o].ID == i)
                {
                    laserList.Add(toLoadData.laserList[o]);
                }
            }           
// ============================================== //
 /* I already added the script here */ ===>  newGun.AddComponent<GunsBehaviour>();
 // ============================================== //     
newGun.GetComponent<GunsBehaviour>().laserList = new GunsBehaviour.LaserType[laserList.Count];
            for(int q = 0; q < newGun.GetComponent<GunsBehaviour>().laserList.Length; q++)
            {
                Sprite loadedLaserSpritea = Resources.Load<Sprite>("Sprites/" + laserList[q].laserSpritePath);
// ======================ERROR======================== //
                                                              newGun.
/*Is pointing to this line the error*/ ===> GetComponent<GunsBehaviour>().
                                                              laserList[q].laserSprite
                                                              = loadedLaserSpritea;
// ================================================ //                
                if (newGun.GetComponent<GunsBehaviour>().laserList[q].laserEffectPath != "NULL")
                {
                    Sprite loadedLaserEffectSprite = Resources.Load<Sprite>("Sprites/" +
                        newGun.GetComponent<GunsBehaviour>().laserList[q].laserEffectPath);
               
                    newGun.GetComponent<GunsBehaviour>().laserList[q].laserEffectSprite = loadedLaserEffectSprite;

                    newGun.GetComponent<GunsBehaviour>().laserList[q].laserSize = laserList[q].laserSize;
                    newGun.GetComponent<GunsBehaviour>().laserList[q].projectileSpeed = laserList[q].projectileSpeed;
                    newGun.GetComponent<GunsBehaviour>().laserList[q].projectileDamage = laserList[q].projectileDamage;
                    newGun.GetComponent<GunsBehaviour>().laserList[q].inclinedAngle = laserList[q].inclinedAngle;
                    newGun.GetComponent<GunsBehaviour>().laserList[q].isFliped = laserList[q].isFliped;
                }

            }
        }
       
    }

The first thing I would do is put a break point at the for loop and check to make sure you laserList has something in it and isn’t actually null. Next does this occur on every loop or only when q is a certain value?

For starters… don’t keep calling ‘GetComponent’, set that to a variable:

var gunScript = newGun.AddComponent<GunsBehaviour>();
gunScript.laserList = new GunsBehaviour.LaserType[laserList.Count];
for(int q = 0; q < gunScript.laserList.Length; q++)
{
    Sprite loadedLaserSpritea = Resources.Load<Sprite>("Sprites/" + laserList[q].laserSpritePath);
    gunScript.laserList[q].laserSprite = loadedLaserSpritea;
    //...
}

As for your issue. I don’t know if ‘GunsBehaviour.LaserType’ is a struct or a class… but I’m willing to bet it’s a class. And if it is a class… sure you instantiated the array of LaserTypes, but you didn’t fill it with objects.

But you can tell for sure in the Visual Studio debugger by putting a watch on the object and checking it.

2 Likes

Thanks i found where this error come from, with what you said i remembered that each of this LaserType in the laserList needs receive this: newGun.GetComponent<GunsBehaviour>().laserList[q] = new GunsBehaviour.LaserType();

And i will try to follow your sugestion of stop using GetComponent, but is there a difference between creating a new variable just to store a GetComponent instead of just using only the function GetComponent?

Yes, it caches the result. While not as slow as things like Find, GetComponent is far slower by comparision to a cached result. One GetComponent call isn’t going to affect much, but several calls in the same function is basically wasting CPU, while multiple calls over several frames on a number of scripts has an impact on framerate.

Using the cache is like you writing down the phone number to a store onto stickynote, where GetComponent is like looking through a phone book (from the beginning, every time). Sure GetComponent is more up-to-date, but the cache is faster to look up and just as easy to check if its still valid.

1 Like

Read everything @JoshuaMcKenzie said.

I want to point out that the variable I suggested you create is scoped to the function and not a field/member of the class. It’d be wasteful to put a temporary variable as a field/member.

But as a temporary variable in the scope of your function. It’s just faster, and can help make your code more readable.

Thanks for your answer, for me now this doesn’t seems to affect me too much so i didn’t noticed anything because i’m working on a small project but with what you said i will try to turn this into a habit.