Just a suggestion: any pool manager should be a template based, meaning it should be able to create a pool of any type of objects/actors, so that it could be reused in many different cases. 'Template' in case of BP is called a 'Wildcard'. I'm not sure though if you can pass a wildcard to the spawn function directly or though a cast, but in C++ it's easy to make this happen: you make a wrapper function for spawning that takes an instance of a template class, check if that instance is an actor and then call the Unreal's Spawn function.
@3DWithLairdWTАй бұрын
TSubtypeOf is how you do it in C++ I made a several actor pooling subsystems for production, and in marketplace too.
@abhijitleihaorambam3763Ай бұрын
Yes
@ghislaingirardotАй бұрын
Yup, and you're right to point it out! I didn't think of mentionning it because I didn't even think it was possible to do in BP. But you might be onto something using a wildcard pin, great idea. Something to try, thanks for the suggestion!
@MireneyeАй бұрын
Excellent video! I'm currently in the trenches of data-oriented designing as well! In my last try at implementing a pool I ended up using a set of active and a set of used ones. And instead of querying the object for if it was being used, I did a Intersection. The idea was supposed to minimize the amount of times we access the object itself to check it's state. But then ofc you pay the price of managing two sets.
@ghislaingirardotАй бұрын
Yup, it's definitely a solution. I'm not too sure what's the best BP implementation tbh, all feel kinda hacky and unoptimized 😅Adding/removing entries in sets probably lead to memory reallocation though 🤔But at least the set difference is computed in CPP so there's that. Doing a CPP implementation, a simple bool array would be the most efficient, I think.
@9thCrusadeАй бұрын
00:32 im not even 1 minute into the video and bro already roasted the fk outta me 💀this is what u need to keep on learning (banger vid as always 🔥)
@ViktorartSnowtrackedАй бұрын
Super useful! As for performance, have you tried the profiling tools? Maybe you have and I forgot. "session frontend" (in UE4) You can see the ms cost of an actor down to literarily the individual BP nodes. Not sure though, might also be some ethereal overhead, so you might be right it's hard to know.
@ghislaingirardotАй бұрын
Not something I did for this specific project because I already know what to expect performance wise. And like I said, the blueprint implementation I showed won't perform miracles, a CPP version is required if you intend to ship it :) Then you can start profiling to find the right implementation.
@ViktorartSnowtrackedАй бұрын
@@ghislaingirardot Ahh, that makes sense.
@Pierre-LouisHernioАй бұрын
Super vidéo, encore une fois !
@ghislaingirardotАй бұрын
Merci!
@faimenDevАй бұрын
A very interesting example of object pooling in Unreal
@alexanderjordan2506Ай бұрын
There are probably a few tricks that can further reduce overhead. As an example, if you have a pool per actor that can fire projectiles, you should also know fire rate and lifetime of the projectile. Therefore, the array should never need to be larger than ceiling((projectiles per second) * (lifetime in seconds)). That way, you're not reserving memory you're never going to need, and should avoid the need to resize the array unless fire rate or lifetime changes. There's also a slight optimization in picking the first available projectile. Because of the way your approach and my thoughts on an optimization are structured, every tick has to check the entire array to decide for each item if collusion checks need to be run; there's no guarantee that you've found the last active item in the array without doing some kind of check/store elsewhere. As such, you can optimizing finding an inactive projectile by storing the index of the last projectile made active and starting your search from there. The next index should always be available, unless we're at the end of the array, in which case the 0th index should be available if the array is appropriately sized to fire rate and lifetime. This results in similar best case, slightly improved average case, and a much improved worst case.
@ghislaingirardotАй бұрын
Neat, the first trick is interesting! You can indeed find the most efficient pool size. You'd just need to resize the pool if the firerate/liftetime is changed at runtime. Regarding the second trick, it's already what I do, I think? Unless I missunderstood you. I do keep track of the last item picked, so the search for an available item should in theory pretty much always return a valid item at the very first bool check.
@alexanderjordan2506Ай бұрын
@@ghislaingirardot Ah, okay, I misunderstood.
@PichcherАй бұрын
thanks for your tuts and explanations
@ramontovar5675Ай бұрын
Hi I love your videos and wanted to make another suggestion! Instead of having a boolean to check if a projectile is in use, you could have two arrays to hold your used and unused projectiles. That way you avoid having to allocate extra memory into the struct, inefficient memory alignment, and it could be more ergonomic for the develop to pull things from an array instead of always checking a boolean. Thanks for your video, loved it.
@ghislaingirardotАй бұрын
Hey! Ty! Hmm, I'm no expert, but that's assuming you want to go for AoS instead of SoA. You won't have memory alignment issues with SoA afaik, no? I'm having a hard time grasping how efficient using two separate struct/object arrays can be... Pulling an item from the *unused* array probably results in memcopy/memmove to shift all indexes, and pulling items from the *used* array isn't guaranteed to be ordered. Projectile 45 may suddenly encounter a hit because of a moving object while the rest of them do not. So you'd have to pull items at arbitrary indexes, more memcopy/memmove, probably not that efficient. I think AoS + bool array check is the fastest & most cache friendly.
@aliveintechАй бұрын
Excellent!
@ghislaingirardotАй бұрын
Ty!
@MrPentagearАй бұрын
As someone else who is self-taught and continuing to learn, would it make sense to destroy / generate new pools when a weapon is switched based on that weapon's clip size?
@blindphoenixАй бұрын
One issue with that is the weapon switching itself, I don't know how others play FPS but I just use the scroll wheel until I'm at the weapon, I imagine there are other noobs switching weapons the same way. The CPU would be creating and destroying every .1 seconds with the scrolling. So creating and destroying your way would be an issue in that particular situation.
@ghislaingirardotАй бұрын
Hmm, interesting question. Depends on the technique used. Using a pool of actor/object, I'd definitely say no. Generating a pool/pre-spawing a whole lot of actors is super duper expensive and is only something to do when you can afford a hitch (beginplay etc). Using a data-oriented design, you would just need to resize a few arrays and that wouldn't be the end of the world. But then a vector is 3*32bits, so an array of 100 vectors is 0.0012MB in memory... So having a pool of 12 or 200 bullets isn't going to meaningfully make a difference imho, so I wouldn't even bother. Memory management becomes an issue when you're dealing with several hundred thousands of entries and/or heavy data set. Rendering 12 or 200 particles in Niagara isn't going to make a measurable difference either... So no, difference in weapon's clip size is likely too small to require pool management.
@CyberWolf755Ай бұрын
If you are only using small arms and have some vehicles, e.g. Battlefield, you'd probably make the VFX adjustable for different calibre of weapons (lenght, thickness, color) and have all the weapons use one of the pools, depending what VFX it will use (small arms, rockets, tank, bomb, gatling gun). Even if the game is like Doom 2016/Eternal, you could do the same, but you'd mostly have a bigger pool for the enemies projectiles and a smaller one for your player weapon projectiles. One thing that can help lower the amount of projectiles needed in general is having a max range, at which the projectile would dissapear, so you don't have to worry about it
@MrPentagearАй бұрын
@@blindphoenix I was thinking you might delay it based on a frame in the weapon's load animation, but I hear you. Valid argument.
@0UTSIDERАй бұрын
What about replication? Would it be possible/efficient with this method and niagara projectiles?
@ghislaingirardotАй бұрын
Oof. Networking isn't a topic I usually cover because it'd be pretentious of me to do so. I've nearly 0 experience in networking. However, the idea, I think, would be to just replicate the projectile data arrays, and then each client would just need to update that to Niagara on their own to draw the visuals. Or, make sure projectiles are deterministic and just replicate fire events/timestamps. Projectiles would have the same path on all clients if using a deterministic trajectory.
@KillerSneakАй бұрын
You’re only highlighting the “plus” side of object pooling. How about describing the negative side of this? Like always having everything loaded into memory. This is such an old design terminology that would be nice for games in 70’s but can’t imagine it still being useful for modern day game design where we try to load and unload everything constantly because of hardware limitations (we build and design games for consoles, not the 1% of consumers with a rtx4090 / 64GB+ ram and a 32 core cpu) also you talk about the garbage collector like it’s a bad thing………
@ghislaingirardotАй бұрын
Hi 1) I did mention downsides and I totally brought the subject of memory management, waste etc... You haven't watched the video. 2) No I don't talk about the garbage collector like it's a bad thing. You're putting words in my mouth because you seem biased on the subject. Nothing's black or white. GC is awesome. But at times it works against you, that's just how it is, like with most technologies. And it's alright. 3) Not all games are huge open worlds. Not all things need to be streamed-in & out and DoP isn't just a thing from the '70s'. In fact, it has never been so popular and widely used in game engines. Good day to you.
@CyberWolf755Ай бұрын
So you are saying this would be useful for games on 70s hardware, but not today, because this is not useful for consoles, only useful to top 1% hardware. Your statement is stupid.