Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a Scriptable Object Instance through a Constructor

I have a Character Scriptable Object and I have several methods in it. Like GetDate,GetAge (which I am not showing here). I have created a Constructor there, but I don't know how to create an instance of that ScriptableObject through the Constructor. That's what I want to do.

I have tried to just type the values in the inspector but that did not run the methods in the Constructor.

Character.cs

[CreateAssetMenu]
[Serializable]
public class Character : Scriptable Object
{
    // Attributes
    public string firstName;
    public string middleName;
    public string lastName;
    public string fullName;
    public bool isMale;

    // Constructor
    public Character(string _firstName, string _middleName, string _lastName, bool _isMale)
    {

        firstName = _firstName;
        middleName = _middleName;
        lastName = _lastName;

        // All The Functions 
        fullName = string.Format("{0} {1} {2}", firstName, middleName, 
        lastName);

        isMale = _isMale;

        // and all the other functions like date calculator.
    }
}

I want to create an instance of this Scriptable Object through this Construction. Something like

Character char("x", "y", "z", true);

or when I type the required fields in the Unity Inspector, then it will run all the methods like that full name string.format.

like image 887
Swastik Bhattacharyya Avatar asked May 15 '26 16:05

Swastik Bhattacharyya


2 Answers

No, not like that. It is still unclear why you have to use ScriptableObjects instead of having a simple class (we came from this question) where you would simply configure those Characters e.g. in the Inspector or use eg.

new Character("abc", "xyz", "kfk", true);

You could however have some kind of factory method like e.g.

[CreateAssetMenu]
[Serializable]
public class Character : Scriptable Object
{
    // Attributes
    public string firstName;
    public string middleName;
    public string lastName;
    public string fullName;
    public bool isMale;

    // Constructor
    private void Init(string _firstName, string _middleName, string _lastName, bool _isMale)
    {
        firstName = _firstName;
        middleName = _middleName;
        lastName = _lastName;

        // All The Functions 
        fullName = string.Format("{0} {1} {2}", firstName, middleName, lastName);

        isMale = _isMale;

        // and all the other functions like date calculator.
    }

    public static Character CreateCharacter(string firstName, string middleName, string lastName, bool isMale)
    {
        var character = ScriptableObject.CreateInstance<Character>();

        character.Init(firstName, middleName, lastName, isMale);
        return character;
    }
}

or alternatively do it e.g. in

private void OnEnable()
{
    fullName = $"{firstName} {middleName} {lastName}";
}

so it is there when the game starts.


If you really want to have it while typing those names in the Inspector you won't come around using a Custom Inspector by implementing Editor

#if UNITY_EDITOR
    using UnityEditor;
#endif

    public class Character : Scriptable Object
    {
        ...
    }

#if UNITY_EDITOR

    [CustomEditor(typeof(Character))]
    public class CharacterEditor : Editor
    {
        private SerializedProperty firstName;
        private SerializedProperty middleName;
        private SerializedProperty lastName;
        private SerializedProperty fullName;

        // called once when the Object of this type gains focus and is shown in the Inspector
        private void OnEnable()
        {
            firstName = serializedObject.FindProperty("firstName");
            middleName= serializedObject.FindProperty("middleName");
            lastName= serializedObject.FindProperty("lastName");
            fullName= serializedObject.FindProperty("fullName");
        }

        // kind of like the Update method of the Inspector
        public override void OnInspectorGUI()
        {
            // draw the default inspector
            base.OnInspectorGUI();

            serializedObject.Update();

            fullName.stringValue = $"{firstName.stringValue} {middleName.stringValue} {lastName.stringValue}";

            serializedObject.ApplyModifiedProperties();
        }
    }

#endif

alternatively to using #if UNITY_EDITOR you can ofcourse have the CharacterEditor in a complete separate script and put that one in a folder named Editor. In both cases the according code is stripped of in a build.


enter image description here

like image 182
derHugo Avatar answered May 17 '26 06:05

derHugo


You can't create a new ScriptableObject Instance using a constructor (much like a monobehaviour). so you need to use Unity API methods

I have added a working sample

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[CreateAssetMenu]
[Serializable]
public class Character : ScriptableObject
{
// Attributes
public string firstName;
public string middleName;
public string lastName;
public string fullName;
public bool isMale;

// Constructor
public Character(string _firstName, string _middleName, string _lastName, bool _isMale)
{

    firstName = _firstName;
    middleName = _middleName;
    lastName = _lastName;

    // All The Functions 
    fullName = string.Format("{0} {1} {2}", firstName, middleName,
    lastName);

    isMale = _isMale;

    // and all the other functions like date calculator.
}

public void Initialize(string _firstName, string _middleName, string _lastName, bool _isMale)
{
    firstName = _firstName;
    middleName = _middleName;
    lastName = _lastName;

    // All The Functions 
    fullName = string.Format("{0} {1} {2}", firstName, middleName,
    lastName);

    isMale = _isMale;
}

}

and here is the class that creates the Character

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class Tester : MonoBehaviour
{
int characterCounter = 0;

// Update is called once per frame
void Update()
{
    if(Input.GetMouseButtonDown(0))
    {
        Character c = CreateMyAsset();
        c.Initialize("a", "b", "c", true);
    }
}

public Character CreateMyAsset()
{
    Character asset = ScriptableObject.CreateInstance<Character>();

    string assetName = "Assets/c" + characterCounter + ".asset";
    characterCounter++;

    AssetDatabase.CreateAsset(asset, assetName);
    AssetDatabase.SaveAssets();

    EditorUtility.FocusProjectWindow();

    Selection.activeObject = asset;
    return asset;
}


}
like image 29
Shachash Avatar answered May 17 '26 04:05

Shachash



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!