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(); } } }
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.
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.
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
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!
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 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
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.
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
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!
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 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.
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.
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!
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
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 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 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! :-)
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.
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!!!!
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.
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'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
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
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!
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.
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 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.
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.
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!
At 36:43, the raise button there on Ryan's screen below GameEvent, that raise button is not there on my unity screen? Can someone tell me how to enable it? I have created an almost exact demo which works exactly the same. Yet, the raise button isnt there. I am using unity 2020.3.
Hello Unity channel! Is it possible to make such sceens, as goes on 25:00 minute on full size? I'm sympathize to the presenter, but work with editor more important for me.
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.
With the runtime set list, can you not reference objects that you instantiate and destroy at runtime? I get a type mismatch when i attempt to do so. I made a serializable class to hold the list and put the class on a gameobject and it worked. but that kinda defeats the purpose
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"?
Hello, Silly question but I'm a bit of a beginner and I don't speak English so I probably missed some things. 24:39 How does the sphereOffPain change the HP value of the player when there is no reference to the ScriptableObject HP in the Damage Dealer script and there seems to be no event?
The sphere script has an onCollision or onTriggerEnter or onTriggerStay Method which are built in methods from unity. with those you can get a reference to the object that created the collision. With that you can get a reference to the health script of the unit and reduce its health value.
Could someone explain me the "Scenes as clean slates"? Timestamp: 3:27 1) No transient data between scenes, so does this mean that there should be no data (which lasts for a very short time) going from the current scene to the next scene? What kind of data that could be? 2) DontDestroyOnLoad()? Why? If we are making the scene clean, DontDestroyOnLoad() will make the scene intact so how will it be clean? I'm a beginner so excuse me if it was a dumb question.
I don't think it's dumb. 1) I believe he refers to scenes being dependant on stuff created by other scenes. This is common when doing singletons; they are usually created by first scene that needs them. It can create chaos because, in order to be able to test a feature separately, you need to be able to generate its dependencies from many different places, only if they're needed; this is prone to bugs because it's easy to miss a case, specially in long dependency chains. I'd add that, ironically, interscene dependencies get more chaotic when they aren't singletons, 'cause they usually need some kind of manager singleton to handle the life time of each object. Scriptable Object assets are created by you on the file system. You can easily add any amount of them that you need, and you assign them as dependencies directly in the inspector. This removes a lot of the work and the risk of creating and assigning dependencies at runtime for each different case. You can easily test features because you can assign the exact dependencies your test needs with a few clicks in the editor. Even automated tests are easier because they can just create the SO instances they need, which is easier than creating GameObjects and filling them with components, specially if they are singletons or they have a lifetime management system. 2) Well I guess it's because we don't usually think of ScriptableObjects as part of the scene, specially when they are stored in assets. Internally, Unity does treat them as part of the scene in some regards; it removes them if nothing in the next scene loaded uses them. The next time they are loaded at runtime, they won't have any changes that were done to them. DontDestroyOnLoad and DontUnloadUnusedAssets prevent that.
@@MaharbaRacsoChannel Thank You So Much! I understand little bit better now and probably understand much better when I will start working with Scriptable Objects. God Bless) ✨
@@nmcnemis Hey, no problem. Glad to help. I bet you're right; I'm sure you'll feel a lot more sure of your insights when you start trying to use them. It's been like that for me.
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.
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 have some strong doubts about this: - How do you manage execution order? Let's say, when my player dies, I want some object to react first, then other objects. - Your whole code is tied to the Unity engine, which means it's a lot harder, if not impossible, to switch to another engine that does not function the same way. In my opinion, you should only use Unity as a view, and have all of your code logic and data somewhere else. - How do you manage large number of entities? As far as I know, Unity Objects can only be accessed on the main thread, and Unity Events generate quite a lot of garbage when you have big amount of entities. - You're basically writing something quite similar to visual scripting, except you don't have the benefits of visual scripting, with the nice flow visualization and debug options. - How do you quickly edit data, when it's all over the place in many different scriptables? You have to create a huge editor window to edit everything? - When in a smaller team, if you don't have a real QA department, how do you do code reviews? I tend to think the other way around, anything that is pure code can be easily reviewed, while scenes, gameobjects and components are quite annoying to track. However, I have to admit there's a lot of advantages as well, especially that system dependency thing which seems quite nice to work with.
I can't answer these in depth, but one thing I have found that works very well is implementing interfaces in your core codebase with scriptableobjects. This way, you aren't inherently tied to Unity for obvious reasons and can still get all the benefits of using scriptable objects. I do the same thing with monobehaviours as well.
It's certainly an interesting approach and it plays to the strength of using Unity as a tool for building the game in-engine versus in your IDE. You pointed out some valid criticisms, I think it really depends on what the team needs designers to do and what the artist/designer/programmer ratio is.
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
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.
how does the player hp setup extend to enemies? does each enemy get a SO of it's own for their current hp or do you keep it stored locally in a variable in their prefab?
The simplified form of the variables that I presented would probably not be the best choice for use on a variable amount of enemies. Alterations on the concept can be made to work for that, though. You could have the variable be instead backed by a list or dictionary so that you can say "give me the hp for enemy x". You could also use a different pattern for things like that. The VariableSets approach I mention could make it easy to track a list of objects and you could have each own own its own state.
Yeah, after watching this I found the concept cool and very usable, on smallish projects. This issue is something that bothered me and I can find a perfect solution for that, which is a shame, since I really like the concept.
It is never a good idea to take a concept and force it to be the solution to all problems (like I often see with singletons). The variable system is really good at tracking and responding to a high level state. This does not really make sense for HP on a bunch of enemies. I would place the enemies in a runtime set and have a different system scan through that to manage enemies. The dynamic variables have worked really well on large projects managing things like player state, configuration settings, quest state and other high level concepts.
I agree I think I explained myself wrong, I am not saying that this system is THE SYSTEM to fix everything, I was trying to convey that I haven't found a good way to implement multiple variables =). Also, amazing talk Ryan! Thank you for that =)
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.
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.
I don't quite see how scriptable objects can be useful for an inventory. Unity docs state that you can't change scriptable objects at runtime on a deployable build. But we do want to change inventory at runtime, so... Does anybody know what I am not getting here?
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!
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.
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
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
Without a doubt the most mind blowing Unity talk ever. Excellent speaker.
he is rather good, I have to say
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!
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.
@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
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. :(
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
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.
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
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!
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.
That was an amazing talk! We definitely need more architecture guidelines for Unity.
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.
On reading unity forums and subreddit, I always find myself keep getting back to this video, kinda interesting
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.
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.
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 one of the best unity talks ever. Thank you very much.
This is the best demonstration on how to use ScriptableObjects by far! Learned so much from it. Thanks fot that talk :-)
this talk alone its worth going to unite
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 an amazing talk and it clearly outlines many patterns to make it easier for developers to crate games on solid games architecture
Just awesome :) thanks a lot! Great pace, info and humour couldn't think of a nicer way to learn :)
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
This is so fantastic, it leaves me speechless. A breathtaking talk. Thank you!
So very helpful and eye opening! Thank you, Ryan and Unity!
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 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 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 video is a classic! Thank you. I am watching it for the 3rd time and get something new out of it every time.
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.
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.
7 minutes in and love the talk already - great communication skills
VERY professional and well done talk. Thanks for the slides, blog and github code!
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!!!!
You rock man! An inspiring talk and presentation, think I can't go back to repeating ill practices after learning from this session.
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 gratifying when i see a system that resembles so closely a system i was already doing. Great talk!
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
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'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.
RuntimeSet {
List items
}
Why, god!?
(amazing presentation and content)
I'm still loving it
Use it in every project :)
Thank you so much haha
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.
Holy mother, this is what I've been looking for! Great talk!
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
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
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 a brilliant approach- thank you for the talk and for the upload ^_^
Best talk ever! Although, I can’t help but think that he looks like Dennis Reynolds in the thumbnail lol
Amazing talk. This will help me hugely. I was soo annoyed having to hard wire everything. Not anymore!
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.
I love that this person used the Pillars of Nosgoth as the image.
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.
Very nice presentation, thank you very much Ryan!
This talk has helped me tremendously!
Thank you so much :)
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.
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!
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 ?
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 concepts here. Thanks for the talk
At 36:43, the raise button there on Ryan's screen below GameEvent, that raise button is not there on my unity screen? Can someone tell me how to enable it? I have created an almost exact demo which works exactly the same. Yet, the raise button isnt there. I am using unity 2020.3.
Hello Unity channel!
Is it possible to make such sceens, as goes on 25:00 minute on full size? I'm sympathize to the presenter, but work with editor more important for me.
The slides and demo are all online: github.com/roboryantron/Unite2017
Cheers Chase!
Wow. What a fantastic presentation!
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.
An amazing talk. Thank you so much!
Sample project's link, there is missing files? Video shows there is Demo07-inventory, but at link, there is none.
With the runtime set list, can you not reference objects that you instantiate and destroy at runtime? I get a type mismatch when i attempt to do so. I made a serializable class to hold the list and put the class on a gameobject and it worked. but that kinda defeats the purpose
That type mismatch is just an editor display quirk, the data is still in tact. You can make a custom editor to get it to draw correctly.
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"?
Really good and helpful talk!
43:47 when the camera man is sleeping :)
Hello,
Silly question but I'm a bit of a beginner and I don't speak English so I probably missed some things.
24:39
How does the sphereOffPain change the HP value of the player when there is no reference to the ScriptableObject HP in the Damage Dealer script and there seems to be no event?
The sphere script has an onCollision or onTriggerEnter or onTriggerStay Method which are built in methods from unity. with those you can get a reference to the object that created the collision. With that you can get a reference to the health script of the unit and reduce its health value.
Could someone explain me the "Scenes as clean slates"? Timestamp: 3:27
1) No transient data between scenes, so does this mean that there should be no data (which lasts for a very short time) going from the current scene to the next scene? What kind of data that could be?
2) DontDestroyOnLoad()? Why? If we are making the scene clean, DontDestroyOnLoad() will make the scene intact so how will it be clean?
I'm a beginner so excuse me if it was a dumb question.
I don't think it's dumb.
1) I believe he refers to scenes being dependant on stuff created by other scenes. This is common when doing singletons; they are usually created by first scene that needs them. It can create chaos because, in order to be able to test a feature separately, you need to be able to generate its dependencies from many different places, only if they're needed; this is prone to bugs because it's easy to miss a case, specially in long dependency chains. I'd add that, ironically, interscene dependencies get more chaotic when they aren't singletons, 'cause they usually need some kind of manager singleton to handle the life time of each object.
Scriptable Object assets are created by you on the file system. You can easily add any amount of them that you need, and you assign them as dependencies directly in the inspector. This removes a lot of the work and the risk of creating and assigning dependencies at runtime for each different case. You can easily test features because you can assign the exact dependencies your test needs with a few clicks in the editor. Even automated tests are easier because they can just create the SO instances they need, which is easier than creating GameObjects and filling them with components, specially if they are singletons or they have a lifetime management system.
2) Well I guess it's because we don't usually think of ScriptableObjects as part of the scene, specially when they are stored in assets. Internally, Unity does treat them as part of the scene in some regards; it removes them if nothing in the next scene loaded uses them. The next time they are loaded at runtime, they won't have any changes that were done to them. DontDestroyOnLoad and DontUnloadUnusedAssets prevent that.
@@MaharbaRacsoChannel Thank You So Much! I understand little bit better now and probably understand much better when I will start working with Scriptable Objects.
God Bless) ✨
@@nmcnemis Hey, no problem. Glad to help. I bet you're right; I'm sure you'll feel a lot more sure of your insights when you start trying to use them. It's been like that for me.
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.
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 have some strong doubts about this:
- How do you manage execution order? Let's say, when my player dies, I want some object to react first, then other objects.
- Your whole code is tied to the Unity engine, which means it's a lot harder, if not impossible, to switch to another engine that does not function the same way. In my opinion, you should only use Unity as a view, and have all of your code logic and data somewhere else.
- How do you manage large number of entities? As far as I know, Unity Objects can only be accessed on the main thread, and Unity Events generate quite a lot of garbage when you have big amount of entities.
- You're basically writing something quite similar to visual scripting, except you don't have the benefits of visual scripting, with the nice flow visualization and debug options.
- How do you quickly edit data, when it's all over the place in many different scriptables? You have to create a huge editor window to edit everything?
- When in a smaller team, if you don't have a real QA department, how do you do code reviews? I tend to think the other way around, anything that is pure code can be easily reviewed, while scenes, gameobjects and components are quite annoying to track.
However, I have to admit there's a lot of advantages as well, especially that system dependency thing which seems quite nice to work with.
I can't answer these in depth, but one thing I have found that works very well is implementing interfaces in your core codebase with scriptableobjects. This way, you aren't inherently tied to Unity for obvious reasons and can still get all the benefits of using scriptable objects. I do the same thing with monobehaviours as well.
It's certainly an interesting approach and it plays to the strength of using Unity as a tool for building the game in-engine versus in your IDE.
You pointed out some valid criticisms, I think it really depends on what the team needs designers to do and what the artist/designer/programmer ratio is.
Outstanding. Downside, I not have a lot to recode and reconsider.
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
Wondering how you go about passing different kind of values alongside events. Events without any args seem not that useful.
Great Subject - Awesome Talk .
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.
how does the player hp setup extend to enemies? does each enemy get a SO of it's own for their current hp or do you keep it stored locally in a variable in their prefab?
The simplified form of the variables that I presented would probably not be the best choice for use on a variable amount of enemies. Alterations on the concept can be made to work for that, though. You could have the variable be instead backed by a list or dictionary so that you can say "give me the hp for enemy x". You could also use a different pattern for things like that. The VariableSets approach I mention could make it easy to track a list of objects and you could have each own own its own state.
Yeah, after watching this I found the concept cool and very usable, on smallish projects. This issue is something that bothered me and I can find a perfect solution for that, which is a shame, since I really like the concept.
It is never a good idea to take a concept and force it to be the solution to all problems (like I often see with singletons).
The variable system is really good at tracking and responding to a high level state. This does not really make sense for HP on a bunch of enemies. I would place the enemies in a runtime set and have a different system scan through that to manage enemies. The dynamic variables have worked really well on large projects managing things like player state, configuration settings, quest state and other high level concepts.
I agree I think I explained myself wrong, I am not saying that this system is THE SYSTEM to fix everything, I was trying to convey that I haven't found a good way to implement multiple variables =).
Also, amazing talk Ryan! Thank you for that =)
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.
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.
Didn't play that part, but I saw it in game review videos. ;)
Kain!
Any thoughts on how to pass a variable(s) with the GameEvent? GameEvent like Event
Did you figure out a solution?
Very cool. Very enlightening. Thanks!
I don't quite see how scriptable objects can be useful for an inventory. Unity docs state that you can't change scriptable objects at runtime on a deployable build. But we do want to change inventory at runtime, so... Does anybody know what I am not getting here?
Great talk, Ryan!