2

I have a folder in my unity project under "Resources/ScriptableObjects/Skins". I need to get all the objects in the folder, generate a random number for the index, then assign the sprite to an existing game object that the script is attached to. The current error I'm getting is "NullReferenceException: Object reference not set to an instance of an object" on line 151 but I'm creating an instance of the object on line 149. What gives? Here is my function to assign the sprite from a random scriptableobject in the folder to the game object the script is tied to:

void AssignRandomSkin(){
    // Load all skins into memory
    Object[] skinObjects = Resources.LoadAll("ScriptableObjects/Skins");


    // Get length of list
    int amountOfSkins = skinObjects.Length;

    // Get random index of skin to assign
    int skinToAssignIndex = Random.Range(0, amountOfSkins);

    GameObject thisSkin = Instantiate(skinObjects[skinToAssignIndex]) as GameObject;
    // Assign it to game object
    gameObject.GetComponent<SpriteRenderer>().sprite = thisSkin.GetComponent<Sprite>();

}

Here is the Scriptable Object:

using UnityEngine;

[CreateAssetMenu(fileName = "Skin", menuName = "ScriptableObjects/SkinObject", order = 1)]
public class SkinObject : ScriptableObject
{
    public string spriteName; // Name of sprite

    public Sprite sprite;

    public float xPos;

    public float yPos;

    public float zPos;

    public float xScale;

    public float yScale;

    public float zScale;

    public float fallSpeed; //AKA Weight

    public string tier; //Category that skin can be assigned in
}
ItsSgtMarv
  • 105
  • 1
  • 11
  • We cannot see which line is 152 and 149 - would you mind editing your question to include methods you have used or marked them somehow? – Tomasz Juszczak Dec 21 '20 at 22:18
  • Sorry this is 149. GameObject thisSkin = Instantiate(skinObjects[skinToAssignIndex]) And this is 152 gameObject.GetComponent().sprite = thisSkin.GetComponent() – ItsSgtMarv Dec 21 '20 at 22:25
  • In general: **Why**? I mean .. why at all? From [Best practices - Resources](https://learn.unity.com/tutorial/assets-resources-and-assetbundles#5c7f8528edbc2a002053b5a7) **Don't use it!** ... Why not simply reference these ScriptableObjects the usual way via the Inspector in a field like `public SkinObject skin;` ? Or select one random from an array `public SkinObject[] availableSkins;` – derHugo Dec 21 '20 at 22:53
  • 1
    Because I would have to write out a reference to every skin and there will be tons. I’d like to just get all objects in a location and pick a random one – ItsSgtMarv Dec 21 '20 at 22:56
  • 1
    And note that it makes no sense to spawn this as a `GameObject` ... It is a `SkinObject` ... And there is no such component `Sprite` ... you rather want to access the field `.sprite` – derHugo Dec 21 '20 at 22:56
  • @ltsSgtMarv what do you mean by `write out a reference to every skin`? As just said .. you can use one array and store them all – derHugo Dec 21 '20 at 22:57
  • I attempted that before and I got a similar error. This was just my most recent attempt. I’ll attempt SkinObject again and comment the code and results – ItsSgtMarv Dec 21 '20 at 23:00

1 Answers1

5

So what happens here?

Your objects are ScriptableObject of type SkinObject! => They are not GameObject prefabs!

Everything in your code should work until the

GameObject thisSkin = Instantiate(skinObjects[skinToAssignIndex]) as GameObject;

first of all it is unnecessary to instantiate a ScriptableObject. This would only create a clone of the asset but you don't need this.

And second you are trying to cast it to GameObject. As said this is a type mismatch and therefore thisSkin will be null!

And finally Sprite is no component. You are rather trying to access the field .sprite of your SkinObject type.


I'm pretty sure it should rather be

// You can directly tell LoadAll to only load assets of the correct type
// even if there would be other assets in the same folder
SkinObject[] skinObjects = Resources.LoadAll<SkinObject>("ScriptableObjects/Skins");

var thisSkin = skinObjects[Random.Range(0, skinObjects.Length)];
// Assign it to game object
gameObject.GetComponent<SpriteRenderer>().sprite = thisSkin.sprite;

However, as said before, from the Best Practices - Resource Folder Don't use it!

Why not simply reference these ScriptableObjects the usual way via the Inspector in a field like

public SkinObject[] availableSkins;
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • Not sure if that solution would work. I dug into your comment about not using the Resources folder and decided to scratch that idea. I am now using your suggestion of declaring a public SkinObject[] skinsAvailable array. Then my code to get a random skin from the object is gameObject.GetComponent().sprite = availableSkins[skinToAssignIndex].sprite; I guess I'll mark this answer as solved? – ItsSgtMarv Dec 22 '20 at 00:00