One minor errata: On the slide about Reload-proof Singletons, I use 'FindObjectOfType' to retrieve the singleton object. This will use Object.FindObjectOfType, which will fail to find objects that are marked with HideAndDontSave... what you should use instead is Resources.FindObjectOfType, which should find the singleton correctly. I think I fixed it in the demo project already.
Fantastic talk Richard! Very informative. I've been using SO with lists for a few months and this was enlightening. I'm still on unity version 5.0 and now I'm tempted to update to use some of these wonderful new features shown here. Please do not be discouraged by the naysayers as we need MORE high level talks such as this. There's an overabundance of beginner tutorials and youtubers teaching the basics. Anyone who thinks this was bad bc it's above their understanding should be directed to the live training on unity archives. Thanks for your time.
Holy moley this is EXACTLY what I needed to hear to be convinced on ScriptableObject. The project I'm working on uses so many 'singleton-like' shared controllers that would be perfect for scriptableobject! I knew about them, but I wasn't quite convinced to use them until this talk. Great presentation, 5/5. Be careful with that 'radio' voice though.. it was almost too soothing xD
Thanks so much, Richard. This was precisely the guidance I needed in handling a tricky problem of managing some shared data using .asset files, and managing the life cycle of that data in memory.
I've been using ScriptableObjects for custom asset files for a few years now, and it's one of my favorite things when working in Unity! I didn't know about the CreateAssetMenu attribute and was using a little Editor script to add the menu items - this'll be a big time saver! I also didn't know about loading from external files with JsonUtility - that's a real game-changer for me! My one complaint about custom assets was that they weren't open to modders, since the files are packed into the game. I am delighted to be wrong!
From what I can tell the concerns on MonoBehaviours are all centered around just general carelessness. For example: You will only have an orc with 300 health if someone willingly makes it 300, puts it into a scene and apply/save it. This can be fixed easily if you instead apply the orc prefab with health of 100 and have a spawner of sorts instantiate the object. Then again, I work alone so that's just me.
Data inconsistency is only one of the problems I discussed - there's also stuff like memory wasted by duplicate data on each instance, increased Instantiate time, etc - but you're right that it only happens if you actually change and save the value. Still, in my experience, this *does* happen - whether it is newbie design interns doing the wrong thing, or simply mis-clicking stuff (and not noticing that some extra change is now riding along with the other things you're saving). It might be less of an issue when you're working solo, for sure.
Absolutely, I use my own make shift systems to do certain things. May seem noobish to some, but as long as it doesn't tax the system to hell and it works, then it's fine in my book. But I see how Scriptable Objects can be useful. Right now I have an object called UniversalObject that's created in the main menu. Isn't Destroyed OnSceneLoad, and is intended to be used throughout the player session. This object holds 2 scripts that keeps track of the player stats and triggers certain music to play on certain scenes. I also have the player object send the player stats to this UniversalObject. Do you think it would be beneficial to convert all of this into Scriptable Objects?
It could be - it would get it out of your hierarchy, and might make it easier to do things like serialize the player stats to/from JSON or write automated tests to check that e.g. when the player's kill count is above a certain level, then it correctly unlocks an expected achievement. That said, if you're happy with what you've got now, I wouldn't go changing it just for 'theory' reasons.
Richard, could you explain the benefits of doing a Delegate Objects Pattern vs attaching a new MB that does it's own work inside it's own coroutine attached to a Prefab? It seems prefab can do the same, including persisting data from play mode.
An important thing to note with ScriptableObjects is that you CANNOT instantiate them at runtime on a built project. This is something that caused me a lot of pain in the past because all of you logic will work just fine when testing in the editor. Just something to keep in mind if you are going to use them you may need to reference an asset. But if you are using them for editor tools that isn't an issue.
You most certainly *can* instantiate them at runtime on a built project - just use ScriptableObject.CreateInstance(). What you can't do is save them back into the Assets folder, because there is no Assets folder in a build - you have to write your own serialization (though classes like JsonUtility can make that very easy).
Really? Well that's great then! I must have done something else wrong. I was using them as a custom "extendable enum" type similar to what was described in the video, but for some reason instantiation and assignment to monobehaviour fields wasn't happening on build, but worked perfectly fine in the editor. I'll have to revisit this and see what went wrong. Using Scriptable Objects was a very convenient solution there.
@@DetectivePoofPoof Answer is very late, but may help others. If I understood correctly, Scriptable Objects get removed by Garbage Collector during runtime, if they lose all references. As Richard said, there is no Assets folder in a build. So it would be important to always have your SO's reference some GameObject which keeps living. Maybe this was the issue you were running into.
This is really clever solution to a lot of problems I have had with unity. I'm not sure if the original presenter will be reading these, but how does ScriptableObject work with something like the decorator pattern?
@Richard Fine Could you use ScriptableObjects like one would use a stylesheet? I'm currently developing software for Hololens and that would make my life so much better.
Sure - they're just data storage. You could have a ScriptableObject that contains all your 'style' information, and make your components look things up in it (in whatever way makes sense). Then by changing the ScriptableObject instance that they use, you change the stylesheet they're using. (This is pretty much exactly how the GUISkin object, in Unity's IMGUI system, already works).
Great presentation, I got a question for you Richard: you said that an unreferenced ScriptableObject with the hide flag set to HideAndDontSave doesn't get freed by Resources.UnloadUnusedAssets(), but does it get freed by calling GC.Collect?
Nope. GC.Collect only ever cleans up scripting wrappers that you have no references to; if there is a 'native part' of the object it doesn't free that (which is what Resources.UnloadUnusedAssets is for).
This part of the demo code does not make sense to me, if we DO NOT have an instance of the, destroy it? How can you destroy it if it does not exist? public static void LoadFromJSON(string path) { if (!_instance) DestroyImmediate(_instance);
ScriptableObjects are they are saved by reference?, if so and you were doing something like a loot table with a dictionary or list of custom Loot classes on the scriptable object. Would referencing an item in the list be saved as references, or would they need to be ScriptableObjects as well?
Not a huge difference - both require that the tests are run from within Unity, but if you've designed things around SOs it's a bit easier to a) swap them out for test data assets in integration tests, and b) test the SOs themselves without affecting things in the scene.
Thanks for the response. But do the ScriptableObjects also require that I use this rather clunky "humble object" pattern in order to test anything in it: blogs.unity3d.com/2014/06/03/unit-testing-part-2-unit-testing-monobehaviours/ ?
I'm sorry, I don't understand this "outside of Unity" concept. It's my understanding that the humble pattern is required if you want to unit test MonoBehaviours in any way at all (whether it's inside or outside Unity). Because you can't mock MonoBehaviours as you're not allowed to call "new" on them.
You're correct that you cannot mock MonoBehaviours, but mocking is not required to write automated tests - it's just better because it means things are cleaner and more isolated. You can still write automated tests that just use real objects all of the time. However, you only have that option if you are running inside of the Unity environment; if you want to run your tests outside of Unity (e.g. from Resharper's Unit Test Runner) then yes, you will have no choice but to use a pattern like Humble Object to isolate your code from the engine.
Downloaded the repo and i get a major issue, (5.6.1 version). I do play in CompleteMainScene and if i stop the play in middle of a game, it will never play again because it lost reference to tank in the gamestate which i cant modify! How can we fix this problem ?
Funny that in the presentation he never mentions his name. Reminds me of the Laura Poitras Snowden document Snowden interview. Where is the promised online repo? I would love to play with that AI stuff.
Clone to atlassian button did not work, something about permissions. And manual download, and open with Unity the project crashes. After several re-opens it fails to import playerinfo prefab. If asked to re-import it Unity crashes. Filed a bug report.
Another question: You list the fact that ScriptableObjects don't reset when you stop play mode as a benefit. However, we're so used to the fact that everything resets that this becomes a drawback. The resetting allows us to play with things without long-term consequences. Do you have any suggestions on how we might make ScriptableObjects reset after leaving play mode?
I'd avoid changing the ScriptableObject instances that are in the project, and instead Instantiate() copies of them when entering play mode. Use the copies for everything and let them be thrown away when exiting playmode.
They're not visible in the hierarchy, but if you can select them somehow (e.g. by setting Selection.object) then you can see and edit them. You can also use Editor.CreateEditor to make an editor for them which you could embed inside a custom editor for another object (or even a custom editor window) - a bit like how the editor for a Material is 'embedded' in the editor for a GameObject when there's a Renderer component attached.
I think the idea is that you have a dictionary of . In the demo that would be which you populate with an arbitrary number of ammo types either in the inspector or hook it up some other way upon initialization. Then afterwards you can use the dictionary and do the int comparisons.
[6:24] Oh I still laugh and cry. ScriptableObjects *CAN* be attached to GameObjects. But you do, you really wish you didn't, it's not functional and it *cannot be detached* and you have to delete the GameObject to get rid of it.
And then you realize that you have to have the same data between client and server. And entire lecture becomes useless, since you cant use .asset file on Java server without wraping it up in serializers and deserializes. So why double work?
One minor errata: On the slide about Reload-proof Singletons, I use 'FindObjectOfType' to retrieve the singleton object. This will use Object.FindObjectOfType, which will fail to find objects that are marked with HideAndDontSave... what you should use instead is Resources.FindObjectOfType, which should find the singleton correctly. I think I fixed it in the demo project already.
One of the best talks given 1. clarity, 2. depth, 3. great examples
Fantastic talk Richard! Very informative. I've been using SO with lists for a few months and this was enlightening. I'm still on unity version 5.0 and now I'm tempted to update to use some of these wonderful new features shown here.
Please do not be discouraged by the naysayers as we need MORE high level talks such as this. There's an overabundance of beginner tutorials and youtubers teaching the basics. Anyone who thinks this was bad bc it's above their understanding should be directed to the live training on unity archives. Thanks for your time.
Holy moley this is EXACTLY what I needed to hear to be convinced on ScriptableObject. The project I'm working on uses so many 'singleton-like' shared controllers that would be perfect for scriptableobject! I knew about them, but I wasn't quite convinced to use them until this talk. Great presentation, 5/5. Be careful with that 'radio' voice though.. it was almost too soothing xD
Thanks :) I must admit, it was the end of a long day and that room was so warm, I was on the verge of falling asleep myself ;)
Good bye different GameManager objects. By the way it is really nice to see someone who actually is working with code a lot.
So many knowledge and good practices in just 50 minutes. Thanks, Bro!
Thanks so much, Richard. This was precisely the guidance I needed in handling a tricky problem of managing some shared data using .asset files, and managing the life cycle of that data in memory.
I've been using ScriptableObjects for custom asset files for a few years now, and it's one of my favorite things when working in Unity! I didn't know about the CreateAssetMenu attribute and was using a little Editor script to add the menu items - this'll be a big time saver!
I also didn't know about loading from external files with JsonUtility - that's a real game-changer for me! My one complaint about custom assets was that they weren't open to modders, since the files are packed into the game. I am delighted to be wrong!
25:17 Reload-proof Singleton ScriptableObject, this is gold
From what I can tell the concerns on MonoBehaviours are all centered around just general carelessness. For example: You will only have an orc with 300 health if someone willingly makes it 300, puts it into a scene and apply/save it. This can be fixed easily if you instead apply the orc prefab with health of 100 and have a spawner of sorts instantiate the object. Then again, I work alone so that's just me.
Data inconsistency is only one of the problems I discussed - there's also stuff like memory wasted by duplicate data on each instance, increased Instantiate time, etc - but you're right that it only happens if you actually change and save the value. Still, in my experience, this *does* happen - whether it is newbie design interns doing the wrong thing, or simply mis-clicking stuff (and not noticing that some extra change is now riding along with the other things you're saving). It might be less of an issue when you're working solo, for sure.
Absolutely, I use my own make shift systems to do certain things. May seem noobish to some, but as long as it doesn't tax the system to hell and it works, then it's fine in my book. But I see how Scriptable Objects can be useful. Right now I have an object called UniversalObject that's created in the main menu. Isn't Destroyed OnSceneLoad, and is intended to be used throughout the player session. This object holds 2 scripts that keeps track of the player stats and triggers certain music to play on certain scenes. I also have the player object send the player stats to this UniversalObject. Do you think it would be beneficial to convert all of this into Scriptable Objects?
It could be - it would get it out of your hierarchy, and might make it easier to do things like serialize the player stats to/from JSON or write automated tests to check that e.g. when the player's kill count is above a certain level, then it correctly unlocks an expected achievement. That said, if you're happy with what you've got now, I wouldn't go changing it just for 'theory' reasons.
Richard Fine Alright nice, thanks for the advice
Know this is 6 years later but Exactly This
This is great, thank you!
Great talk! Thank you so much! Can't wait to take a look at the demo project. :)
Great presentation
Thanks for providing the Demo project
Richard, could you explain the benefits of doing a Delegate Objects Pattern vs attaching a new MB that does it's own work inside it's own coroutine attached to a Prefab? It seems prefab can do the same, including persisting data from play mode.
i just discovered this and its saved the fucking life of my project
Good job Richard Fine, another great talk from you! :)
Great talk !
great talk.. cheers mate..
34:34 He did not explain where "Shell Explode" scriptable object is used. He created scriptable object but he did assign it in the Inspector Window.
Thanks! Great talk.
An important thing to note with ScriptableObjects is that you CANNOT instantiate them at runtime on a built project. This is something that caused me a lot of pain in the past because all of you logic will work just fine when testing in the editor. Just something to keep in mind if you are going to use them you may need to reference an asset. But if you are using them for editor tools that isn't an issue.
You most certainly *can* instantiate them at runtime on a built project - just use ScriptableObject.CreateInstance(). What you can't do is save them back into the Assets folder, because there is no Assets folder in a build - you have to write your own serialization (though classes like JsonUtility can make that very easy).
Really? Well that's great then! I must have done something else wrong. I was using them as a custom "extendable enum" type similar to what was described in the video, but for some reason instantiation and assignment to monobehaviour fields wasn't happening on build, but worked perfectly fine in the editor. I'll have to revisit this and see what went wrong. Using Scriptable Objects was a very convenient solution there.
@@DetectivePoofPoof Answer is very late, but may help others. If I understood correctly, Scriptable Objects get removed by Garbage Collector during runtime, if they lose all references. As Richard said, there is no Assets folder in a build. So it would be important to always have your SO's reference some GameObject which keeps living. Maybe this was the issue you were running into.
Great presentation!
Does anyone know how can I add that(32:02) preview function to my scriptable object?
Overthrowing Monobehaviours is the way although I wouldn't say that you need ScriptableObjects to do that :)
Very impressive.
Difference between this and PropertyAttribute?
This is really clever solution to a lot of problems I have had with unity.
I'm not sure if the original presenter will be reading these, but how does ScriptableObject work with something like the decorator pattern?
@Richard Fine
Could you use ScriptableObjects like one would use a stylesheet? I'm currently developing software for Hololens and that would make my life so much better.
Sure - they're just data storage. You could have a ScriptableObject that contains all your 'style' information, and make your components look things up in it (in whatever way makes sense). Then by changing the ScriptableObject instance that they use, you change the stylesheet they're using. (This is pretty much exactly how the GUISkin object, in Unity's IMGUI system, already works).
Great presentation,
I got a question for you Richard: you said that an unreferenced ScriptableObject with the hide flag set to HideAndDontSave doesn't get freed by Resources.UnloadUnusedAssets(), but does it get freed by calling GC.Collect?
Nope. GC.Collect only ever cleans up scripting wrappers that you have no references to; if there is a 'native part' of the object it doesn't free that (which is what Resources.UnloadUnusedAssets is for).
This part of the demo code does not make sense to me, if we DO NOT have an instance of the, destroy it? How can you destroy it if it does not exist?
public static void LoadFromJSON(string path)
{
if (!_instance) DestroyImmediate(_instance);
ScriptableObjects are they are saved by reference?, if so and you were doing something like a loot table with a dictionary or list of custom Loot classes on the scriptable object. Would referencing an item in the list be saved as references, or would they need to be ScriptableObjects as well?
@22:45 should be:
JsonUtility.FromJsonOverwrite(json, result);
Too bad those great optimizations did not find their way into the latest "Tanks!!! Reference Project". Or am I wrong?
Sadly his jokes never go down well, I feel sorry for him :P
Great talk though, I'm an advocate of using Scriptable Objects wherever you can.
Is there any difference between MonoBehaviours and ScriptableObjects when it comes to automated testing (mainly Unit Testing)?
Not a huge difference - both require that the tests are run from within Unity, but if you've designed things around SOs it's a bit easier to a) swap them out for test data assets in integration tests, and b) test the SOs themselves without affecting things in the scene.
Thanks for the response. But do the ScriptableObjects also require that I use this rather clunky "humble object" pattern in order to test anything in it: blogs.unity3d.com/2014/06/03/unit-testing-part-2-unit-testing-monobehaviours/ ?
If you want to run the tests outside of Unity, yes.
I'm sorry, I don't understand this "outside of Unity" concept. It's my understanding that the humble pattern is required if you want to unit test MonoBehaviours in any way at all (whether it's inside or outside Unity). Because you can't mock MonoBehaviours as you're not allowed to call "new" on them.
You're correct that you cannot mock MonoBehaviours, but mocking is not required to write automated tests - it's just better because it means things are cleaner and more isolated. You can still write automated tests that just use real objects all of the time. However, you only have that option if you are running inside of the Unity environment; if you want to run your tests outside of Unity (e.g. from Resharper's Unit Test Runner) then yes, you will have no choice but to use a pattern like Humble Object to isolate your code from the engine.
What does he mean by "C# statics"?
Downloaded the repo and i get a major issue, (5.6.1 version). I do play in CompleteMainScene and if i stop the play in middle of a game, it will never play again because it lost reference to tank in the gamestate which i cant modify! How can we fix this problem ?
I still prefer the Ryan Hipple take on this
Funny that in the presentation he never mentions his name. Reminds me of the Laura Poitras Snowden document Snowden interview.
Where is the promised online repo?
I would love to play with that AI stuff.
bitbucket.org/richardfine/scriptableobjectdemo/src
Clone to atlassian button did not work, something about permissions. And manual download, and open with Unity the project crashes. After several re-opens it fails to import playerinfo prefab. If asked to re-import it Unity crashes. Filed a bug report.
Another question: You list the fact that ScriptableObjects don't reset when you stop play mode as a benefit. However, we're so used to the fact that everything resets that this becomes a drawback. The resetting allows us to play with things without long-term consequences. Do you have any suggestions on how we might make ScriptableObjects reset after leaving play mode?
I'd avoid changing the ScriptableObject instances that are in the project, and instead Instantiate() copies of them when entering play mode. Use the copies for everything and let them be thrown away when exiting playmode.
Can you edit the values on instantiated ScriptableObjects? Are they visible in the hierarchy?
They're not visible in the hierarchy, but if you can select them somehow (e.g. by setting Selection.object) then you can see and edit them. You can also use Editor.CreateEditor to make an editor for them which you could embed inside a custom editor for another object (or even a custom editor window) - a bit like how the editor for a Material is 'embedded' in the editor for a GameObject when there's a Renderer component attached.
OOP for the win!
But (almost) all my scripts use references to in-scene objects! Am I doing Unity wrong? :P
❤️ Unity ❤️
19:49 what's the overhead for this? This feels way bulkier than an enum.
I think about 4 bytes per reference. In practice it's not been a problem.
Nice talk though! :)
And I don't get the extendable enums either... :/ When is the object set and how do you compare it to ints?
I think the idea is that you have a dictionary of . In the demo that would be which you populate with an arbitrary number of ammo types either in the inspector or hook it up some other way upon initialization. Then afterwards you can use the dictionary and do the int comparisons.
great
17:17 isn't this just flyweight?
Pretty much, though using ScriptableObject as a basis for the flyweight pattern makes the instances easier to manage.
Damn Im 4 years late
很ok
[6:24] Oh I still laugh and cry.
ScriptableObjects *CAN* be attached to GameObjects.
But you do, you really wish you didn't, it's not functional and it *cannot be detached* and you have to delete the GameObject to get rid of it.
Unlike everyone else, the *FIRST* time I hear something like this, I test it, and sometimes a few more times.
You need to fix this.
And then you realize that you have to have the same data between client and server. And entire lecture becomes useless, since you cant use .asset file on Java server without wraping it up in serializers and deserializes. So why double work?