Search Unity

ScriptableObject.CreateInstance vs Instantiate

Discussion in 'Scripting' started by laurentlavigne, Feb 4, 2018.

  1. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,351
    what is the performance profile of createinstance?
     
  2. Prastiwar

    Prastiwar

    Joined:
    Jul 29, 2017
    Posts:
    125
    Last edited: Feb 5, 2018
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,440
    Nope. You can use ScriptableObject.CreateInstance as much as you want at runtime.


    For OP's question, Are you wondering if it's faster to eg. create a ton of copies of an existing SO than to create a ton of new SOs? It's not that hard to check!

    Code (csharp):
    1. public class Create : MonoBehaviour
    2. {
    3.     public SomeSO toClone;
    4.  
    5.     void Update()
    6.     {
    7.         if (Input.GetKeyDown(KeyCode.Space))
    8.         {
    9.             var stop = Stopwatch.StartNew();
    10.             for (int i = 0; i < 10000; i++)
    11.             {
    12.                 var so = ScriptableObject.CreateInstance<SomeSO>();
    13.             }
    14.  
    15.             stop.Stop();
    16.             Debug.Log(stop.Elapsed);
    17.         }
    18.        
    19.         if (Input.GetKeyDown(KeyCode.Alpha0))
    20.         {
    21.             var stop = Stopwatch.StartNew();
    22.             for (int i = 0; i < 10000; i++)
    23.             {
    24.                 var so = Instantiate(toClone);
    25.             }
    26.  
    27.             stop.Stop();
    28.             Debug.Log(stop.Elapsed);
    29.         }
    30.     }
    31. }
    The results are that CreateInstance is in the ballpark of 12-13 ms, while Instantiate takes about 4.
     
    ammirea, phobos2077, Novack and 4 others like this.
  4. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,351
    3x slower is shockingly bad. You know who made this?
     
  5. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,655
    They're both pretty irrelevant actually- making copies of ScriptableObjects during runtime is pretty pointless in most cases, and if you're doing it in the editor then it doesn't matter what the performance hit is (which is why they still use the OnGUI system for editor scripts despite its terrible performance).

    ScriptableObjects don't benefit from any of the built-in tools at runtime, since the AssetDatabase is an editor class, so it's essentially the same as using any serializable class type since you need to write and load it from the disk yourself manually either way. I could see using it as a factory pattern I suppose, treating the pre-made SOs like blueprints and just making copies when they're needed, but that would be trivial to handle during scene loads rather than mid-play, and CreateInstance wouldn't be used at all in that scenario. In my own solutions, the pre-made SOs ("definitions", "blueprints", w/e) simply generate non-SOs, so there's no extra overhead for saving the objects to disk.

    I actually can't imagine a single scenario where CreateInstance is ever actually useful at runtime, to be perfectly honest.
     
    phobos2077, eses and Ryiah like this.
  6. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,351
    i instantiated SO at runtime as data and function buckets, so you say createinstance is in fact making an asset?
     
  7. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,655
    It's just got a lot of pointless overhead for no real benefit outside of the editor. You can use a non-ScriptableObject and just make a new instance with the "new" keyword easily enough, so what's the point of it being a ScriptableObject in the first place? If it was for a factory pattern, then Instantiate would be the function to use so that you can make a duplicate of the original.
     
    phobos2077, Ryiah and Kiwasi like this.
  8. simonlvschal

    simonlvschal

    Joined:
    Nov 17, 2015
    Posts:
    263
    there is no point in Using ScriptableObjects.CreateInstance. since scriptable Objects should just be used as Data Containers.. and also i am pretty sure u cannot use Instantiate on a Scriptable Object. since it has no objects or data that can be used to create a object
     
  9. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    you really need to watch some of the more recent unity vids on how to use scriptableobjects if you still think that.
     
    forcepusher and laurentlavigne like this.
  10. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,655
    Instantiate can absolutely be used on ScriptableObjects- they're derived from UnityEngine.Object after all.

    @LeftyRighty To be fair, some of the recent Unity vids abuse ScriptableObjects in really bizarre ways- ways that aren't even supported properly, and which cause some pretty serious side effects. For instance, instantiating new ScriptableObjects without saving them to the disk as assets, and then assigning them to ScriptableObject references in a scene is actually done in one of those tutorials, made me cringe like crazy while watching it, and in practice creates all sorts of problems in the Editor, like dirtying every open scene every time its done, not having a proper reference target in the inspector, creating a bunch of garbage to be GCed, etc...

    They're inherently just YAML files, which means they are, at their core, just data containers, like XML or JSON files. The extra functionality given by serializing them and giving them custom editors isn't much different than writing inspectors for any other asset type, like ZIP files for instance, which is easy enough.

    Out of curiosity, what tutorials on ScriptableObjects are you referring to, that they aren't just treated like data containers with a custom inspector?
     
    Last edited: Feb 6, 2018
    phobos2077, Ryiah and Kiwasi like this.
  11. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,608
    Yeah, I see very little benefit to creating a new ScriptableObject at runtime. The only real difference between a ScriptableObject and a vanilla class is that you can make a ScriptableObject into an asset in the editor. There seems to be little point to doing this at runtime.

    I suppose you could use it if you want to pump a regular class through the same Instantiation/Enable/Disable/Destroy pipeline that GameObjects follow. But it doesn't seem especially smart to do this.
     
  12. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,351
    it might be what i'm doing.

    i use them to avoid making custom inspector, all I have is this thing which shows the content of all referenced object within the inspector - it's convenient.

    i use SO in the following scenario:
    Actor is a component attached to each agent, it has a list of Action SO
    when the AI triggers an action, it sends an reference of an instance of the Action SO's to a centralized ActionManager, packaged alongside a target and other parameters which allow me to conveniently format all actions the same way.
    the ActionManager calls the Action's precondition, if the preconditions are met it locks the target, adds the Action package to the list, processes that list each frame. the Action Package includes the Action and things like time it takes for the action to complete, callbacks when completed or failed etc...

    instantiation is now no longer an issue because i've capped the AI ability to spawn actions @ 1 action/agent so i pre-instantiate the SO at agent startup but I want to hear how you guys use SO and how you handle actor->action->target
     
    phobos2077 likes this.
  13. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    4,645
    For example:



    Also you can use them as expandable enums (by designer), although it's more or less data storing feature.
     
    athgen113 and phobos2077 like this.
  14. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    pipped to it, but specifically the AI tutorial and the "monobehaviour tyranny" talk where they discuss "plug and socket" architecture to use functions on scriptableobjects, rather than just using them as data holders
     
  15. simonlvschal

    simonlvschal

    Joined:
    Nov 17, 2015
    Posts:
    263
    no. i dont. cause scriptable objects are normally used for Data Containers. and some functions since it lives as a asset
     
  16. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    4,645
    It's obviously up to you what new techniques you want to learn or not, but that statement, that the scriptableobjects "normally" used as data containers is, well, silly. SOs have multiple functions, multiple goals and multiple usage. It's up to you if you utilize those or not. But that's your shortcoming if you don't.
     
  17. LocalsOnlyCoop

    LocalsOnlyCoop

    Joined:
    Mar 8, 2019
    Posts:
    5
    That second video was fantastic! (I know this is an old topic). I was curious how he gets around the One Object / One Variable problem. If I wanted to clone an enemy several times, they couldn't all reference the same HP variable. Also I imagine your project would become quite full of ScriptableObject instances.
     
    lmraddmb, FuBaa and DeletedFragment like this.
  18. denlee0710

    denlee0710

    Joined:
    Mar 9, 2015
    Posts:
    29
    You can create .asset(instances) and of a scriptable object in editor time and save it. Without SO you can accomplish the same by hardcoding it with new(), albeit would be pretty ugly code.

    If you are editing and saving SO.asset at runtime, it’s equivalent to serializing a regular object.

    The way Unity explain and position SO is very confusing when I first learned about it and tried to understand it. Eventually I realized ScriptableObjects are just regular objects that which you can instantiate and initialize in editor time. Otherwise they aren’t any different. No more confusion!
     
  19. FuBaa

    FuBaa

    Joined:
    Aug 22, 2012
    Posts:
    1
    Bit late, sorry.

    If we have a
    GameObject Enemy
    , all we need to do is make a decision about who is concerned (which other Objects) are interested in the data it holds. If other objects are concerned with it, we should use a
    ScriptableObject
    , and reference that data. Or, if no other Objects are concerned with the data, then our
    Enemy
    can just have an internal Instance Variable instead.

    Let's use a little example, and say that our
    Enemy
    has three variables it's interested in,
    health.current
    ,
    health.max
    and
    movement.speed
    .

    In our game there's also floating health bars that appear above an enemies head (something like this), which is looked after by our players HUD (probably a Canvas UI element billboarded). As such, our
    Enemy
    Object needs some way of telling the
    Player
    's HUD Object about what its
    health.current
    and
    health.max
    values are. This is where
    ScriptableObject
    s would be used, and both the
    Enemy
    and the
    Player
    's HUD would reference that same
    ScriptableObject
    Data.

    That leaves us with the
    Enemy
    's
    movement.speed
    ... Which, at the moment at least, nothing else in our game is concerned with. The Enemy knows it's movement speed is 4f (for example), and it can do its internal calculations to move the model at that speed quite happily. Our Player doesn't care what the Enemy's movement speed is, neither does our HUD. Therefore, the
    Enemy.movement.speed
    can just be stored as an Instance Variable inside of our
    Enemy
    Object.


    If you need to generate a new
    Enemy
    at runtime (then you're likely procedurally generating stuff, which is awesome, keep it up!), then you could use something like:


    RefInt.cs:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class RefInt : ScriptableObject
    4. {
    5.   public int Value;
    6. }
    Enemy.cs:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Enemy : MonoBehaviour
    4. {
    5.   private void Awake()
    6.   {
    7.     // We create a new Integer ScriptableObject to hold our newly created Enemy's Current HP data.
    8.     RefInt enemyCurHP = ScriptableObject.CreateInstance<RefInt>();
    9.  
    10.     // We assign a value to that
    11.     enemyCurHP.Value = 5;
    12.  
    13.     // We send a message to the Player's HUD object, saying:
    14.     //  "Hey! I'm a new Enemy!
    15.     //   I think you're interested in knowing what my current HP value is.
    16.     //   I'm currently keeping track of it myself in this ScriptableObject...
    17.     //   Why don't we both just reference the same number, rather than all this chat?"
    18.     PlayerHUD.TrackNewValue(gameObject, enemyCurHP);
    19.   }
    20. }
    PlayerHUD.cs:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class PlayerHUD : MonoBehaviour
    5. {
    6.   // Use Polymorphism to keep the referenced data nice and general.
    7.   private static Dictionary<GameObject, ScriptableObject> _refData =
    8.       new Dictionary<GameObject, ScriptableObject>();
    9.  
    10.  
    11.   // We use this to keep track of any new data that the PlayerHUD needs to know about.
    12.   public static void TrackNewValue(GameObject obj, ScriptableObject reference)
    13.   {
    14.     _refData.Add(obj, reference);
    15.   }
    16.  
    17.  
    18.   // We can then Update the screen to represent any changes to this data, independently
    19.   // of how, when or why it's changed.
    20.   private void Update()
    21.   {
    22.     // Just some Pseudo code to give an example...
    23.     someUIElement.text = _refData[anEnemyThatsInRangeOfThePlayer];
    24.   }
    25. }
    This is just a thrown together example (please don't use it; there are better ways of doing pretty much everything that's in there). But it gives the general idea... And be sure to remove the references when you're done, to avoid memory leaks.


    As for ending up with hundreds, thousands, tens of thousands of pieces of ScriptableObject Data, it's not a problem, as internally that data will exist in a
    Serialized
    form, whether or not its an Instance Variable or a ScriptableObject. The Engine doesn't care where the data comes from, and indeed, won't know.

    You're not creating more data (each enemy is still going to have HP, right?), you're just changing how the data is used (referencing shared data, instead of asking for it a lot, or storing it multiple times). At runtime, you can use something similar to the above outlined criteria. In the editor, you'll likely have lots of ScriptableObject data files (.asset files)... This is completely normal. Just keep them organised (folders/directories are your friends here), and you shouldn't encounter any issues.

    The big difference (and the point of all this) is that rather than storing the
    EnemyCurHP
    in multiple places (or constantly asking the
    Enemy
    Object, "Hey! What's your HP?", "What's your HP?", "What's your HP?"), you're instead storing it once, and then every object that wants to know about that value can just reference it.

    All this is good, and the Engine will reward you with blazzingly fast FPS on potato devices for your trouble!
     
    Last edited: Apr 30, 2019
  20. phobos2077

    phobos2077

    Joined:
    Feb 10, 2018
    Posts:
    68
    Have you tried interfaces? Just use them instead of SO's if all you need is to reduce coupling between components (like player health). No need to overcomplicate the structure of your MonoBehaviors with extra SO's.
    Interface fields are not normally supported by Unity's inspector, but there is a handy workaround for this. I can show you if you want. Basically you create a special InterfaceReference class and a PropertyDrawer and vuola! - your components don't care if you put another MonoBehavior or ScriptableObject reference into the field - all they know is the object implements certain interface. So your code is clean and no need to restructure your components.

    PS: your UI code is inefficient. You ideally shouldn't update e.g. "text" property every update. Use Observer pattern to resolve this (plain simple C# public events) or use UniRx - it's awesome.
     
    Last edited: Jun 10, 2019
    NoxCaos and NeatWolf like this.
  21. NoxCaos

    NoxCaos

    Joined:
    Jan 14, 2014
    Posts:
    10
    I agree with this. Instead of trying to create refs like that, it is much better to go with Observer pattern. Way less updates for UI, much higher FPS.

    I would still want to create an instance for SO. Let's say I have SO that describes basic enemy parameters, like attack, defence, speed and health. First three is something that should not change, but health is changing during the game. But if all enemies have reference to the same SO, changing health will change it for all enemies in the game.

    So I guess my question is: is that still okay to use Instantiate to create SO instances if it has [NotSerialized] property? If I want to handle logic in one 'System' of enemies, it is easier to have access to all data right away, rather than referencing source of 'static' data (SO) and custom class of 'dynamic' data.
     
  22. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,655
    You wouldn't want to create an instance for the SO though. The point is that the SO doesn't contain data that needs to be instantiated per consumer, it's shared data instead- if it does contain per-GO instance data, then it being an SO isn't serving any real purpose. Use a completely normal POCO object and "new SomeClass()" instead and put your instance data in there.

    My answer is still the same now as it was over a year ago when I originally posted here: if you're instantiating an SO to use for data, you're taking a really bizarre and inefficient route to the goalpost. That doesn't mean it's not technically viable, but if someone asks me directly if it's "okay", I'm going to have to say "not really". It feels like using the wrong tool for the job. Having one source of static data that's shared between a bunch of different instances and doesn't change at runtime, and one source that's purely per-GO for data that can actually change: those distinctions are what makes the SO a gain in efficiency.

    The problem isn't the non-serialized fields, but the serialized ones- if you're duplicating all of that information on a per-GO basis, that gain is lost, and you have the overhead of all of the SO inherited behaviours that now can't even be used at runtime.

    Anyways, using the right interface, you can abstract out which properties pull information from the SO and which pull from the dynamic data- it's simply an implementation detail, and you save time and energy by minimizing the dynamic data you have to serialize yourself for save files. Those are a lot of little victories to throw away because you don't like having two data sources for some reason.

    But now, and as always, do whatever you like- it's your game, and most pegs can be hammered into most holes if you're willing to hit them hard enough, I've just never personally been fond of hammers is all. =)
     
    Last edited: Jul 21, 2019
    phobos2077 likes this.
  23. NoxCaos

    NoxCaos

    Joined:
    Jan 14, 2014
    Posts:
    10
    Thank you a lot for reply, it really clarifies a lot of things for me and the point that you were making a year ago. This is really confusing, since so many people just suddenly started to use SO for literally everything. Even Unity themselves have different videos and articles that have different architecture approaches regarding SO.

    I see your point and I agree with you. Essentially making a copy of static data is a waste of resources.
     
    phobos2077 likes this.
  24. BloodHound_PL

    BloodHound_PL

    Joined:
    May 12, 2016
    Posts:
    3
    I want to create Task System for AI-bots capable of using tools and machines in a variety of contexts. I consider SO in its static nature as universal recipe for using drills, lawnmowers or bulldozers, but since it can be instantiated it could also store/find level-dependent data like designated drive-by/patrol route (one of many possible), mission objective or simulated accident coordinates. I'm going to test this right away, thanks for that thread.
     
  25. patrykszylindev

    patrykszylindev

    Joined:
    Oct 28, 2019
    Posts:
    13
    Would you be so kind and share how to create special interface references? I've been at it for past two days, and I have to admit. It is quite difficult to wrap my head around it. I'd much prefer to follow SOLID instead of hacking this sort of problem with SOs. I'd appreciate it a lot!

    Thanks,
    Patryk.
     
  26. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    803
    Sorry but these videos aren't really related. You should use SOs only as data containers (immutable data) like json and XML files. In a few situations, you can make use of SOs with mutable data.

    Using "CreateInstance" is completely awful in order to create a new instance of an SO. You can utilize normal pure classes (containing data and method) and populate them with the SO.
    If you have only one unique object(such as inventory system, player data, etc), it may be suitable to employ SO containing mutable data and method.
     
    Last edited: Dec 14, 2019
    phobos2077 likes this.
  27. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    10
    Sorry if this is too much of a necropost. This thread has come up a lot for me in Google lately.

    I do think that it can be very useful to use SOs as containers for values that should be instantiated multiple times, like the health of an enemy, but I also think it is usually a very bad idea to instantiate SOs in code. Instantiating them kind of defeats the point of using them. Basically, what I do is I use SOs as keys in a dictionary of values (I actually use them as keys in a dictionary of indexes of a list of values, for some performance tricks, but that is not very important right now). The dictionaries are stored in special MonoBehaviours.

    This allows me modularize and reuse my code a lot, because the same MonoBehaviours can modify different sources of data and it's very easy to manually share values between scripts without each of them having to reference one another explicitly (and without having to write a lot of interfaces). I also can make prefabs with this without needing multiple SOs. This helps with more than MonoBehaviours; I've actually made FSM and GOAP systems where the same graph file can be used on a lot of very different entities because they reference the same SOs as each entities behaviours and, at the same time, those SOs values are unique per entity (or, optionally, can be global too).

    I'll share this system when I polish it a bit more, but I wanted to say: TL;DR. Scriptable Objects can be very useful, they can make Game Design a lot easier. You can get a lot of what you need from Scriptable Objects if you get a bit creative with your systems. You don't need to instantiate them most of the time, though; that's usually an antipattern.
     
    Last edited: Jan 8, 2020
  28. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    5
    Let me add my 3 cents.
    If I am correct, the whole idea of unity object is to allow user interaction with runtime objects, setuping, saving, connecting them via graphical interface to make everything scalable and easy to use. Scriptable objects are data containers, but at the same time allow to plug/connect assets and data. In addition inheritance can be handled well (unlike serialized classes), so using them to build and save data structures sounds like good idea.

    Consider this example: There is some more complex structure like FSM or behaviour tree based on scriptable objects.
    I can make AI graph and plug it into some MonoBehaviour on scene, the problem starts when I need to run several AI agents. This graph may need to store some runtime state in private memebers, but as it is SO asset, it is shared among all instances of enemies and it does not work. On the other hand, I could instantiate a runtime copy for each enemy, so all units have own graph and state.
    The only way to avoid situation above would be to make corresponding standard c# class for each node, but creating 20 (or more) another similar classes for each node sounds ridiculous.

    Edit: Actually this is not the best example, because single Instantiate would make copy only for the top most object. To make it work it's needed to traverse and copy all nodes.
     
    Last edited: Jan 25, 2020 at 4:22 AM
unityunity