Hi,
I’m a bit new to Unity, and I’m struggling to “create” a ScriptableObject at runtime. I want to create a gameobject, then assign that different values from a scriptableObject. I’ve watched what feels like a endless amount of youtube videos without getting a hang of this.
My code is as follows:
[CreateAssetMenu(fileName = "New Unit", menuName = "Unit")]
public class Unit : ScriptableObject {
public new string name;
public int maxHP;
public Sprite artwork;
}
public class Enemy : MonoBehaviour
{
public Unit enemy;
public Text nameText;
public Text health;
public Image image;
// Start is called before the first frame update
void Start()
{
}
public void LoadEnemy()
{
health.text = enemy.maxHP.ToString();
nameText.text = enemy.name;
image.sprite = enemy.artwork;
}
}
public class CombatManager : MonoBehaviour
{
public Unit enemyAsset;
//SetupScene initializes our level and calls the previous functions to lay out the game board
public void SetupScene()
{
GameObject enemy = new GameObject("Enemy");
enemy.AddComponent<Enemy>();
enemy.GetComponent<Enemy>().enemy.maxHP = enemyAsset.maxHP;
enemy.GetComponent<Enemy>().enemy.artwork = enemyAsset.artwork;
enemy.GetComponent<Enemy>().enemy.name = enemyAsset.name;
}
}
Any help is appreciated!
The main point of scriptable objects is to PRE define data as loadable/referenceable objects on disk.
Basically they are a class that has special wiring to “connect” public fields in the class to specific chunks of data in a single instance of the ScriptableObject on disk, and also lets you change those values in the Inspector. The wiring is “live” so even if your game is running, if you hand-edit a ScriptableObject, the on-disk asset changes, and vice-versa.
The same goes for if your code changes the on-disk object: it is one global object and will change.
That said, you can Instantiate() a ScriptableObject, which basically makes a copy of it, but does NOT write it to disk.
var UnitCopy = Instantiate<Unit>( enemyAsset);
If you want to write it to disk you need to do it at Editor time only (not runtime), and there is google-able reference material for doing that. Otherwise the copy will just disappear as soon as it is eligible for garbage collection or the app terminates.
1 Like
So how can I assign these values to my Enemy class?
What I would like to do is to pick a random ScriptableObject out of three, then assign one of them to a GameObject. Right now the Enemy will spawn as the Unit added to the prefab.
public class CombatManager : MonoBehaviour
{
public GameObject playerPrefab;
public GameObject enemyPrefab;
public Unit unit;
public Transform enemySpawn;
Enemy enemyAsset;
Player playerUnit;
void Start()
{
SetupScene();
}
public void SetupScene()
{
GameObject playerGO = Instantiate(playerPrefab);
playerUnit = playerGO.GetComponent<Player>();
GameObject enemyGO = Instantiate(enemyPrefab, enemySpawn);
enemyAsset = enemyGO.GetComponent<Enemy>();
}
}

If I want my prefab to change to the Blastoise Unit, how can I do that?
Thanks for the help!
I would make an array of Units in the CombatManager, instead of just one:
public Unit[] PossibleUnits;
Then fill it out in the inspector with all possible ones.
In the manager, you would choose randomly from that list and supply it to the prefab you make, generally by Instantiating it and then injecting the supplied unit. You can save the prefab off with NO Unit in there to make sure it doesn’t get used before it is defined (i.e., check it at runtime so you know the new Unit has been injected by the CombatManager).
1 Like
How do I supply it to the prefab though?
The one I supply to CombatManager is not used at this time.
Instead I am using the one supplied to the prefab. Below is my enemy prefab.
I would be able to supply the "Enemy"field in Enemy with a Unit, instead of the one predefined.
Found what I was looking for!
enemyAsset.enemy = unit;
Thanks a lot for the help! 
1 Like
I kinda left this open-ended because it is highly dependent on what you’re most comfortable with.
And it looks like you came up with an excellent solution!
One thing I noticed was that I was ending up with two gameobjects in unity when using Instantiate, like this:
GameObject playerGO = Instantiate(playerPrefab, playerSpawn);
playerAsset = playerGO.GetComponent<Player>();
But without the lines of code above, I end up with zero copies. Is this the preferred way? Or should I “spawn” my gameobjects in another way?