Search code examples
unity-game-engine

instantiated using the ScriptableObject.CreateInstance


Im trying to create a button and multiple Sliders that update based each others values. Since every button and set of sliders is highly related I tried to call one method that would update the set, therefore I call one Update method for GenerateItem, rather than calling Update on each Object and making them reference each other.

Why am I getting the error above, and what is the "Unity" way to solve this? My program will likely have a lot of these sliders and Buttons so I would rather not code them all by hand.

GenerateItem must be instantiated using the ScriptableObject.CreateInstance method instead of new GenerateItem

void Start () {

    Button a = ((GameObject)Instantiate(prefabButton)).GetComponent<Button>();
    Slider b = ((GameObject)Instantiate(prefabCreationSlider)).GetComponent<Slider>();
    Slider c = ((GameObject)Instantiate(prefabCapacitySlider)).GetComponent<Slider>();
    Text d = ((GameObject)Instantiate(prefabText)).GetComponent<Text>();
    items.Add(new GenerateItem("OxyGen", 0.5f, 50f,a,c,b,d));
}

// Update is called once per frame
void Update () {
    items.ForEach(a => a.BtnUpdate());
}

I tried:

GenerateItem o= ScriptableObject.CreateInstance(GenerateItem);

but couldn't figure out how to set the properties of the object.


Solution

  • I don't see the code of the ScriptableObjects.

    But you either have to use CreateInstance(Type) which returns a ScriptableObject and cast the created instance to your type:

    GenerateItem o = (GenerateItem) ScriptableObject.CreateInstance(typeof(GenerateItem));
    

    Or simply use the typed version ScriptableObject.CreateInstance<Type>() which returns a Type and therefore doesn't require the typecast (I prefer this one)

    GenerateItem o = ScriptableObject.CreateInstance<GenerateItem>();
    

    Than you can set the properties as usual

     o.<some property> = <some value>;
    

    Note that the properties/fields ofcourse have to be public for this solution.


    Alternatively have some kind of

    public void SetValues(string name, float value1, float value2, Button button, Slider slider1, Slider slider2, Text text)
    {
        // Apply values
    
        <some property> = <some value>
        /* ... */
    }
    

    method inside of the ScriptableObjects so you can simply call

    o.SetValues("OxyGen", 0.5f, 50f, a, c, b, d);
    

    Another alternative (and I personaly like this one most) - Factory pattern

    Only allow setting of the values on instantiation and protect them against later direct changes. Have a method in GenerationItem that takes completely care of the instantiation and setting the values

    public static GenerateItem CreateInstance(string name, float value1, float value2, Button button, Slider slider1, Slider slider2, Text text)
    {
        // Let the method itself take care of the Instantiated
        // You don't need "ScriptableObject." since this class inherits from it
        GenerateItem o = CreateInstance<GenerateItem>();
    
        // Then directly set the values
        o.<some property> = <some value>;
    
        /* .... */
    
        return o;
    }
    

    So later in your class you just have to call

    var o = GenerateItem.CreateInstance("OxyGen", 0.5f, 50f, a, c, b, d);
    

    This makes sure values cannot be changed afterwards that easy. Depends on your needs.