I agree. I tried implementing a more designer-centric development process in our process at a previous company I worked at years ago, but I never had the time to develop it to the point of discovering the capabilities of ScriptableObjects. UnityEvent was a Godsend, and a worthy successor to SendMessage, which had potential, but some serious caveats and performance issues.
Totally agree. Far to many videos are purely about how to make X work. That's fine, but when you approach game dev a little more professionally, these architecture decisions/challenges comes up pretty fast - and are very hard to find the "best practice" for often. Personally I come from a coding background, so I'm not a super fan of all this drag'n'drop stuff. Sure of cause the editor is awesome to build 3d worlds etc, but like references between things very quickly becomes a nightmare. Yes you can do "Find references in scene"....but what if you have multiple scenes? Generally figuring out how things are referencing each other is one of my big challenges - as I want things to be a simple as possible. Too often, if not always, it's based on "something you need to know" - and that sucks :) Haven't watched this video to the end yet, hoping for some ideas - however I am already running a lot of stuff "event" driven, via a Message system in code, so I'm on the same path.
36:25 "If you write a simple inspector" This is kinda just thrown out there. For people wondering where this button came from, paste this code in a new C# Script using UnityEngine; using UnityEditor; [CustomEditor(typeof(GameEvent))] public class WhateverYourScriptNameIs : Editor { public override void OnInspectorGUI() { DrawDefaultInspector(); GameEvent myGameEvent = (GameEvent)target; if (GUILayout.Button("Raise()")) { myGameEvent.Raise(); } } }
Same here... Holy shinning cubes! Scriptable objects just went from "meh" to "amazing!" in my mind. I was so not understanding their advantages! I'm shocked at how deep I was down in Dunning-Kruger effect...
actually, we have something similar in tv production animations with assets constantly referenced in various animation shots. and any change in the assets gets an update throughout. Talk about updating all the 200 shots just for more skin texture switch.
So I took this concept and ran with it a bit. Here are some things I learned and some advice for other developers: All my ScriptableObjects inherit from a base class ScriptableGameObject, that has a few fields on it, most notably a string for a developer description. This is never actually used but it basically means any developer on the project can write anything they want about any object in the inspector. Also, It's probably best to also make a ConstFloatReference, which is the same as a FloatReference (or whatever) but doesn't let you change the value in your code (you can still set a custom value in the inspector and can still reference a normal variable). This has no bearing on the actual game and there's no such thing as a "constant" in your actual variable classes, but it means that at the reference point, you can't accidentally change the value of a variable in your code. This is useful if, for example, you have UI elements that read the players health but you want to make sure that they cannot change the players health under any circumstances, so it's effectively a "one-way" variable link. It's just an extra level of safety at the cost of a little bit of extra work. I also have a generic ScriptableObject-based ObjectPool which takes a prefab and can automatically handle creation/enabling/disabling etc of objects in the pool. This is extremely useful because it encourages me to use more object pools (I can create them basically as I need them with a simple right click, and create, say, a "Pistol Bullet Pool") which itself results in a more efficient game because every weapon that fires projectiles can very easily use an object pool and even share them (in the case of multiplayer). Lastly, if you combine this with pluggable stuff like Pluggable AI as seen in the other Unity videos on this topic, you can get a lot of flexibility. In general you should be favoring references over a complex inheritence heirarchy or a lot of singletons. But singletons are still required, unfortunately. For example, it's pretty much impossible to set a game state without using a singleton. I mean you can technically use a game state variable, but if you want all of your game objects to, say, not move when the game state is "Paused", you either have to use a singleton to store the gamestate so you can check it, or you have to reference a game state variable in each object, which can be an absolute pain because you will likely have to do it with every prefab in your entire project.
I was wondering about your second point. It would seem without that everything would be just be made into a global which is really dumb. For your reference variable, is it just a wrapper essentially for the real variable and just returning the value? That seems like it would be the smartest thing you can do to make sure that not everything can write to everything.
@@litgamesdev The reference wraps the variable, but also contains a value of type T which can be used instead, selectable from the inspector (it also contains a bool to say if it's using the reference or not). This allows developers to easily have "one-off" cases. Nothing here is global.
Thanks for your help :). Your last point about needing to use a singleton, what if you are just activating everything that the camera sees and loading in chunks then it might not be that much effort to pause all the objects in sceen using a scriptable object event.?
@@pixelpat777 my general rule is: if it can be done without a Singleton, it probably should be. If you have a system to work with your camera that makes it self sufficient with minimal dependencies, then you're golden. The reason singletons are bad in the first place is because they add hidden dependencies to your objects and if that can be avoided, then it's probably a good thing.
I'm sitting here stunned, realizing how many stupid simple problems this would have solved for me if I had watched this back in nov 2017 as first posted... I've used scriptable objects for more typical data, but using them as globally available "meet in the middle" kind of user editable data is so obvious now!
2:38 Engineering Pillers 7:04 ScriptableObjects Basics 15:26 Modular Data 27:50 Event Architecture 38:30 Runtime Sets 45:32 No More Enums 50:33 Asset Base Systems
This is an amazing demonstration of the power of ScriptableObjects. I spent a week re-watching this video, and modifying the demo scenes, until I attained complete understanding. It illustrates I've been overlooking the power of using ScriptableObjects, as opposed to singletons, in my work. I especially like your descriptions of what the 'wrong singleton alternatives' are - you perfectly pointed the path down which I went, not knowing what Unity was capable of. Thank you for sharing this excellent work. I can tell you hid company secrets, as you hinted at in the demonstration - yet you pointed out all the salient points of ScriptableObjects quite well anyway. Replacing the GameEvent listener list with Delegates is an exercise to be done by the student, for extra credit. ;-)
This really is a great talk, as you pointed out, we have lots of info on how to accomplish very specific things in Unity, but I feel that design best practices / design patterns specifically within Unity is one of the areas I have the hardest time getting information about.
@@herohiralal3255 i think this is what he said: You don't reference the "owner" at all to get the value because the SO holds the value. It's better and safer for designer because it gives them a GUI to create their own values with other SO features to help. Changes affect all scenes and any objects which rely on them(stops accidental prefab changes and is a form of serialization). That's what I got.
@32:41 lmao he actually moved the background art thing up to perfectly not-cover the word "hookers." Obviously great presentation overall but I specifically appreciate the effort that went into this easter egg of a meme
I started using these for pretty much everything. They solve pretty much every issue I typically have to deal with. I never wanted to use multiple scenes because it was a pain to serialize and deserialize data between scenes. Now it doesn’t matter. I can just drop in whatever I want without a care in the world.
I cant express how important the video is ... THis is one of the best video in UNITE, THE demonstrator is super knowledgeable and has shown powers of SOs, and is really good at demonstration. THank you very much
Been doing Unity at home for a couple years now and always knew I should be using Enums. I used them for the first time last night, spent a bunch of time setting up a bunch of stuff using them ... then added a new one near the top of the list ... OMG !! ... it didn't keep the values I set where I used them !! ... well THATS good to know !! ... and here I am :)
This is very useful, its a shame there isn't people like him (that I'm aware of) making unity courses or books that go through how to apply this stuff in detail, I'd find it very useful to have a book/course that goes through how to apply this step by step rather than an overview.
I'm so glad someone directed me to this talk. Had no idea how powerful Scriptable Objects could be, and will definitely be watching the Richard Fine and The Hack Spectrum talks next. Thanks Ryan!
I agree, he was very easy to listen to, not condescending in the least, intelligent, articulate. I would like to see more game development topics presented by him.
I have just discovered this video and I have to say that it is amazing! For the first time, someone has explained me very well how ScriptableObjects can be used
While eye-opening, this presentation sent me down a two-day rabbit hole which consisted of me slamming headfirst into scripting mania and error headaches. Making float variables was the easy part. I can barely customize the editor to display them in the Inspector!
Awesome talk, thank you! I personally get rid of using Editor to set references as much as possible as it's really difficult yo find those references later or make sure Unity did not broke them for unknown reason at some point. Doing everything via code saved my life but I will give a try to use scriptable object based event system.
i didn't know until now that scriptable objects are important for game architecture. I always wondered how Developers manage to do this in AAA Games. Really eye opening talk. Recommended Talk!!!!
This is fascinating. In a lot of ways, Unity and its particular setup seems to get in the way when you try to program from a typical perspective. I'm very new to it, so I'm not fully on board with its style of doing things yet. You've created some very clever ways of doing things that embrace Unity's strengths and that's pretty awesome. This and Richard Fine's talk about ScriptableObject should be required viewing. Thank you very much! :-)
This was an incredibly useful speech that hit many issues that I struggled with. Virtually every point I have worked at some point but was unsatisfied with my solutions. After watching this it's time to take another whack at it. Thanks!
For anyone interested - we've just open-sourced our implementation of this concept, called SmartData. It's comprehensive, powerful, extensible, includes custom editors and even a live node-graph visualizer/debugger. github.com/sigtrapgames/SmartData
Wish we had an example of that inventory system, saving/loading and resetting those scriptable objects must be quite tricky. Not sure if I want to attempt that myself yet.
So to make sure that I've got this architecture concept straight, I'd like to use scriptableobjects for my multiplayer game. For this reason, I'd like the shared configuration of this type - things like Max Health etc., to be FloatVariable, IntVariable, and so on as required (Or simply - BaseConfiguration to hold all of them together, increased locality). In order to let our UI bind itself to the player's data, I'd like to use FloatReference, IntReference, etc (Or simply - PawnStateReference - holds everything you intend other systems to interact with, leaving other fields as true private fields for encapsulation) Then, the player our UI recognizes will have PawnStateReference hold the PawnStateVariable SO, and other clients of the exact same type/prefab will use the "constant" (isn't runtime a better name?) instead. Simple, client and other players share the exact same components with the player having an additional Input script that handles converting the inputs to actions via client pawn. UI only knows what our client pawn is doing extensibly, and if I'd like to add UI elements per every other player, I can use a RuntimeSet of all pawns in the scene and access the PawnStateReference from there, as it'll be public. I don't even need to add a messy "IsClient" boolean or whatever because I could just compare the PawnState reference with the one my UI recognizes. Is this considered an attempt to overengineer scriptableobjects into my game or does this seem like proper usage of the proposed architecture? Thanks.
Thanks for this great talk, especially for the demos and use cases presented; still very useful in 2018. :) And exactly what I was looking for, because as a Unity noob (but someone who understands SOLID programming in .Net) I had a lot of dilemmas about how to implement loosely coupled design in Unity, and most sources don't answer this at all. I also appreciate the critical tone towards some Unity characteristics, e.g. the curly brace placement and relying on magic strings.
So basically variables that may need to be shared between different "systems" could/should be individual SO's so it's easy to do so. That's pretty cool!
I'm a very new programmer. I started learning C# & Unity Development in late July of 2020 (it is late September 2020 as of writing this.) This talk has helped me out so much, that I cannot even describe the sheer thankfulness, and happiness I have from it. I'm currently at that point where I fully understand C# on a fundamental level. I'm familiar with the dynamic of value types & reference types on an intuitive level, and I am also familiar with all data types and how to properly implement them in accordance to eachother. The problem I do have though- what is the most efficient manner to use all of these tools together, in order to create the cleanest, most efficient, and modular manner? I really really like the system that he presented here, and I am going to be using it from here on out. This is a fantastic way to create systems that are decoupled from eachother. Utilizing the data types are the shared resource between different systems is a take that I have never even considered doing. I always thought that you HAD to reference system to one another, in order to create any sort of communicative functionality between said systems.
I really like the modularity and designer-centric focus of this approach. I use Zenject now and like it, but it's often not quite as easy to pivot with zero programmer involvement.
I tested it and combined it with pluggable approach. this architecture really challenges other architectures. Authorable for non-coders and easy to maintain
This is one of the most amazing talks I have seen.... Demonstrating stuff as you say about it... Yayyy to Scriptable objects.... Btw that we are not monsters line was XD
I like the idea of using an asset as a source of publicly communicating some data. It reminds me of a Unix Socket in the unix/linux world, a sort of public channel for reading/writing data.
this looks great and the talk is huge and very well done, It's just really hard for beginners to understand how to correctly implement them, or this is how I'm feeling
This talk, and the 2016 talk by Richard Fine are huge eye-openers, and greatly appreciated! I was wondering though: would it be a good idea to make the GameEvent and EventListener classes generic? That way, it can be parameterized for other generated UnityEvent types.
This is super nice talk. I've used this architecture in a couple of games and found myself often re-writing the same boilerplate code (for events), so I've found a really nice open-source library for it: github(dot)com/chark/scriptable-events. I really recommend using it!
Great talk, web lacks architecture advice for Unity developers. I wonder how they handle version source control issues using this approach. There are many changes after each game start, so it should be some type of runtime folder that must be in .gitignore file. But in that case game either will not start right after clone game repository or scriptable objects should be created by themself.
Looks like great stuff but I failed to understand some details (I am a novice in Unity). I wish there were more examples and code, less common phrases. Could anyone explain how FloatReferences are supposed to be used when we have not a single player with specific HP, but a bunch of different instances of units with their own individual HPs (like in RTS)? Are these FloatReferences HP have to be created for each unit at runtime? The same question is for Events: how it would be if an event could be raised by multiple sources (I don't want it to be received by all subscribers, but only those related to this specific source/instance)? Should we create a separate scriptable object for every event source? Could anyone provide some links to more complicated examples?
I feel you man, I tried to replicate his examples in a little project having a player and multiple enemies. I tried using his UnitHealth and just putting it on the enemy but as you said it would reference the same health the player references. I'm now Instantiating the health SO at runtime but finding it difficult to get a reference for that from the health bar. I would love for someone with experience to chime in with some wisdom.
I'm late but I would have the enemy have a MaxHealth FloatReference and a private float for currentHealth inside it that it tracks by itself. You only need to use this stuff for DI (Dependency Injection) anyway. Idk tho I've been a dirty Singleton user all my life so
If you are planning to have a constant number of human players in a given game session, ever say 4-8 then this approach would still work. If you are referring to X number of dynamic enemies that could be more than the 10+ and that comes and go at any given time then I would avoid this approach as you’ll end up creating X number of HP instance per enemy, and that’s only HP we’re talking and not counting other properties. However let’s say if each enemy had their own little HP UI above them, I suppose you could dynamically create an instance of the float variable with ScriptableObject.creatInstance() and wire that onto the enemy’s UI at runtime.
You reintroduce the tight coupling problem that singletons bring though. And ScriptableObjects are accessible from everywhere anyway. They're assets, so you can reference them like any other asset from within another class as normal. Like referencing a texture or an icon.
Thank god he doesn't use a Mac. Don't know why that always bothers me so much. Also, funny how they think people won't notice he is using an MSI laptop. Anywho, great talk. Definitely one of the most informative and insightful
This is a re-upload of a previous version of this video that had audio sync issues. They also could've been there in person or maybe they're even a co-worker or friend that helped edit or critique the presentation. Why would you put someone on blast just for saying, "Good Job"?
So I guess it is safe to say, and correct me if I am wrong, scriptable objects still rely on dependency. I can't imagine you can make a system without some kind of dependency. But the dependency is on the scriptable objects themselves. Makes sense.
Great talk! One downside that wasn't mentioned is that the event binding is only visible in the inspector, which makes this approach a little more unfriendly when viewing the source code outside of the Unity IDE.
He explained at 22:33 how his FloatVariable scriptable object could be used as a parameter in the animator but he never actually showed how to do it. How do you actually bind the two? Do you actually have to do somewhere in an 'Update' method a `animator.SetFloat(myFloatVariable)` to keep it in sync? What's the trick here?
You may have meant at 22:10? He says "I'd like to see" as it's not possible. One good spot for that `Update` would be a StateMachineBehaviour that has a field for a FloatVariable. This would allow syncing the animator parameter to match the FloatVariable only while in animator nodes that rely on that parameter for a transition.
This method requires that any consumers of a variable that are only concerned with changes in the value have to constantly poll the value and compare it to a previous state. This could have huge performance implications
Not if you make a variable object invoke a delegate on change! Some use cases benefit from checking every frame for data that changes a lot. Others can just get an event when it changes.
Working with enums isn't an issue with serialization, because you ALWAYS define the value for the enum to avoid these issues. But if some loss of performance isn't an issue, one can use the alternative approaches instead.
Yeah, I wasn't entirely sure why they couldn't safely remove certain enum values without breaking things. The compiler should be telling where enums that no longer exist are being used through errors.
Awesome talk, I really like the floatReference idea, but there is something I struggle to understand. How can I use float reference for runtime instance of object? Like the buildings health in your RTS exemple. We can put all the SO in runtime sets or dictionnary but it seem to be a "hacky" solution. And I can't figure how runtime sets and events can resolve totally the need of singleton or static reference, if I want the room where the player is standing or if I want to call a function of my saveSystem with parameters the singleton seem to be better.
Correct, SO was never intended to be a one stop solution for all. Understanding and combining SO usage where appropriate along with singleton just gives you an upper hand when making decisions in architecture. However, If you don’t want the singleton approach and want a more robust gameManager for larger scale games, then you can look into using a Dependency Injection framework.
You make a MonoBehaviour called Scope. Inside the Scope are dictionaries where SOs are keys. Values of the dictionaries can either be local copies of the SOs, real values (like float, bool, int, etc) for a little better performance an less memory, or a cacheable index of a list that has the real values for the best performance. Inside your other code, you call a method like Scope.GetFloat(SOFloat). Then, what GetFloat does is try to use SOFloat in a dictionary to get the value to return and, if it doesn't find it, an entry is created, initialized, and returned. PD For the cacheable index of a list. You'd cache the index inside a FloatReference instance, you'd pass that FloatReference to GetFloat instead of an SOFloat, and you only get the index from the dictionary if the SO referenced by FloatReference has changed or if it's being used with a new Scope. That way, getting the scoped value, most of the time, just means getting a value at an index from a list which can be a lot faster.
I'm a game artist looking at this guy's forehead and I think I just unlocked the ability to visualize better shading in my head now. Thankyou Ryan Hipple.
One more observation - the notion that DI is exactly what the inspector is for and that there's no need for DI frameworks like Zenject is only partially true imo. It would make more sense if: A. Every single class in your project that requires dependencies is either a MonoBehaviour or a ScriptableObject B. You don't use interfaces However in reality, you would want to use basic C# classes and interfaces and you can't inject their dependencies via inspector. Zenject also has many useful features like binding factories and memory pools. I would advocate for a combination of the inspector and a DI framework.
Interfaces can still work with the inspector! You serialize a reference to the UnityEngine.Object and use validation (OnValidate, ISerializationCallbackReciever, CustomEditor, PropertyDrawer) to reject the Object if it does not implement the interface. Then on Initialization (or ISerializationCallbackReciever.OnAfterDeserialize) you can cast to your interface and store it.
It sounds very hacky. I'm sure there are many ways to make it work. You could also purchase Odin Inspector from the Asset Store and serialize pretty much anything. But even if point B wasn't valid, there's still point A. I'm of the opinion that you shouldn't pollute scenes with objects that aren't 'actual things' in the scene, but are just there to run MonoBehaviours. The point is that the inspector cannot fully replace a DI framework.
Great talk, Ryan! You mention that the demo version of StringReference is a lot simpler than the one you use in production. I have been working on a very similar concept that is generic and free to use. I created a forum post for this, as well. As of yet, no one seems interested, so I would love some feedback from you (or anyone for that matter)! For anyone else interested in this, head to the forums to share your thoughts and questions. Or, better yet, start to contribute on the BitBucket repository! BitBucket Link: bitbucket.org/nobrainerinteractive/referenceablevalue Unity Forum Post: forum.unity.com/threads/referenceablevalue.505389/ Cheers, David
This was 5 years ago and yet, I still come back to this video for reference. This changed the way I use ScriptableObjects forever.
Very good talk, we need more talks in this quality for Architecture (y)
I agree. I tried implementing a more designer-centric development process in our process at a previous company I worked at years ago, but I never had the time to develop it to the point of discovering the capabilities of ScriptableObjects. UnityEvent was a Godsend, and a worthy successor to SendMessage, which had potential, but some serious caveats and performance issues.
Totally agree. Far to many videos are purely about how to make X work. That's fine, but when you approach game dev a little more professionally, these architecture decisions/challenges comes up pretty fast - and are very hard to find the "best practice" for often.
Personally I come from a coding background, so I'm not a super fan of all this drag'n'drop stuff. Sure of cause the editor is awesome to build 3d worlds etc, but like references between things very quickly becomes a nightmare. Yes you can do "Find references in scene"....but what if you have multiple scenes?
Generally figuring out how things are referencing each other is one of my big challenges - as I want things to be a simple as possible. Too often, if not always, it's based on "something you need to know" - and that sucks :)
Haven't watched this video to the end yet, hoping for some ideas - however I am already running a lot of stuff "event" driven, via a Message system in code, so I'm on the same path.
36:25 "If you write a simple inspector"
This is kinda just thrown out there. For people wondering where this button came from, paste this code in a new C# Script
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(GameEvent))]
public class WhateverYourScriptNameIs : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
GameEvent myGameEvent = (GameEvent)target;
if (GUILayout.Button("Raise()"))
{
myGameEvent.Raise();
}
}
}
Thank you!
You know, I wasn't entirely sold on scriptable objects until this talk. Thanks, it has been rather eye opening.
Same here... Holy shinning cubes! Scriptable objects just went from "meh" to "amazing!" in my mind. I was so not understanding their advantages! I'm shocked at how deep I was down in Dunning-Kruger effect...
actually, we have something similar in tv production animations with assets constantly referenced in various animation shots. and any change in the assets gets an update throughout. Talk about updating all the 200 shots just for more skin texture switch.
That's exactly what I went through, that's probably why he was shitting on Richard, cause his talk was meh at best but this is brilliant
Without a doubt the most mind blowing Unity talk ever. Excellent speaker.
he is rather good, I have to say
So I took this concept and ran with it a bit. Here are some things I learned and some advice for other developers:
All my ScriptableObjects inherit from a base class ScriptableGameObject, that has a few fields on it, most notably a string for a developer description. This is never actually used but it basically means any developer on the project can write anything they want about any object in the inspector.
Also, It's probably best to also make a ConstFloatReference, which is the same as a FloatReference (or whatever) but doesn't let you change the value in your code (you can still set a custom value in the inspector and can still reference a normal variable). This has no bearing on the actual game and there's no such thing as a "constant" in your actual variable classes, but it means that at the reference point, you can't accidentally change the value of a variable in your code. This is useful if, for example, you have UI elements that read the players health but you want to make sure that they cannot change the players health under any circumstances, so it's effectively a "one-way" variable link. It's just an extra level of safety at the cost of a little bit of extra work.
I also have a generic ScriptableObject-based ObjectPool which takes a prefab and can automatically handle creation/enabling/disabling etc of objects in the pool. This is extremely useful because it encourages me to use more object pools (I can create them basically as I need them with a simple right click, and create, say, a "Pistol Bullet Pool") which itself results in a more efficient game because every weapon that fires projectiles can very easily use an object pool and even share them (in the case of multiplayer).
Lastly, if you combine this with pluggable stuff like Pluggable AI as seen in the other Unity videos on this topic, you can get a lot of flexibility. In general you should be favoring references over a complex inheritence heirarchy or a lot of singletons. But singletons are still required, unfortunately. For example, it's pretty much impossible to set a game state without using a singleton. I mean you can technically use a game state variable, but if you want all of your game objects to, say, not move when the game state is "Paused", you either have to use a singleton to store the gamestate so you can check it, or you have to reference a game state variable in each object, which can be an absolute pain because you will likely have to do it with every prefab in your entire project.
Hey Paul, thanks! This is super helpful!
I was wondering about your second point. It would seem without that everything would be just be made into a global which is really dumb. For your reference variable, is it just a wrapper essentially for the real variable and just returning the value? That seems like it would be the smartest thing you can do to make sure that not everything can write to everything.
@@litgamesdev The reference wraps the variable, but also contains a value of type T which can be used instead, selectable from the inspector (it also contains a bool to say if it's using the reference or not). This allows developers to easily have "one-off" cases.
Nothing here is global.
Thanks for your help :). Your last point about needing to use a singleton, what if you are just activating everything that the camera sees and loading in chunks then it might not be that much effort to pause all the objects in sceen using a scriptable object event.?
@@pixelpat777 my general rule is: if it can be done without a Singleton, it probably should be. If you have a system to work with your camera that makes it self sufficient with minimal dependencies, then you're golden. The reason singletons are bad in the first place is because they add hidden dependencies to your objects and if that can be avoided, then it's probably a good thing.
I'm sitting here stunned, realizing how many stupid simple problems this would have solved for me if I had watched this back in nov 2017 as first posted... I've used scriptable objects for more typical data, but using them as globally available "meet in the middle" kind of user editable data is so obvious now!
2:38 Engineering Pillers
7:04 ScriptableObjects Basics
15:26 Modular Data
27:50 Event Architecture
38:30 Runtime Sets
45:32 No More Enums
50:33 Asset Base Systems
Holy sh{}t
This is an amazing demonstration of the power of ScriptableObjects. I spent a week re-watching this video, and modifying the demo scenes, until I attained complete understanding. It illustrates I've been overlooking the power of using ScriptableObjects, as opposed to singletons, in my work. I especially like your descriptions of what the 'wrong singleton alternatives' are - you perfectly pointed the path down which I went, not knowing what Unity was capable of.
Thank you for sharing this excellent work. I can tell you hid company secrets, as you hinted at in the demonstration - yet you pointed out all the salient points of ScriptableObjects quite well anyway. Replacing the GameEvent listener list with Delegates is an exercise to be done by the student, for extra credit. ;-)
This really is a great talk, as you pointed out, we have lots of info on how to accomplish very specific things in Unity, but I feel that design best practices / design patterns specifically within Unity is one of the areas I have the hardest time getting information about.
24:00 float reference abstraction - my god the sudden realisation that this is exactly what I was looking for. it's so elegant. THANK YOU
Can you please tell me the use for this, like what's the entire point of using floatvariable scriptable object & floatreference class?
@@herohiralal3255 i think this is what he said: You don't reference the "owner" at all to get the value because the SO holds the value. It's better and safer for designer because it gives them a GUI to create their own values with other SO features to help. Changes affect all scenes and any objects which rely on them(stops accidental prefab changes and is a form of serialization).
That's what I got.
This is pure gold, ten years working in Unity and I finally know this
"If (scene.menuname != menuscene)" is how I solved a problem in my game very recently. I had been pretty proud of myself for that. :(
@32:41 lmao he actually moved the background art thing up to perfectly not-cover the word "hookers." Obviously great presentation overall but I specifically appreciate the effort that went into this easter egg of a meme
good catch, hahah
haha yes he did, good catch :D
I started using these for pretty much everything. They solve pretty much every issue I typically have to deal with. I never wanted to use multiple scenes because it was a pain to serialize and deserialize data between scenes. Now it doesn’t matter. I can just drop in whatever I want without a care in the world.
I cant express how important the video is ... THis is one of the best video in UNITE, THE demonstrator is super knowledgeable and has shown powers of SOs, and is really good at demonstration. THank you very much
On reading unity forums and subreddit, I always find myself keep getting back to this video, kinda interesting
this talk alone its worth going to unite
Been doing Unity at home for a couple years now and always knew I should be using Enums. I used them for the first time last night, spent a bunch of time setting up a bunch of stuff using them ... then added a new one near the top of the list ... OMG !! ... it didn't keep the values I set where I used them !! ... well THATS good to know !! ... and here I am :)
This is very useful, its a shame there isn't people like him (that I'm aware of) making unity courses or books that go through how to apply this stuff in detail, I'd find it very useful to have a book/course that goes through how to apply this step by step rather than an overview.
I'm so glad someone directed me to this talk. Had no idea how powerful Scriptable Objects could be, and will definitely be watching the Richard Fine and The Hack Spectrum talks next. Thanks Ryan!
What an excellent, relatable and casual speaker this guy is. Great job, great subject! Thank you Ryan.
I agree, he was very easy to listen to, not condescending in the least, intelligent, articulate. I would like to see more game development topics presented by him.
I have just discovered this video and I have to say that it is amazing! For the first time, someone has explained me very well how ScriptableObjects can be used
While eye-opening, this presentation sent me down a two-day rabbit hole which consisted of me slamming headfirst into scripting mania and error headaches. Making float variables was the easy part. I can barely customize the editor to display them in the Inspector!
This is an amazing talk and it clearly outlines many patterns to make it easier for developers to crate games on solid games architecture
That was an amazing talk! We definitely need more architecture guidelines for Unity.
Awesome talk, thank you! I personally get rid of using Editor to set references as much as possible as it's really difficult yo find those references later or make sure Unity did not broke them for unknown reason at some point. Doing everything via code saved my life but I will give a try to use scriptable object based event system.
Does this guy have a book or a video series that he is selling somewhere ? Those architecture tips are golden, I would GLADLY pay for more.
i didn't know until now that scriptable objects are important for game architecture. I always wondered how Developers manage to do this in AAA Games. Really eye opening talk. Recommended Talk!!!!
This is fascinating. In a lot of ways, Unity and its particular setup seems to get in the way when you try to program from a typical perspective. I'm very new to it, so I'm not fully on board with its style of doing things yet.
You've created some very clever ways of doing things that embrace Unity's strengths and that's pretty awesome. This and Richard Fine's talk about ScriptableObject should be required viewing. Thank you very much! :-)
This was an incredibly useful speech that hit many issues that I struggled with. Virtually every point I have worked at some point but was unsatisfied with my solutions. After watching this it's time to take another whack at it. Thanks!
This is the best demonstration on how to use ScriptableObjects by far! Learned so much from it. Thanks fot that talk :-)
For anyone interested - we've just open-sourced our implementation of this concept, called SmartData. It's comprehensive, powerful, extensible, includes custom editors and even a live node-graph visualizer/debugger. github.com/sigtrapgames/SmartData
So gratifying when i see a system that resembles so closely a system i was already doing. Great talk!
This video is a classic! Thank you. I am watching it for the 3rd time and get something new out of it every time.
I'm a big fan of scriptable objects already. But I definitely had not thought about some of these use cases. Thank you so much! Great talk! :D
This is one of the best unity talks ever. Thank you very much.
Just awesome :) thanks a lot! Great pace, info and humour couldn't think of a nicer way to learn :)
Wish we had an example of that inventory system, saving/loading and resetting those scriptable objects must be quite tricky. Not sure if I want to attempt that myself yet.
So to make sure that I've got this architecture concept straight, I'd like to use scriptableobjects for my multiplayer game.
For this reason, I'd like the shared configuration of this type - things like Max Health etc., to be FloatVariable, IntVariable, and so on as required (Or simply - BaseConfiguration to hold all of them together, increased locality).
In order to let our UI bind itself to the player's data, I'd like to use FloatReference, IntReference, etc (Or simply - PawnStateReference - holds everything you intend other systems to interact with, leaving other fields as true private fields for encapsulation)
Then, the player our UI recognizes will have PawnStateReference hold the PawnStateVariable SO, and other clients of the exact same type/prefab will use the "constant" (isn't runtime a better name?) instead.
Simple, client and other players share the exact same components with the player having an additional Input script that handles converting the inputs to actions via client pawn.
UI only knows what our client pawn is doing extensibly, and if I'd like to add UI elements per every other player, I can use a RuntimeSet of all pawns in the scene and access the PawnStateReference from there, as it'll be public. I don't even need to add a messy "IsClient" boolean or whatever because I could just compare the PawnState reference with the one my UI recognizes.
Is this considered an attempt to overengineer scriptableobjects into my game or does this seem like proper usage of the proposed architecture?
Thanks.
Thank you for the re-upload! This is a great talk and the audio de-sync would've been a pain when I refer back to this while coding later.
this talk is amazing and has totally changed how i will approach setting up unity projects in the future!!
True, the FloatVariable scriptableobject thing blew my mind lol
So very helpful and eye opening! Thank you, Ryan and Unity!
Thanks for this great talk, especially for the demos and use cases presented; still very useful in 2018. :) And exactly what I was looking for, because as a Unity noob (but someone who understands SOLID programming in .Net) I had a lot of dilemmas about how to implement loosely coupled design in Unity, and most sources don't answer this at all. I also appreciate the critical tone towards some Unity characteristics, e.g. the curly brace placement and relying on magic strings.
So basically variables that may need to be shared between different "systems" could/should be individual SO's so it's easy to do so. That's pretty cool!
This is so fantastic, it leaves me speechless. A breathtaking talk. Thank you!
RuntimeSet {
List items
}
Why, god!?
(amazing presentation and content)
I'm a very new programmer. I started learning C# & Unity Development in late July of 2020 (it is late September 2020 as of writing this.)
This talk has helped me out so much, that I cannot even describe the sheer thankfulness, and happiness I have from it.
I'm currently at that point where I fully understand C# on a fundamental level. I'm familiar with the dynamic of value types & reference types on an intuitive level, and I am also familiar with all data types and how to properly implement them in accordance to eachother.
The problem I do have though- what is the most efficient manner to use all of these tools together, in order to create the cleanest, most efficient, and modular manner?
I really really like the system that he presented here, and I am going to be using it from here on out. This is a fantastic way to create systems that are decoupled from eachother. Utilizing the data types are the shared resource between different systems is a take that I have never even considered doing. I always thought that you HAD to reference system to one another, in order to create any sort of communicative functionality between said systems.
7 minutes in and love the talk already - great communication skills
I really like the modularity and designer-centric focus of this approach. I use Zenject now and like it, but it's often not quite as easy to pivot with zero programmer involvement.
VERY professional and well done talk. Thanks for the slides, blog and github code!
You rock man! An inspiring talk and presentation, think I can't go back to repeating ill practices after learning from this session.
I love that this person used the Pillars of Nosgoth as the image.
I tested it and combined it with pluggable approach. this architecture really challenges other architectures.
Authorable for non-coders and easy to maintain
Good lecture
Keeping the code clean is super important
This talk is amazing.
Best talk ever! Although, I can’t help but think that he looks like Dennis Reynolds in the thumbnail lol
I'm still loving it
Use it in every project :)
Thank you so much haha
Amazing talk. This will help me hugely. I was soo annoyed having to hard wire everything. Not anymore!
This is one of the most amazing talks I have seen.... Demonstrating stuff as you say about it... Yayyy to Scriptable objects.... Btw that we are not monsters line was XD
I like the idea of using an asset as a source of publicly communicating some data. It reminds me of a Unix Socket in the unix/linux world, a sort of public channel for reading/writing data.
Holy mother, this is what I've been looking for! Great talk!
this looks great and the talk is huge and very well done, It's just really hard for beginners to understand how to correctly implement them, or this is how I'm feeling
This is a brilliant approach- thank you for the talk and for the upload ^_^
Very nice presentation, thank you very much Ryan!
This talk, and the 2016 talk by Richard Fine are huge eye-openers, and greatly appreciated! I was wondering though: would it be a good idea to make the GameEvent and EventListener classes generic? That way, it can be parameterized for other generated UnityEvent types.
This is super nice talk. I've used this architecture in a couple of
games and found myself often re-writing the same boilerplate code (for
events), so I've found a really nice open-source library for it:
github(dot)com/chark/scriptable-events. I really recommend using it!
Great talk, web lacks architecture advice for Unity developers. I wonder how they handle version source control issues using this approach. There are many changes after each game start, so it should be some type of runtime folder that must be in .gitignore file. But in that case game either will not start right after clone game repository or scriptable objects should be created by themself.
Looks like great stuff but I failed to understand some details (I am a novice in Unity). I wish there were more examples and code, less common phrases. Could anyone explain how FloatReferences are supposed to be used when we have not a single player with specific HP, but a bunch of different instances of units with their own individual HPs (like in RTS)? Are these FloatReferences HP have to be created for each unit at runtime?
The same question is for Events: how it would be if an event could be raised by multiple sources (I don't want it to be received by all subscribers, but only those related to this specific source/instance)? Should we create a separate scriptable object for every event source?
Could anyone provide some links to more complicated examples?
I feel you man, I tried to replicate his examples in a little project having a player and multiple enemies. I tried using his UnitHealth and just putting it on the enemy but as you said it would reference the same health the player references. I'm now Instantiating the health SO at runtime but finding it difficult to get a reference for that from the health bar.
I would love for someone with experience to chime in with some wisdom.
I'm late but I would have the enemy have a MaxHealth FloatReference and a private float for currentHealth inside it that it tracks by itself. You only need to use this stuff for DI (Dependency Injection) anyway. Idk tho I've been a dirty Singleton user all my life so
If you are planning to have a constant number of human players in a given game session, ever say 4-8 then this approach would still work.
If you are referring to X number of dynamic enemies that could be more than the 10+ and that comes and go at any given time then I would avoid this approach as you’ll end up creating X number of HP instance per enemy, and that’s only HP we’re talking and not counting other properties.
However let’s say if each enemy had their own little HP UI above them, I suppose you could dynamically create an instance of the float variable with ScriptableObject.creatInstance() and wire that onto the enemy’s UI at runtime.
The guy in the video answers some of your concerns in a reply to a different comment here, posted by ReverendWolf, his name is Ryan.
Just tried the event system. Works great!
I use both, a singleton-scriptable-object. You can access it from every, without drag-n-drop the asset into the inspector everywhere.
You reintroduce the tight coupling problem that singletons bring though. And ScriptableObjects are accessible from everywhere anyway. They're assets, so you can reference them like any other asset from within another class as normal. Like referencing a texture or an icon.
Thank god he doesn't use a Mac. Don't know why that always bothers me so much. Also, funny how they think people won't notice he is using an MSI laptop.
Anywho, great talk. Definitely one of the most informative and insightful
Good Job.
This is a re-upload of a previous version of this video that had audio sync issues. They also could've been there in person or maybe they're even a co-worker or friend that helped edit or critique the presentation. Why would you put someone on blast just for saying, "Good Job"?
Wow. What a fantastic presentation!
also agree with most of the commenters, this vid sold me to scriptableobjects. I can honestly say, I've never used a singleton.
Great concepts here. Thanks for the talk
Really good and helpful talk!
43:47 when the camera man is sleeping :)
Didn't play that part, but I saw it in game review videos. ;)
Kain!
So I guess it is safe to say, and correct me if I am wrong, scriptable objects still rely on dependency. I can't imagine you can make a system without some kind of dependency. But the dependency is on the scriptable objects themselves. Makes sense.
This talk has helped me tremendously!
Thank you so much :)
An amazing talk. Thank you so much!
Hey Ryan, awesome talk, really gave some good insights! Could you tell me how you achieve the selection the way it is shown at 20:55 ?
Great talk! One downside that wasn't mentioned is that the event binding is only visible in the inspector, which makes this approach a little more unfriendly when viewing the source code outside of the Unity IDE.
Outstanding. Downside, I not have a lot to recode and reconsider.
He explained at 22:33 how his FloatVariable scriptable object could be used as a parameter in the animator but he never actually showed how to do it. How do you actually bind the two? Do you actually have to do somewhere in an 'Update' method a `animator.SetFloat(myFloatVariable)` to keep it in sync? What's the trick here?
You may have meant at 22:10? He says "I'd like to see" as it's not possible. One good spot for that `Update` would be a StateMachineBehaviour that has a field for a FloatVariable. This would allow syncing the animator parameter to match the FloatVariable only while in animator nodes that rely on that parameter for a transition.
This method requires that any consumers of a variable that are only concerned with changes in the value have to constantly poll the value and compare it to a previous state. This could have huge performance implications
Not if you make a variable object invoke a delegate on change! Some use cases benefit from checking every frame for data that changes a lot. Others can just get an event when it changes.
@@RyanHipple Yeah sure, you can alter what is shown in the video to do that.
Unity should be using these type of SO references for their color pallette swatches.
Very cool. Very enlightening. Thanks!
Great Subject - Awesome Talk .
Working with enums isn't an issue with serialization, because you ALWAYS define the value for the enum to avoid these issues. But if some loss of performance isn't an issue, one can use the alternative approaches instead.
Yeah, I wasn't entirely sure why they couldn't safely remove certain enum values without breaking things. The compiler should be telling where enums that no longer exist are being used through errors.
Awesome talk, I really like the floatReference idea, but there is something I struggle to understand. How can I use float reference for runtime instance of object? Like the buildings health in your RTS exemple. We can put all the SO in runtime sets or dictionnary but it seem to be a "hacky" solution. And I can't figure how runtime sets and events can resolve totally the need of singleton or static reference, if I want the room where the player is standing or if I want to call a function of my saveSystem with parameters the singleton seem to be better.
I'm asking myself the same question for runtime instance. Have you had an answer since then?
Correct, SO was never intended to be a one stop solution for all. Understanding and combining SO usage where appropriate along with singleton just gives you an upper hand when making decisions in architecture.
However, If you don’t want the singleton approach and want a more robust gameManager for larger scale games, then you can look into using a Dependency Injection framework.
You make a MonoBehaviour called Scope. Inside the Scope are dictionaries where SOs are keys. Values of the dictionaries can either be local copies of the SOs, real values (like float, bool, int, etc) for a little better performance an less memory, or a cacheable index of a list that has the real values for the best performance. Inside your other code, you call a method like Scope.GetFloat(SOFloat). Then, what GetFloat does is try to use SOFloat in a dictionary to get the value to return and, if it doesn't find it, an entry is created, initialized, and returned.
PD
For the cacheable index of a list. You'd cache the index inside a FloatReference instance, you'd pass that FloatReference to GetFloat instead of an SOFloat, and you only get the index from the dictionary if the SO referenced by FloatReference has changed or if it's being used with a new Scope. That way, getting the scoped value, most of the time, just means getting a value at an index from a list which can be a lot faster.
I'm a game artist looking at this guy's forehead and I think I just unlocked the ability to visualize better shading in my head now. Thankyou Ryan Hipple.
One more observation - the notion that DI is exactly what the inspector is for and that there's no need for DI frameworks like Zenject is only partially true imo. It would make more sense if:
A. Every single class in your project that requires dependencies is either a MonoBehaviour or a ScriptableObject
B. You don't use interfaces
However in reality, you would want to use basic C# classes and interfaces and you can't inject their dependencies via inspector. Zenject also has many useful features like binding factories and memory pools. I would advocate for a combination of the inspector and a DI framework.
Interfaces can still work with the inspector! You serialize a reference to the UnityEngine.Object and use validation (OnValidate, ISerializationCallbackReciever, CustomEditor, PropertyDrawer) to reject the Object if it does not implement the interface. Then on Initialization (or ISerializationCallbackReciever.OnAfterDeserialize) you can cast to your interface and store it.
It sounds very hacky. I'm sure there are many ways to make it work. You could also purchase Odin Inspector from the Asset Store and serialize pretty much anything. But even if point B wasn't valid, there's still point A. I'm of the opinion that you shouldn't pollute scenes with objects that aren't 'actual things' in the scene, but are just there to run MonoBehaviours. The point is that the inspector cannot fully replace a DI framework.
Great stuff :)
Great talk, Ryan!
To be honest I clicked for the Firefly in the thumbnail
me to.
Sad they aren't making a Firefly game!
Jesus! This stuff is fucking golden!
Any thoughts on how to pass a variable(s) with the GameEvent? GameEvent like Event
Did you figure out a solution?
Great talk, Ryan!
You mention that the demo version of StringReference is a lot simpler than the one you use in production. I have been working on a very similar concept that is generic and free to use. I created a forum post for this, as well. As of yet, no one seems interested, so I would love some feedback from you (or anyone for that matter)!
For anyone else interested in this, head to the forums to share your thoughts and questions. Or, better yet, start to contribute on the BitBucket repository!
BitBucket Link: bitbucket.org/nobrainerinteractive/referenceablevalue
Unity Forum Post: forum.unity.com/threads/referenceablevalue.505389/
Cheers,
David
Really wish he had gone into the inventory system example...