Flyweight Factory with Unity Object Pooling

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I've been exploring options for managing all my projectiles in my game using the flyweight pattern the flyweight pattern aims to minimize memory usage and improve performance by sharing as much data as possible with similar objects all my Fireballs for example share the same prefab and some other values and this data is stored in a scriptable object what would be nice is to combine the utility of the flyweight pattern with unity's object pool class so what I'd like to do today is create a simple but Power ful Factory that can not only create our flyweight objects but move them in and out of their own object pools as well I'm going to start by defining a simple flyweight class that will contain a reference to the intrinsic settings intrinsic values are the ones that are shared by all the fly weights so we can Define all those common values in a scriptable object you'll just call it flyweight settings it's going to have a reference to the prefab then I'll add a few more values that'll work for for my projectiles that I'm going to set this up for now I'm also going to have a method in here that will actually create a flyweight for me so I can instantiate it into a variable here and set active false I'm going to make sure they're all named the same and I'm just going to name mine after my prefab names now I'm going to add the flyweight component to it and set the reference to the settings then I can return the object I'm going to add a create asset menu attribute and this is really all the shared data I want for right now so I'm just going to move this into its own file [Music] then I can come back to my flyweight class and just going to add some really basic functionality here so I can test it out so while the flyweight is active I want it to be always moving straight forward so I can grab the speed from the common settings and just every update move it ahead a little bit and then we'll despawn it after a little while for now despawning is going to mean actually destroying it so I'm just going to wait for a certain amount of time and we can set that on enable and then we'll destroy it so in on enable let's just start a co- routine here so I'm using a helper method here to get a wait for seconds and I actually am storing them in a little dictionary why don't we go take a look at that quickly so instead of creating a new wait for seconds every time I want one I'll just create it the first time store it in the dictionary and every time I want one afterwards I can just request it this way now back in my settings I'm also going to add an enum here for types of fly weights this will be useful when we start building our flyweight Factory I'm just going to make two types for for now for this demo Fire and Ice and that's it let's add a property here in the by weight settings and that's about all we need right now if I jump back over to my hero class I can put a little implementation in here so we can start testing it out so if we had a public list of flyweight settings here in our update method we could check for some key presses and then our flyweight settings can create the flyweight for us we can just set it at a about eye level of the character and turn it on now this is a very naive implementation but it's really just for testing before we go back into Unity let's also make sure it's rotated the right direction as well so back here in unity I can start defining some scriptable objects that'll contain all of this shared data for each flyweight so the first one here could just be for fire and I already have a fireball um particle system that I want to put onto here so I'll just drag that prefab into here and I think the the default value for the other things are okay now I'm just going to duplicate the Fireball and I'm going to call this one Frost because the prefab is actually called Frost Missle so let's find it here drag that in now the hero just needs references to both of those scriptable objects that we just made and that's really it once those references are in there we can press play and try it out so I'll just zoom in a little bit here and let's see how this super basic fly weight is working yeah we got both types here just pressing one and two yeah no problem so this is okay but it's not really that useful we're still destroying the fly weights when they run out of time and that's garbage collection and I don't really want to start managing individual object pools for every type of flyweight in my game so what would be really nice is to create a simple Factory that will manage all of this for us and I'm going to call that the flyweight Factory I only want to have one flyweight Factory so I'm going to use a version of the Singleton pattern here and just keep an instance of it here as a static variable and then I'm going to start leveraging unity's object pool class we'll keep an object pool for each type of flyweight in a dictionary so to maintain the Singleton in a wake let's just check to see if the instance was null or not if the instance was null let's set instance equal to this and don't destroy onload otherwise we'll destroy the game object so in a moment I'll create a few public methods to act as an API to this but we're going to need a private method so when we pass something in here we need to know which pool it actually belongs to since all of the flyweights have a reference to their settings which contains the type we can use that to find out which pool this object belongs to so we pass in the settings and we'll try and get the pool if it exists we return that pool if it doesn't exist then we need a new object pool for this particular type so let's create a new object pool of type fly weight the Constructor for a basic object pool in unity takes in four callbacks and three values so I'm just going to put each one on its own line we've already made a create method in our settings class the create method is a funk that Returns the same type is the pool now the other callbacks are all actions of that type we'll be able to keep those in our settings class as well the last three values we can just Define in our Factory here I'll just get all these code hints out of the way for a second so we've got create and then we've got actions that fire on get on release on Destroy and then we've got three values that we'll set for each pool that we want to create so up at the top of the class I can declare serialized fields for each of the Primitives finish up that private method we need to add this new pool to our dictionary and then we need to return the pool so let's set up these action callbacks on get we just want to enable the game object on release we'll do the opposite and if we were actually going to destroy this pulled object then we can just actually destroy it all right our Factory is almost ready we just need some public methods so that we can interact with this Factory so I'm going to make two static methods here one is going to spawn a new flyweight to do that the consumer just needs a reference to the settings scriptable object so going to pass that in then we'll get the pool for those settings and then we'll actually call the get method on the pool now we'll basically do the inverse of that when we want to return a particular flyweight to the pool the fly weight has has a reference to its own settings so it knows what type of pool it belongs to we'll just call the release method on that pool and that's it now back in the hero we're not going to create flyweights ourselves anymore we're going to call the flyweight Factory spawn method pass in the settings for the one that we want I'll just change both references here then we also don't have to set active to True anymore because we already have a call back for that now the last thing to do is we don't actually have to destroy these objects anymore instead let's just call the factories return to pool method and pass in this back in unity all I have to do is create a flyweight Factory here we'll just add the component here to the new game object I'm just going to pull this down a little bit so we can see the hierarchy a little bit better so now if I start pressing the buttons here we should watch these things start to deactivate themselves and stay inside the pool yeah there we go so they're not being destroyed anymore and now if I start casting again you can see some of the existing ones start activating again and then after a little bit they go back into the pool so this is a very simple implementation of a flyweight Factory but it really only makes one kind of flyweight which is a projectile wouldn't it be nice if we kind of separated the flyweight logic from the projectile logic so we can make any kind of flyweight maybe a tree or an enemy there's really two ways we could go about this we could extract an interface or we could extract a Bas abstract class so both of those methods have their advantages but the interface would require using generics and it would get quite a bit more complex the simpler way to go here is use an abstract class so I'm going to pull out all of the projectile specific logic into a new class projectile we'll just leave the settings in the fly weight now our intrinsic data for projectiles is probably different than any other sort of fly weight so let's jump over to the settings class I'll make a new class that extends the flyweight settings we'll just call it projectile settings now as we continue to develop our game we could add more values in here for now copilot suggesting damage sure I'll move these other projectile specific settings into here and then I'm going to make all of the methods virtual that way we can override them from the base flyweight settings class if we want to let's add a create asset menu attribute here and move this into its own file now if we jump back over to our new projectile class here you can see we've got a few things that can't be referenced and that's because flyweight settings in the Base Class isn't the projectile settings type so let's cast it into a projectile settings type we'll need to use the keyword new here because we're using the same variable name there we go all right just a few more references to change back in the hero we're still referencing flyweight settings this should really be projectile settings we can enforce the type here and I'll just change the variable name to to be projectiles that's all we really have to change there if we come back to our projectile class because it's a monel behavior it needs to be in its own file I'll move that over here and then one more thing is we should really override our create method in the projectile class because we don't want to add the flyweight component to it we want to add a projectile component to it I'm just going to copy and paste that same create method over into our projectile settings class here and we'll change this to an override and we'll change the type of component that's being added from flyweight to projectile now in the future we'll be able to add any more custom logic we want when creating projectiles here and we could override the other callbacks as well if we wanted other behavior when despawning or spawning Etc all right well let's jump back into unity and just make sure that I didn't break anything press play and start shooting off some projectiles yeah looks good looks really good let just make sure they're going back into the pool properly yep perfect well I hope that gives you a few ideas if you're looking to manage the spawning of objects that all share some common settings I'm still weighing the pros and cons of using interfaces instead of a base class for this and I'd like to key the pool dictionary differently let me know what you think in the comments below
Info
Channel: git-amend
Views: 4,623
Rating: undefined out of 5
Keywords: unity tutorial, unity arcade game, unity game tutorial, unity, game development, game dev, game development unity, programming, c#, software development, learn to code, learn programming, unity tutorials, unity devlog, indiedev, gamedev, unity3d, unity flyweight
Id: qHn4sschAro
Channel Id: undefined
Length: 11min 29sec (689 seconds)
Published: Sun Jan 07 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.