Flyweight Factory with Unity Object Pooling

  Рет қаралды 6,281

git-amend

git-amend

Күн бұрын

Explore Unity Object Pooling for Flyweight Game Objects that share common (intrinsic) data and callbacks in this video aimed towards efficient management of resources and object pools!
🔔 Subscribe for more Unity Tutorials / @git-amend
#unity3d #gamedev #indiedev
▬ Contents of this video ▬▬▬▬▬▬▬▬▬▬
0:00 Flyweight
4:00 Flyweight Factory
8:10 Refactoring
Source code: gist.github.com/adammyhre/cf4...
Extensions and Utils: github.com/adammyhre/Unity-Utils
Assets Shown In This Video (Affiliate Links)
Advanced Dissolve: assetstore.unity.com/packages...
Aquarius Max Stylized Trees: assetstore.unity.com/packages...
Eole Foliage Shader: assetstore.unity.com/packages...
Epic Toon FX: assetstore.unity.com/packages...
Dungeon Mason Tiny Hero Duo: (FREE): assetstore.unity.com/packages...
Dmitriy Dryzhak Models: assetstore.unity.com/publishe...
Chromisu: Handpainted Forest MEGA Pack assetstore.unity.com/packages...
VFX Trees: assetstore.unity.com/packages...
Kronnect Beautify: assetstore.unity.com/packages...
Follow me!
linktr.ee/gitamend

