Better Save/Load using Data Binding in Unity

  Рет қаралды 9,317

git-amend

git-amend

Күн бұрын

Data Binding in Unity can speed up your save times tremendously by keeping the persistent state of the game ready to save at a moments notice. Data binding is a fast and efficient way to save data quickly at runtime, and can help improve your data modelling. Let's build a Save/Load system to see this in practice.
NOTES: If using the SerializableGuid from the repo, don't forget the PropertyDrawer!
Support for saving Scriptable Object references using SerializableGuid has been added to the repository - feel free to check that out as well as several additional Serializable Types.
🔔 Subscribe for more Unity Tutorials / @git-amend
Discord: / discord
#unity3d #gamedev #indiedev
▬ Contents of this video ▬▬▬▬▬▬▬▬▬▬
0:00 Overview
1:15 Save/Load System
8:15 Binding
Source code: github.com/adammyhre/Unity-In...
Assets Shown In This Video (Affiliate Links)
Cartoon Fantasy UI: assetstore.unity.com/packages...
Eole Foliage Shader: assetstore.unity.com/packages...
Dungeon Mason Tiny Hero Duo: (FREE): assetstore.unity.com/packages...
Kronnect Beautify: assetstore.unity.com/packages...
Slate Cinematic Sequencer: assetstore.unity.com/packages...
Protofactor Animals: assetstore.unity.com/packages...
Follow me!
linktr.ee/gitamend

