How to Use Dynamic Buffers to Store Many Components on an Entity in Unity ECS - DOTS Tutorial 2021

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in unity ecs you can only add one data component of a given type to a single entity or can you hello everyone i hope you're all doing well in today's video we're going to be talking about dynamic buffers which can be used to store multiple data components on an entity similar to an array or a list so first i'll be talking about the theory behind dynamic buffers how they work when you might want to use them i'm going to be showing you how to actually set up dynamic buffers and use them in an actual project by using this little fishing simulator game that you see playing behind me and in fact a little turbo makes games trivia for you this is actually the second fishing simulator i've made i made a game a little while back which was a tower defense fishing simulator called email fishing for a game jam a couple years ago i think i did a couple videos on the channel about it so maybe leave some links up in the description for you but anyways that's not the topic of today's video today's video is all about dynamic buffers before we get into it i'd just like to say if you do find today's video helpful i'd really appreciate it if you hit that like button also feel free to subscribe to the channel for lots more videos about uni's entity component system and their data oriented technology stack of course if you do have any questions for me or suggestions for future videos you can always leave those down in the comment section below or join us over on discord over at tmg.dev discord so dynamic buffers give us a way that we can associate array-like data with an entity now it can hold a variable number of these elements and we can resize the dynamic buffer if we need to now these elements can basically be any type of data component you know we can have simple things just like integers or some custom data components so dynamic buffers are best used for well dynamic data data that's going to be changing throughout the life cycle of our application maybe we're going to be adding and removing things to this buffer or maybe we're just going to be changing values on this buffer pretty frequently so that's the best use for these dynamic buffers is when we want to have you know a set of data that needs a number of elements that is going to be changing throughout the life cycle of our application and furthermore each of these entities can basically have their own dynamic buffer in which a different set of elements can be stored on each one of these now one important concept that we need to keep in mind with dynamic buffers is an attribute known as the internal buffer capacity now by using this internal buffer capacity attribute it gives us some control about where the actual data lives in memory so basically if we have anything a number of elements less than this internal buffer capacity that we set less than or equal to i should say then that data is actually going to be able to live inside the actual chunk with our entities now if we go over that internal buffer capacity that we set now all that data set inside that dynamic buffer is actually going to be moved out of the chunk and into the heap so it's going to be a little bit less performant if we have the memory off in the heat because you know when the cpu actually processes that chunk of data it's going to have to point to another memory location in order to look through that dynamic buffer so now we can kind of choose what we want to set this internal buffer capacity to be and so when we're actually determining what we should set this number as we need to keep a couple things in mind now you might initially be thinking you know let's set this value kind of as high as we possibly can so then all that data is basically going to live inside the chunk that's going to be the most performant now that's not necessarily going to be the most ideal because it's going to allocate and block off a large chunk of memory inside that chunk so then we're not going to be able to fit as many entities inside a single chunk as we normally would and then so now if we have a lot of entities we're going to have to allocate a lot of different chunks and we're not necessarily going to have the best chunk utilization if we're not actually filling those buffers up to near the maximum amount so now we kind of actually want to bring that number down a little bit so we get to the point where um you know we're we're still not allocating a bunch of memory off to the heap but we're still just kind of like in that that right middle zone where we have a realistic number of these elements that are fitting inside the chunk and we can fit the maximum number of entities inside the chunk without having to push these dynamic buffers off to the heap now say that if you don't totally understand this at this point that's totally fine i do plan on making a video in the future kind of going over some debugging and performance monitoring tips for unity ecs and i'll be going over how we can actually monitor our chunk utilization and things like that but for now just kind of set the internal buffer capacity to a value that feels right for your game you know what's going to be the most likely scenario for how big that buffer is going to get all right so here we are over in unity not a whole lot to point out here other than my beautiful drawing of a fisherman here basically the idea of this project is we're going to be catching fish when we press the space bar and then we're basically going to be tracking the length of each fish that we catch throughout you know the duration of our little fishing simulation here um and then at the end once we catch eight fish then it's just going to display the lengths of all the fish so we're basically going to be storing the lengths of each fish inside a dynamic buffer by the way you can download all the project files and code featured in today's tutorial video using the links in the description below so when working with dynamic buffers the first thing that we need to do is define a single element the type of a single element of our dynamic buffer so in this case we're just going to make a public struct which we're going to be calling the fish length buffer element and then it's going to implement the i buffer element data so not i component data as we normally would in ecs but it's i buffer element data that's basically going to be saying you know hey this is a element that can be used in a dynamic buffer and then here's where we actually define the data type that's going to be on our buffer buffer element so in this case it's we're just going to do a public integer and we can just call this value here so this is basically just going to be the length value of the fishes that we catch now like i mentioned earlier this data type can basically be you know any data component that we want it's still going to be subject to the same limitations of a regular component data so you know we can't use like managed classes or things like that so we can just only use blittable data types things of that nature but you know any custom data components that we want we can basically make it part of this buffer element now if we want we can have multiple types of data so maybe we can also have like an enum for the type of fish it is or a float for like the the weight in grams of the fish or something like that but these buffer elements work best when there's just one single element and i'll show you why that is there's a couple reasons so the first one is here we can actually do a generate authoring component and what this is going to allow us to do is when we come back over to unity here we can go on to any game object and here we can just add the fish length buffer element you'll see that it's actually gives us acts like it basically gives us an author component component for a full dynamic buffer um so you'll see that there's just kind of this little values drop down and then there's a list here so we can actually you know define what we want for each of these elements so we can say oh we caught a seven-inch fish and here we cut a nine-inch fish or a 13-inch fish now this only works if we just have one single value on our buffer element so that's kind of one advantage is if you do want to define things through like an authoring component like this that's one reason that you might do that but we don't need that now so we're just going to go ahead and remove that component and then as i mentioned in kind of the theory section of the video here's how we can actually set the internal buffer capacity so we basically just do a new attribute called internal buffer capacity and we just pass in the integer for the essentially maximum capacity that we want to allocate the dynamic buffer in the chunk now in this case i've chosen a value of 8 because basically in my fishing simulation system we're only going to catch up to a maximum of eight fish before it displays the results to the player so we know that the maximum in our game will never go above eight so that's kind of a good place to start at if we say went to a value of ten and the player could only catch eight fish still then that's just gonna be kind of a waste of memory because it's allocating memory for you know memory that's never actually going to be filled up with any data now if we went lower to say like a value of six then when we catch fish number seven and eight it's actually going to move the values of this entire dynamic buffer out of the chunk and into the heap of memory which is going to be a little bit slower for the computer to access so now i'll show you how to actually add a dynamic buffer to an entity so over here in my fishing simulation system i'm just in the onstart running function here we you see that i have a variable called fisherman which is just an entity variable we'll set this equal to entitymanage.create entity to just go ahead and create an empty entity for us to play around with now the way we add a dynamic buffer to an nc very similar to adding a data component to an entity so of course we'll just use the entitymanager this time we're going to use the add buffer inside the type brackets we're going to put in the type of buffer element that we're basically going to be wanting essentially a dynamic buffer of so in this case it's going to be the fish length buffer element and then inside the parentheses we can just pass in the uh fisherman entity right here now that's basically all we need to do to add a dynamic buffer to an entity now you'll notice the add buffer function if you hover over it you'll see that it returns a type of dynamic buffer with type of fish length buffer element you'll see that i've defined a variable up here for a private dynamic buffer type of fish length buffer element just called fish log so this is basically going to be the actual essentially array of data that we're going to be tracking the length of the fish that we catch in so one thing that we can do is just go ahead and do a fishlog equals entitymanager.addbuffer so now we have a reference to this fish log here now i will point out that this is a little bit dangerous because when structural changes are made in your game this dynamic buffer reference is actually going to break so basically any time that we want to add data to it it's always good to just go ahead and actually get a new reference to that data so now i'm going to show you how to actually add data to a dynamic buffer so just in our on update function here um you'll see that basically we're just waiting for the player to press the space key when they do press the space key we're just going to go ahead and run some catch fitch logic which basically just kind of shows some ui on the screen there's not a whole lot of craziness happening there but if we did catch a fish then we're going to go ahead and generate a random length for a fish if you haven't seen my video on using random immunity ecs i would highly suggest checking that out i'll leave a link up in the card as well as in the description below so anyways if we did catch a fish we're just gonna go ahead and again get a new fresh reference to that dynamic buffer just by doing fish log is equal to a get buffer type of fish length buffer element and then we can pass in our fisherman entity here so now that we have it we can actually just go ahead and add some elements to this so we can just do a fishlog dot add you know very similar to like something that would do for a list then you'll see that it's it wants us to pass in a type of fish length buffer element so we'll just go ahead and create a new fish length buffer element and then we can set this value equal to the fish length which is just that random value that we generated here so that's basically all that we need to do for adding things to the dynamic buffer then coming over to unity here if we press the play button and then we press the space bar you'll see that we catch a six inch trout go ahead and start fishing again press the space bar and we catch a 10 inch trout this time we can go ahead and do this a few more times and you see that we now have a 14 inch trout so now if we actually come over to the entity debugger you see this entity 3 is just that new entity that we created in code here you'll see that you know all it has on it is just this fischer length buffer element you'll see that it has a size of three because we have three elements here again and now it's keeping track of the length of fish that we catch so you'll see that there's you know 6 10 14 and as we continue to fish you'll see that we now caught a 22-inch fish a nine inch fish now one thing that i should point out is there's actually a much cleaner way that we can add elements to this dynamic buffer so this kind of goes back to one of the advantages of just using a single data value for our buffer elements so what we can actually do here is we can create a public static implicit operator which is going to return us a fish length buffer element which takes in an integer just called value and then here this is just going to go ahead and return a new fish length buffer element setting the value property equal to the value value that we're passing in so that means we can come back to the fishing simulation system we can basically just get rid of all this and then when we do fish log dot add we can just pass in the fish length just like that and in the operator it's going to go ahead and create a new fish length buffer element it's going to pass in this value here so again we'll come over to unity we'll hit the space bar a couple times you'll see that we catch some fish go to the entity debugger you'll see that we've tracked the length of these fish here now the last thing that i'm going to show off is basically a cool way that we can kind of total up the lengths of the fish that we caught we'll just do a simple for loop here just going from zero to the fishlog.length again we can just use the dot length similar to like we would do on an array or a list or something like that so if we wanted to say print out the length of each fish that we got we can just go ahead and access each element by using the underscore fish log at position i dot value so you know very similar to accessing something like we would in an array and again we just have to do the dot value because we actually um need to actually get the value off this here however if we are using you know pure integers say we wanted to use like this total length here so we can actually add up the total length of all the fish that we caught we can do another one of these implicit operators so i'll just make a public static implicit operator this time it's going to return an integer and actually take in a fish length buffer element which we just call element and then so here we'll just go ahead and return element dot value so the advantage of this is when we want to total up the total length we can just say total length plus equals the uh fish log at position i and then we don't need to put the dot value at the end that's basically how we can total up the total length so now if we come back to unity and we just go ahead and catch a couple of these fish you'll see that once we catch uh up to eight of these fish here then you'll see that it kind of gives us this little final end screen that says you caught fish with the lengths of 6 10 14 22 9 21 15 and 23 for a total length of 120. so anything else that's basically the gist of how to use dynamic buffers in unity's entity component system i hope this you know kind of gave you a little bit more insight about how we can um have one entity track multiple data components so it's as you can see it's pretty similar to just using an array there is just a little bit of kind of setup that you have to get additional setup that you have to go through that's kind of ecs specific and there are a couple quirks and things that you do need to watch out for as you go along so once again i do hope you did find today's video helpful if you did i'd really appreciate it if you hit that like button also feel free to subscribe to the channel for lots more videos about unity's nt component system and their data oriented technology stack of course if you do have any questions for me or suggestions for any future videos you can always leave those down in the comments section below or join us over on discord over at tmg.dev discord hope you have a fantastic rest of your day and i'll see you in the next one you
Info
Channel: Turbo Makes Games
Views: 1,416
Rating: undefined out of 5
Keywords: unity tutorials, unity3d tutorials, beginner unity tutorials 2019, custom editor window, game tools programming, game tools programmer, video game programmer, how to program video games, unity ecs dynamic buffer, unity ecs dynamic buffer example, unity dynamic buffer, unity ecs array component, what is unity ecs
Id: Ki0AwYZw2Ac
Channel Id: undefined
Length: 16min 28sec (988 seconds)
Published: Tue Jul 20 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.