Пікірлер: 58
@git-amend
@git-amend 5 ай бұрын
NEW DISCORD: discord.gg/FDRZGQBBUC Hi everyone! Join the new Discord to connect with a friendly, like-minded community, ask questions, share your projects and discuss your favorite topics!
@florianlipke6839
@florianlipke6839 5 ай бұрын
I really enjoy your videos, particularly the design pattern series. They're clear, informative, and extremely helpful. Thanks for the great content!
@git-amend
@git-amend 5 ай бұрын
Glad you like them!
@TheMystogrigen
@TheMystogrigen 5 ай бұрын
A suggestion for improved sanity while using the editor: serialize a transform, and parent to that in the objectpool instantiate method. It is really... REALLY annoying scrolling through 300 cloned objects while diagnosing something while playmode is engaged.
@git-amend
@git-amend 5 ай бұрын
Good tip!
@Caliums
@Caliums 5 ай бұрын
Don't know how to tell you how every video of yours is a pleasure to watch. This one actually came right when I was looking to implement something almost identical, so I definitely compared and improved my implementation through this video! Thanks as always!!
@git-amend
@git-amend 5 ай бұрын
Great to hear!
@alexandre2bi554
@alexandre2bi554 5 ай бұрын
Thanks for your work ! Really interesting and well explained. I hope to see more in the future !
@git-amend
@git-amend 5 ай бұрын
Thanks for watching!
@TChrisBaker
@TChrisBaker 5 ай бұрын
Great video. I was just trying to solve this similar problem recently and I was not sure where to start. This helps so much.
@git-amend
@git-amend 5 ай бұрын
Great to hear!
@Breckdareck
@Breckdareck 5 ай бұрын
Awesome video. 👌 Another great addition for people to learn from!
@git-amend
@git-amend 5 ай бұрын
Thanks! 👍
@rutchjohnson
@rutchjohnson 5 ай бұрын
Thanks for the great new vid! :) Love the weekly uploads
@git-amend
@git-amend 5 ай бұрын
Glad you watch 'em!
@user-fm9wx4wc8h
@user-fm9wx4wc8h 5 ай бұрын
Golden content for Unity dev.
@git-amend
@git-amend 5 ай бұрын
Thank you!
@rofu8096
@rofu8096 5 ай бұрын
I really need more videos about object pools. If you have object pool logic that you have written yourself, I would be eager to see it.
@git-amend
@git-amend 5 ай бұрын
When it comes to object pooling, I tend to use Unity's object pool class the most. When we build some bigger systems this year, we'll look at more use cases.
@nightyonetwothree
@nightyonetwothree 3 ай бұрын
Did similar thing in my project. My thoughts: 1. imho it's just better and easier to use custom flyweight factories for different type of objects instead of inheritence. Also custom pool (just stack) is just fine w/o any extra logic. 2. use single pool for all flyweight of any type, just re-initializing them with different configs on Get() method. So you basically need only 1 prefab and as many scriptables as you want. 3. add holder transform variable to group objects.
@Betruet
@Betruet 5 ай бұрын
Well explained. Subbed for future content :)
@git-amend
@git-amend 5 ай бұрын
Awesome, thank you!
@kevin41307
@kevin41307 5 ай бұрын
really great video!
@git-amend
@git-amend 5 ай бұрын
Thank you!
@damonfedorick
@damonfedorick 5 ай бұрын
Nice. Also grats on 5k subs. You'll be 100k by the end of this year.
@git-amend
@git-amend 5 ай бұрын
Haha, not sure about that... but 🤞
@damonfedorick
@damonfedorick 5 ай бұрын
@@git-amend well your one of the only channels, i comment and like in every video i watch. that has got to say something.
@Cloud-Yo
@Cloud-Yo 4 ай бұрын
Amazing, I have just the project to add t his to!
@git-amend
@git-amend 4 ай бұрын
Perfect!
@RobinDoesUnity
@RobinDoesUnity 5 ай бұрын
Hey man, your content is amazing. Keep it up! Just wondering, why aren't you using your implementation of Singleton for the FlyweightFactory here? Seems like a good candidate for being auto generated.
@git-amend
@git-amend 5 ай бұрын
You bet! Thank you so much for the super!
@shukarullahshah
@shukarullahshah 5 ай бұрын
Thank you
@git-amend
@git-amend 5 ай бұрын
You're welcome 😊
@techdave99
@techdave99 5 ай бұрын
Just joined the discord. Will be a better place to chat about the subject.
@git-amend
@git-amend 5 ай бұрын
Great, see you over there!
@midniteoilsoftware
@midniteoilsoftware 5 ай бұрын
Very nice. The only thing I would do different is I'd call DontDestroyOnLoad on the Flyweight instances to they don't get destroyed when loading a new scene (unless you don't want them the live across multiple scenes).
@git-amend
@git-amend 5 ай бұрын
Good point, thanks!
@nev546
@nev546 5 ай бұрын
so I know youtube is listening because I was recommended this video after investigating a game crash, which is very creepy but useful nonetheless, you guys seem like the perfect people to ask questions to. During a youtube livestream, fellow warframe content creator "theBakerTV" ran into a crash relatively late into a challenge run, and when reading out the error logs trying to determine the crash, several of them stuck out to me, and I would appreciate any input as to a more correct or technical explanation of what exactly went wrong to cause the crash. The series of events was: 1: In game, baker would kill large clusters of enemies at a time, sometimes this would lead to large puddles of pickups on the ground, such as life support to sustain the mission timer, ammo, resources etc. These puddles of drops would sometimes induce a small amount of lag when picking them up all at once, and I speculated that the drops were imparting more strain on the game's memory than normal. 2: Before the crash, enemy spawns would slow down occasionally if there were too many spawn requested at a time, likely for the sake of maintaining performance/preventing lag. In the logs this could be seen directly as "Spawning paused" for a few lines before resuming normal spawning 3a: The game has an integer cap on the amount of damage you can deal, but this cap is only visual, and is 2,147,483,520, if you ever get a number higher than this, the only way to know is to check logs, where you can see your actual damage written in scientific notation (i.e. 2.5e+09). In game, any damage greater than damage cap will appear as the damage cap number but negative, and in logs, the damage you deal to an enemy will show up as a "warning" log, with the phrase "Damage too high!" followed by the aforementioned scientific notation 3b: I bring this up because in mission, baker was killing clusters of enemies (in some cases 33 at a time) but he never brought his damage anywhere close to damage cap, with his highest point of damage being 6.9e+07, (just shy of 70 million damage.) Despite this, he still got the "Damage too high!" warning in logs, and for the life of me I can't figure out why. 4: The final moments before the crash were: "Finish load of flyweight batch: 100% utilization" Followed by several enemy spawns, before "Failed to allocate bytes internally" and the final error log reading "Assert out of memory" which ultimately caused the crash. I'm no game dev, and my understanding of computer science is cavemanish at best, but I speculated that this was ultimately caused by a memory leak, and the large influx of enemy spawns pushed the loader over it's limit, freezing the entire game and causing the crash. Warframe's game engine is unique, it is an ever changing sister to the unreal engine, named "Evolution" so the inner workings of the engine are similar but still vastly unique from unreal, at least that's my understanding of how it works, so idk if your guys' unity knowledge is applicable but if it is, I'd love some kind of help in analyzing and further understanding what caused the crash. Because the crash was live, we have the VOD of it here (kzbin.info0ASv6d1djps?si=Fq39OSr3XlwnD90a&t=8915 (timestamped at the moment Baker pulls up the log file)) and you can even see before the crash how much the game's performance had deteriorated by the time the crash happened.
@git-amend
@git-amend 5 ай бұрын
This is a question for the game developers; anyone reading this here will only be able to speculate at best. Clearly the final outcome is the result of running out of memory, but the only people that can answer your question need to have both in-depth knowledge of the game's engine and the specific implementation details.
@nev546
@nev546 5 ай бұрын
@@git-amend dang, worth a shot! Thank you very much for reading anyways!!
@thetalesofold
@thetalesofold 3 ай бұрын
This is exactly what I needed. However, I am confused because I was trying to do the shoot 'em up style of weapon strategies, and even with setting the parent I seem to be shooting myself or they spawn from the center of the camera.
@lbarral
@lbarral 5 ай бұрын
It's an awesome approach! Reuse instead of always creating an instance... The question is: when these objects at the pool are destroyed?
@git-amend
@git-amend 5 ай бұрын
While not shown in the video, the ObjectPool class has a Clear method- this will call the destroy callback on all objects in a pool
@MarushiaDark316
@MarushiaDark316 5 ай бұрын
That's really cool. I wish this video had come out months ago when I was working on a project that required making a bunch of different object pools by hand, all of different types. I wound up going down the generics road and so I understand exactly why you chose to do a base class method because that was a god-damned nightmare trying to reflect everything. Do you think you could do a video on reflection and polymorphism?
@git-amend
@git-amend 5 ай бұрын
Yeah, that's not a bad idea. I'll give that some consideration. Cheers!
@PiGameDev
@PiGameDev 5 ай бұрын
Great video! Object pulling is very important in Unity. Great job! I wonder if you could make a video where you combine your systems together? Here I feel like you could use your injector system or a factory and drop the static calls. What do you think?
@git-amend
@git-amend 5 ай бұрын
Thanks! This year I'll try to do more combinations of patterns and start building slightly larger systems.
@adriankovatana
@adriankovatana 5 ай бұрын
Great video. Wouldn't you want to move FlyweightType out of the abstract class and into the concrete ProjectileSettings class? Those types seem specific to the projectile, rather than the flyweight.
@Briezar
@Briezar 5 ай бұрын
great video as always! I would further improve on your yield dictionary to use custom equality comparer to avoid boxing and duplicate values due to floating point comparison, as well returning null instead of new WaitForSeconds if the delay is less than a single frame. private class FloatComparer : IEqualityComparer { bool IEqualityComparer.Equals(float x, float y) { return Mathf.Abs(x - y)
@git-amend
@git-amend 5 ай бұрын
Looks like a good optimization! Cheers!
@ezioassassin2028
@ezioassassin2028 5 ай бұрын
I've added support for flyweights as an interface. It's not perfect, and it requires the user to know what class implements the interface rather than inheriting from the base flyweight class. I'm also keying the dictionaries with an int ID and just manually keeping track of them for my project in a spreadsheet (its not the best but I'm developing solo so I alone deal with it until I can think of something better). public interface IFlyweight { public FlyweightSettings Settings { get; set; } public GameObject gameObject { get; } //naming this "gameObject" allows interaction with the GameObject this interface is attached to without having to set it when implementing the interface because it automatically hooks itself to the gameObject reference of a MonoBehaviour. I didn't know this, I figured this out on accident. } public class FlyweightFactory : PersistantSingleton{ [SerializeField] bool collectionCheck = true; [SerializeField] int defaultCapacity = 10; [SerializeField] int maxPoolSize = 100; readonly Dictionary flyweightPools = new(); readonly Dictionary IflyweightPools = new(); IObjectPool GetPoolForFlyweight(FlyweightSettings settings) { IObjectPool pool; if (flyweightPools.TryGetValue(settings.FlyweightID, out pool)) { return pool; } pool = new ObjectPool(settings.Create_Flyweight, settings.OnGet, settings.OnRelease, settings.OnDestroyPoolObject, collectionCheck, defaultCapacity, maxPoolSize); flyweightPools.Add(settings.FlyweightID, pool); return pool; } IObjectPool GetPoolForIFlyweight(FlyweightSettings settings) { IObjectPool pool; if (IflyweightPools.TryGetValue(settings.FlyweightID, out pool)) { return pool; } pool = new ObjectPool(settings.Create_IFlyweight, settings.OnGet, settings.OnRelease, settings.OnDestroyPoolObject, collectionCheck, defaultCapacity, maxPoolSize); IflyweightPools.Add(settings.FlyweightID, pool); return pool; } public static Flyweight SpawnFlyweight(FlyweightSettings settings) => instance.GetPoolForFlyweight(settings)?.Get(); public static IFlyweight SpawnIFlyweight(FlyweightSettings settings) => instance.GetPoolForIFlyweight(settings)?.Get(); public static void ReturnToPool(Flyweight flyweight) => instance.GetPoolForFlyweight(flyweight.settings)?.Release(flyweight); public static void ReturnToPool(IFlyweight flyweight) => instance.GetPoolForIFlyweight(flyweight.Settings)?.Release(flyweight); } public class FlyweightSettings : ScriptableObject { public GameObject prefab; [SerializeField] protected int flyweightID; public int FlyweightID => flyweightID; public virtual Flyweight Create_Flyweight() { var go = Instantiate(prefab); go.SetActive(false); go.name = prefab.name; var flyweight = go.GetOrAdd(); flyweight.settings = this; return flyweight; } public virtual IFlyweight Create_IFlyweight() { var go = Instantiate(prefab); go.SetActive(false); go.name = prefab.name; var flyweight = go.GetComponent(); if(flyweight is null) { Debug.LogError($"{prefab} does NOT contain a script with the IFlyweight interface!"); return null; } flyweight.Settings = this; return flyweight; } public virtual void OnGet(Flyweight flyweight) => flyweight.gameObject.SetActive(true); public virtual void OnGet(IFlyweight flyweight) => flyweight.gameObject.SetActive(true); public virtual void OnRelease(Flyweight flyweight) => flyweight.gameObject.SetActive(false); public virtual void OnRelease(IFlyweight flyweight) => flyweight.gameObject.SetActive(false); public virtual void OnDestroyPoolObject(Flyweight flyweight) => Destroy(flyweight.gameObject); public virtual void OnDestroyPoolObject(IFlyweight flyweight) => Destroy(flyweight.gameObject); }
@git-amend
@git-amend 5 ай бұрын
Maybe you could use Guid.NewGuid() to create Ids for each type somehow instead of using a spreadsheet?
@abuzzakasm9767
@abuzzakasm9767 4 ай бұрын
Can you amke a similar tutorial for netcode for game object. Really love your explanation ❤️
@git-amend
@git-amend 4 ай бұрын
Might not do another Netcode project for a while, but you can check out the Kart Game playlist on this channel, it's all about Netcode.
@TheMystogrigen
@TheMystogrigen 5 ай бұрын
Every time I see one of your videos, I get scared as I always end up implementing something I see. This video was the WaitForSeconds Dictionary. Going through all the WaitForSeconds creating I did was not fun.
@git-amend
@git-amend 5 ай бұрын
That reminds me, I added that code to the Utility repo and I should have linked it in the description!
@emilhdov3350
@emilhdov3350 4 ай бұрын
Hi, i watched video second time but I still can't understand what IObjectPool is.
@git-amend
@git-amend 4 ай бұрын
Do you mean the interface? docs.unity3d.com/ScriptReference/Pool.IObjectPool_1.html
Better Singletons in Unity C#
14:08
git-amend
Рет қаралды 7 М.
When to use Factory and Abstract Factory Programming Patterns
12:13
Osman Kalyoncu Sonu Üzücü Saddest Videos Dream Engine 170 #shorts
00:27
3M❤️ #thankyou #shorts
00:16
ウエスP -Mr Uekusa- Wes-P
Рет қаралды 11 МЛН
SIMPLE Tip For Better Unity Game Architecture
12:57
git-amend
Рет қаралды 27 М.
Serialize Types in the Unity Editor using Reflection
11:50
git-amend
Рет қаралды 6 М.
EASY Stats and Modifiers in Unity | Broker Chain Pattern
16:05
Ranking ALL Design Patterns for Games under 30min
25:51
This is GameDev
Рет қаралды 7 М.
Why Does Scrum Make Programmers HATE Coding?
16:14
Thriving Technologist
Рет қаралды 499 М.
(Better) Object Pooling - I Didn't Like My Old Solution
8:49
One Wheel Studio
Рет қаралды 14 М.
Visitor: How I Mastered the Toughest Programming Pattern
12:59
How I Simplify Unity Development with the Façade Pattern
12:42