Пікірлер: 100
@git-amend
@git-amend 3 ай бұрын
Hi everyone! Happy Sunday! Most of the time I prefer to bind my save/load data instead of wasting time trying to find all the savable objects when I need them. Let me know how you approach data persitence in your games! I've added support for saving Scriptable Object references to the repository as well (was not covered in the video).
@johanlindberg628
@johanlindberg628 3 ай бұрын
Seriously, you keep producing the most high quality Unity content KZbin has ever seen. :) As a Software Developer doing gamdev as a hobby I appreciate this approach to gamedev.
@git-amend
@git-amend 3 ай бұрын
Thanks for the comment! Lots more to come!
@jacobs.7925
@jacobs.7925 3 ай бұрын
Agreed 100%. This content is insane, it's above the level of most paid courses as well, I still can't believe we get something this good on youtube. Git-amend is a true hero.
@DadMakesGamez
@DadMakesGamez 3 ай бұрын
same here :)
@martinleissler8329
@martinleissler8329 3 ай бұрын
I, for one, welcome our new Unity tutorial overlords.
@simonnordon8421
@simonnordon8421 3 ай бұрын
So far it's the only unity dev channel that actually codes properly. The last was infallable code but they stoped posting.
@qwetzq9757
@qwetzq9757 3 ай бұрын
This is ABSOLUTE expertise and professionalism
@git-amend
@git-amend 3 ай бұрын
Too kind!
@renegaderaid
@renegaderaid 2 ай бұрын
Incredibly informative to see how to properly set something like this up. I can’t wait to watch the rest of your videos. Thank you!
@git-amend
@git-amend 2 ай бұрын
Awesome, thank you!
@KuroUsagi1010
@KuroUsagi1010 3 ай бұрын
I hope you get more exposure. your videos are really good!
@git-amend
@git-amend 3 ай бұрын
Thank you so much!
@rashadsworld_
@rashadsworld_ 3 ай бұрын
I really appreciate the consistent high quality content. You’ve inspired me to start learning game architecture. Do you have any videos where you talk about your journey of becoming a senior engineer?
@git-amend
@git-amend 3 ай бұрын
I don't yet, but that is a very requested video. Sometime this year I will make a video like that. Thanks!
@madpelican9242
@madpelican9242 29 күн бұрын
Great tutorial! Thanks! I definitely learned few new tricks. I spend some time messing with the system, but there is one thing that's kept bugging me out. Pun unintended. When we call "Bind" method of the SaveLoadSystem class, we passing there some TData that contains within GameData class. In Bind method we checking if TData null. And if it is, we create new TData. But it seems like this null check is rather pointless because GameData class won't reference this new instance of TData created by "Bind" method. Only object with IBind interface will receive it. In this case that, pretty much, will break the whole thing. GameData won't receive any changes that happened on IBind object. Of course this won't happen when all TData in the GameData class created in inspector. Since both TData and GameData marked as SerializeField. But then it means that this null check will never happen. And i can't quite figure out why then this check needed? Am i missing something important here? I stepped on this rake because decided to use SerializeReference instead of SerializeField. In my case that was necessary to make sure that GameData is created and managed only in runtime.
@jacobs.7925
@jacobs.7925 3 ай бұрын
Nice!! Was just about to purchase a save/load asset - gonna watch this first so I can decide whether it's viable/worth it to make one by myself. Thanks!!
@git-amend
@git-amend 3 ай бұрын
Great! Some of the paid Assets are very good, let me know if you buy one!
@radiantgames55
@radiantgames55 3 ай бұрын
Really high quality content!!
@git-amend
@git-amend 3 ай бұрын
Thanks!
@Niural
@Niural 2 ай бұрын
Every single video is top tier. Thank you for these amazing videos. I hope you can make enough money from pure teaching. I would genuinely love to learn from you. I think teaching is the most respectable thing a human being can do for others so others can take it, add on top of it and pass it to the future for common knowledge and progress of whole humanity. We wouldn't be here if some people who figured how some things work kept this knowledge for themselves instead of taking time to share this knowledge to others. Cause most people do keep it for themselves and that knowledge dies when they die. Imagine every generation has to reinvent electricity and computers from scratch. So thank you for doing this and i hope you can keep doing this.
@git-amend
@git-amend 2 ай бұрын
Thanks so much! I really appreciate the comment.
@nc956
@nc956 2 ай бұрын
My friend - keep it up. I'm not the best in this "Software development" thing but I can clearly see what an ocean of difference your vids make. I've always wanted to decouple my code (Which you cover in a different vid) and I didn't know how. It seems so daunting and crazy - those abstractions - but I have some hope for it now.
@git-amend
@git-amend 2 ай бұрын
Thanks, will do! Appreciate the comment!
@cileth
@cileth 3 ай бұрын
Every tutorial video is a banger! Love getting these senior dev insights with systems that make sense and are expandable. It would be interesting to see how you would write automated tests for a system like this. It's very rare to find quality content like this :) do you have a patreon?
@git-amend
@git-amend 3 ай бұрын
Thanks for the comment! I do not have a patreon right now - not enough time to create bonus content for the members!
@mracipayam
@mracipayam 3 ай бұрын
Who would buy if git amend make a premium course ? Me first.
@git-amend
@git-amend 3 ай бұрын
Thanks for the vote of confidence!
@martin.m.kloeckener
@martin.m.kloeckener 3 ай бұрын
Great tutorial! How do you handle versioning? What if GameData changes in a new version of the game? The Serializer will fail to read an old save file. For bigger, breaking changes this is of course fine, but for smaller adjustments I don't want my players to lose all progress due to a small addition of one persistent value.
@git-amend
@git-amend 3 ай бұрын
Thanks for the comment! I'm sure other people will have similar questions. First of all, make sure to start adding a version number as soon as you think you are going to have to maintain multiple versions of saved data - some kind of id system, even if it's just an integer. After that, the easiest thing to do is to implement a migration strategy. When you deserialize using Unity's Json library, missing fields in your saved data (the new fields in the GameData class) are set to the default values. Check the version number and then handle migration if you need to set those new fields to something special.
@martin.m.kloeckener
@martin.m.kloeckener 3 ай бұрын
@@git-amend Thanks for your answer, that's helpful!
@metaling278
@metaling278 2 ай бұрын
for those unable to get the init keyword to compile. There's a bug in visual studio 2019 where you have to make a dummy class for it to compile namespace System.Runtime.CompilerServices { internal static class IsExternalInit {} }
@git-amend
@git-amend 2 ай бұрын
Interesting, thanks for sharing that.
@toastyshrimp1882
@toastyshrimp1882 3 ай бұрын
not sure if you've mentioned this elsewhere, what is that drawing software you're using to visualize architecture?
@git-amend
@git-amend 3 ай бұрын
That's Excalidraw for Obsidian. You can also use the web version: excalidraw.com/ kzbin.info/www/bejne/pWHIqX5jrauDac0
@techdave99
@techdave99 3 ай бұрын
He has tried a few in the past. I don't know which one he is using here. Might be listed in the Discord.
@dreamcodestudio
@dreamcodestudio 2 ай бұрын
thx
@atherissquamigera7425
@atherissquamigera7425 3 ай бұрын
Hello sir. Thanks for the nice tutorial. I have a question. How did you create that custom editor for the Transform component? Is it a package?
@git-amend
@git-amend 3 ай бұрын
That's called Better Transform by Tiny Giant Studio, they also have an improvement for the Mesh Renderer component as well: assetstore.unity.com/packages/tools/utilities/better-transform-real-size-global-local-switch-and-child-parent--258314
@atherissquamigera7425
@atherissquamigera7425 3 ай бұрын
Thank you so much
@simonnordon8421
@simonnordon8421 3 ай бұрын
What are the pros and cons of saving as a single json dump versus having multiple files for each of your game data? Feels like having inventory, player and game data separate would be more scalable and more resistant to file save corruption.
@git-amend
@git-amend 3 ай бұрын
That's an interesting question. I would imagine the main pro of one file is simplicity. There would also only be only one read or write operation performed, which might be an advantage in some scenarios. The flip side of course are advantages you've already pointed out, and beyond that you might want to be able to save data more frequently for some game objects than for others, depending on your game. I think it really comes down to a per project level, but definitely something to consider.
@bane9109
@bane9109 2 ай бұрын
I really love your videos! I have a question: how would you save and prevent loading something that's already been destroyed in the scene, such as an enemy that was killed? Currently, when I stop and start the editor and load the game, the dead enemies are back to their last saved positions.
@git-amend
@git-amend 2 ай бұрын
Well, that's a difficult question to answer without seeing your entire project. If you are following along with the video, you'll notice there is a Bind method that can handle Lists of things for saving, and that could include a list of Enemies and their positions. You would need to tie this into your spawning system, so that as you spawn enemies into (and out of) your game you keep this list up to date. Then when the game is saved you should be able to save a list of all the enemy positions on the level and when the game starts up your spawning system can put them back into the right places, potentially with all the same data. You would do the same thing for items and so on.
@bane9109
@bane9109 2 ай бұрын
I see, I'll try that out! Thanks for the feedback, I think this is the answer I'm looking for!
@jeidoz
@jeidoz 29 күн бұрын
Great video tutorial, but I want to ask a question about future possible multi line Bind method calls in SaveLoadSystem.OnSceneLoaded. Could we instead try to create a public events like "OnLoad" and "OnSave" and just let each ISaveable class to react and write/read his own data part when event is dispatched?
@git-amend
@git-amend 29 күн бұрын
You could do that, but it would defeat the purpose of binding data as shown in this video. Most naïve systems do exactly what you are describing - the trade off is that you then have to have each of these ISaveable classes register and deregister for events and implement their own save/load logic which could become cumbersome. You then have to decide if you want each entity to save into it's own data file or combine them all somehow.
@Briezar
@Briezar 3 ай бұрын
may I ask about the other use cases of the SerializableGuid class? I can infer its use to compare objects by Guid and to load all resources to an int lookup table, but I feel like it shouldn't need to be this complicated if it does not have more uses. If the item map gets big enough for lookups to be slow, then I probably need to load less instead of using ints. Resources.Load also caches the first call so the next calls are faster until you release them, so I would prefer to call it once for initialization then keep calling it instead of storing it in an extra dictionary. If performance is still an issue, I'd prefer to cache the resource on the using classes instead of a central data map. I also don't think guid comparisons are gonna be used a lot. What are your thoughts?
@Briezar
@Briezar 3 ай бұрын
great video btw! Another immediate watch for me.
@git-amend
@git-amend 3 ай бұрын
Thanks for the comment! The SerializableGuid class is just an example of how you can serialize a Guid. I personally don't find it to be complicated, but of course you should implement whatever identification system is suitable for you and your project. As for optimizations of loading resources and so on, those are important things, but they are topics for another video. I wouldn't typically use Resources.Load, however I knew that if I did not add something to the repository, people would complain. We'll have a video about Asset Bundles and Addressables in the near future, and address some of these concerns about loading and memory. Cheers!
@damonfedorick
@damonfedorick 3 ай бұрын
Nice.
@git-amend
@git-amend 3 ай бұрын
Thank you! Cheers!
@CharlieClark-ns3qr
@CharlieClark-ns3qr Ай бұрын
How would you recommend I use this to save data for multiple levels? For example if I have 8 levels and I want to save the highscore for each, how many stars the player has, what levels still need to be unlocked, etc. I was thinking of using a dictionary but I'm not sure how that would work using the data binding system.
@git-amend
@git-amend Ай бұрын
For more complex types that aren't supported out of the box with Unity's built in tools, most people will use the Newtonsoft-JSON package. Check it out here: docs.unity3d.com/Packages/com.unity.nuget.newtonsoft-json@3.0/manual/index.html Specific Dictionary example: www.newtonsoft.com/json/help/html/SerializeDictionary.htm
@CharlieClark-ns3qr
@CharlieClark-ns3qr Ай бұрын
@@git-amend Awesome thank you so much for the reply, I appreciate it.
@pietro0games
@pietro0games 20 күн бұрын
Something I couldnt get in the video: Ok, you save an ID for the items, but how do you load the Scriptable objects based on the ID? Do you have an instance of a list that has all the items of the game and then you search the id inside this list?
@git-amend
@git-amend 20 күн бұрын
If you take a look in the repository, there is an extra commit made after this video's code that adds support for scriptable objects save/load. It is fairly straight forward.
@Tofkaai
@Tofkaai 3 ай бұрын
Is it safe to persist the instance ID of the scriptable objects for items? Are they not liable to change?
@git-amend
@git-amend 3 ай бұрын
Instance Ids are liable to change. The system can be improved by using the SerializeableGuid of each asset instead. I've added another commit to the repository to show how that can be done.
@ZombieChicken-X
@ZombieChicken-X 2 ай бұрын
How do I need to change the structure of this when there are multiple inventories? This implementation only lets me register a type once, say its like minecraft and theres hundreds of chests all with their own inventory data structure, should I just make the thing thats being saved a collection of InventoryData or is there a better solution?
@git-amend
@git-amend 2 ай бұрын
In that case you might want to start using the Bind(List datas) method so that you can associate each unique Inventory with a matching Id (the Id denoting the owner of the Inventory).
@ZombieChicken-X
@ZombieChicken-X 2 ай бұрын
so itd be like Bind ?@@git-amend
@pebandit1
@pebandit1 3 ай бұрын
Would it be possible to have many different GameData instances to save some content in different files ?
@git-amend
@git-amend 3 ай бұрын
Sure, you don't have to wrap any of the data in the GameData object - it could all be separate if you wanted to. The main wrapper is more of a convenience object, and would make it a bit easier if you needed to start versioning for example.
@pebandit1
@pebandit1 3 ай бұрын
@@git-amend Thank you !! Great video btw
7 күн бұрын
This might be my only hope for making a save system like Half-Life
@git-amend
@git-amend 7 күн бұрын
Great, I hope it inspires you to build something awesome!
@whyv9338
@whyv9338 3 ай бұрын
What's the name of the program used to make the diagrams? It looks really clean and simple.
@git-amend
@git-amend 3 ай бұрын
That's Excalidraw for Obsidian. You can also use the web version: excalidraw.com/ kzbin.info/www/bejne/pWHIqX5jrauDac0
@whyv9338
@whyv9338 3 ай бұрын
@@git-amend Thank you!
@GarT.
@GarT. 2 ай бұрын
@@git-amendThanks a lot!
@rofu8096
@rofu8096 3 ай бұрын
Can you make a video about Audio System for next week?
@rofu8096
@rofu8096 3 ай бұрын
By the way, this week's topic is very interesting as always. Thank you very much for making videos with such high quality content.
@git-amend
@git-amend 3 ай бұрын
I have another plan already for next week - but a video about an audio system would be a good topic. What kind of features would you want to include in such a system?
@rofu8096
@rofu8096 3 ай бұрын
@@git-amend I feel like I don't pay enough attention to sound in the games I make. In the last game I made, I tried to do something by combining your flyweight factory with the audio system, but I messed up. It would be perfect if you made a sound system video where we can use Audio Sources in a more optimized way.
@cileth
@cileth 3 ай бұрын
@@git-amend Would be neat to see how to get unity setup with fmod or wwise if you've ever used those. From a feature standpoint...general system setup, playing one off sounds, playing looping sounds, spatial audio relative to player. Basic music stuff could be cool too like a system to manage current song, transitioning, looping. I know fmod has some variable connections to control multi channel audio stuff and apply audio effects and filters (like different reverb values depending on indoor/outdoor for example).
@jcx5750
@jcx5750 Ай бұрын
what is that flow diagram you are using sir
@git-amend
@git-amend Ай бұрын
That is ExcaliDraw for ObsidianØ kzbin.info/www/bejne/pWHIqX5jrauDac0
@Nytrock
@Nytrock Ай бұрын
Greetings! Is there a way to somehow encrypt the file so that a dishonest player can't just find it, open it, and give himself 999 mushrooms?
@git-amend
@git-amend Ай бұрын
Sure! Unity supports Base64 out-of-the-box - check out the end of this article for how to use it: pudding-entertainment.medium.com/unity-how-to-save-and-load-files-using-json-and-base64-a033def09a47
@publicmmi
@publicmmi 3 ай бұрын
Your method to save the inventory (using instanceID) will not work outside the editor. Even if you save and reload the unity editor and load it won't work. One way is to use sort of database holding the item prefabs ids
@git-amend
@git-amend 3 ай бұрын
Very astute. As mentioned in the pinned comment and description, you can see an implementation in the repository.
@publicmmi
@publicmmi 3 ай бұрын
@@git-amend Thx, i will look into it. What you also need to implement is deleting objects from scene after loading if they were deleted before. What i do in my system is, after loading, delete everything which saveable in the scene and create everything from the save file.
@nanaschi
@nanaschi 2 ай бұрын
Sadly for me the property [field: SerializeField] public SerializableGuid Id { get; set; } = SerializableGuid.NewGuid(); and [field: SerializeField] public SerializableGuid Id { get; set; } do not serialize. I'm using latest unity version and still investigating the issue but for now it does not work for me 2022.3.16
@git-amend
@git-amend 2 ай бұрын
Are you using the PropertyDrawer from the repository?
@nanaschi
@nanaschi 2 ай бұрын
@@git-amend thanks for the quick reply. Indeed, it seems the issue was with the SerializableGuidDrawer class to showcase it properly. I'll continue testing your approach. Just cloning the repo itself is not possible since it has dependencies and missing entities. But for now all good :)
@nanaschi
@nanaschi 2 ай бұрын
​@@git-amend I encountered another problem (just for me I hope). When I start playing it goes to the default persistent property state. I did everything as in the tutorial of yours (This is my hero): public void Bind(PlayerData data) { _playerData = data; _playerData.Id = Id; transform.position = data.Position; } private void Update() { _playerData.Position = transform.position; } And it goes always transform.position = data.Position; (in your video it does not for some reason) but I wanna it to happen only on load. If I fix I'll let you know. P.S. Long story short on each play it goes to default position of the data I store in GameData The way I had to do it is the following but you in your videos did not have this check and I can not wrap my head around why: public void Bind(PlayerData data) { _playerData = data; _playerData.Id = Id; // Check if the loaded position is not the default Vector3(0,0,0) or any other invalid position if (_playerData.Position != Vector3.zero) { transform.position = _playerData.Position; } else { // Optionally, set a default starting position here // transform.position = defaultStartingPosition; } } Maybe for you this check works if (data == null) { data = new TData { Id = entity.Id }; } but for me it never does since GameData always exists
@nanaschi
@nanaschi 2 ай бұрын
I think your hero is also sent to (0,0,0) :) I rewatched your video many times and that's the most logical conclusion I can get. This is on timestep 12:36
@bane9109
@bane9109 2 ай бұрын
@@nanaschi Did you ever find a solution to things going back to (0,0,0)? I'm having the same problem (mine is 0,0 since i'm working on a 2d game)
Visitor: How I Mastered the Toughest Programming Pattern
12:59
Easy and Powerful Extension Methods | Unity C#
12:21
git-amend
Рет қаралды 7 М.
Final increíble 😱
00:39
Juan De Dios Pantoja 2
Рет қаралды 23 МЛН
Did you find it?! 🤔✨✍️ #funnyart
00:11
Artistomg
Рет қаралды 126 МЛН
[柴犬ASMR]曼玉Manyu&小白Bai 毛发护理Spa asmr
01:00
是曼玉不是鳗鱼
Рет қаралды 51 МЛН
Sprinting with More and More Money
00:29
MrBeast
Рет қаралды 134 МЛН
UI Toolkit Runtime Data Binding and Logic
17:11
git-amend
Рет қаралды 5 М.
The Unity HACK that the PROS know
21:27
git-amend
Рет қаралды 10 М.
Loading Scenes On Demand Has Never Been Easier!
16:00
git-amend
Рет қаралды 3,6 М.
How I Simplify Unity Development with the Façade Pattern
12:42
git-amend
Рет қаралды 4,9 М.
Clean Code using the Strategy Pattern
12:34
git-amend
Рет қаралды 10 М.
EASY Stats and Modifiers in Unity | Broker Chain Pattern
16:05
Mediator Pattern - Reduce Chaotic Dependencies
15:47
git-amend
Рет қаралды 6 М.
Flyweight Factory with Unity Object Pooling
11:30
git-amend
Рет қаралды 6 М.
How to Implement Blackboard Architecture in Unity C#
28:57
git-amend
Рет қаралды 7 М.
Как он смог забить гол
0:59
Garga
Рет қаралды 1,9 МЛН
Minecraft RTX 203% CLUCK KENT #Shorts
0:29
Jake Fellman
Рет қаралды 23 МЛН
Escape Nextbots Rosalia And Obunga Police #gmod
0:36
BizarroTube GMod
Рет қаралды 19 МЛН