├── .gitignore ├── Images ├── pool-add-actor.png ├── pooled-actor-example.png ├── pooled_expanding_graph.jpg ├── pooled_graph.jpg ├── project-settings-nav.png ├── project-settings-settings.png ├── subsystem-node.png └── unpooled_graph.jpg ├── LICENSE ├── ObjectPool.uplugin ├── README.md ├── Resources └── icon128.png └── Source └── ObjectPool ├── ObjectPool.Build.cs ├── Private ├── ObjectPool.cpp └── ObjectPoolSubsystem.cpp └── Public ├── ObjectPool.h ├── ObjectPoolSettings.h ├── ObjectPoolSubsystem.h └── ObjectPooledActorInterface.h /.gitignore: -------------------------------------------------------------------------------- 1 | Binaries 2 | Intermediate -------------------------------------------------------------------------------- /Images/pool-add-actor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennystarfighter/UnrealEngine-ObjectPool/5b1b13842b12d0223bec03c30a629fadb915d054/Images/pool-add-actor.png -------------------------------------------------------------------------------- /Images/pooled-actor-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennystarfighter/UnrealEngine-ObjectPool/5b1b13842b12d0223bec03c30a629fadb915d054/Images/pooled-actor-example.png -------------------------------------------------------------------------------- /Images/pooled_expanding_graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennystarfighter/UnrealEngine-ObjectPool/5b1b13842b12d0223bec03c30a629fadb915d054/Images/pooled_expanding_graph.jpg -------------------------------------------------------------------------------- /Images/pooled_graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennystarfighter/UnrealEngine-ObjectPool/5b1b13842b12d0223bec03c30a629fadb915d054/Images/pooled_graph.jpg -------------------------------------------------------------------------------- /Images/project-settings-nav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennystarfighter/UnrealEngine-ObjectPool/5b1b13842b12d0223bec03c30a629fadb915d054/Images/project-settings-nav.png -------------------------------------------------------------------------------- /Images/project-settings-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennystarfighter/UnrealEngine-ObjectPool/5b1b13842b12d0223bec03c30a629fadb915d054/Images/project-settings-settings.png -------------------------------------------------------------------------------- /Images/subsystem-node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennystarfighter/UnrealEngine-ObjectPool/5b1b13842b12d0223bec03c30a629fadb915d054/Images/subsystem-node.png -------------------------------------------------------------------------------- /Images/unpooled_graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennystarfighter/UnrealEngine-ObjectPool/5b1b13842b12d0223bec03c30a629fadb915d054/Images/unpooled_graph.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Benjamin Larsson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ObjectPool.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0", 5 | "FriendlyName": "ObjectPool", 6 | "Description": "Object Pooling made easy", 7 | "Category": "Other", 8 | "CreatedBy": "Benjamin Larsson / BennyStarfighter", 9 | "CreatedByURL": "https://github.com/bennystarfighter", 10 | "DocsURL": "https://github.com/bennystarfighter/UnrealEngine-ObjectPool", 11 | "MarketplaceURL": "", 12 | "SupportURL": "https://github.com/bennystarfighter/UnrealEngine-ObjectPool/issues", 13 | "CanContainContent": false, 14 | "IsBetaVersion": false, 15 | "IsExperimentalVersion": false, 16 | "Installed": false, 17 | "Modules": [ 18 | { 19 | "Name": "ObjectPool", 20 | "Type": "Runtime", 21 | "LoadingPhase": "Default" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Icon](Resources/icon128.png) 2 | 3 | # UnrealEngine-ObjectPool 4 | 5 | This is a plugin for Unreal Engine 5 (Probably works in 4 as well) which provides an easy-to-use [Object Pool](https://en.wikipedia.org/wiki/Object_pool_pattern). 6 | 7 | # Index 8 | - [What](#what) 9 | - [Why](#why) 10 | - [Performance Example](#performance-example) 11 | - [How](#how) 12 | - [Settings](#settings) 13 | - [Pool User](#pool-user) 14 | - [Pooled Actor](#pooled-actor) 15 | 16 | 17 | # What 18 | 19 | >[Wikipedia (Object pool pattern)](https://en.wikipedia.org/wiki/Object_pool_pattern) - The object pool pattern is a software creational design pattern that uses a set of initialised objects kept ready to use – a "pool" – rather than allocating and destroying them on demand. A client of the pool will request an object from the pool and perform operations on the returned object. When the client has finished, it returns the object to the pool rather than destroying it; this can be done manually or automatically. 20 | > 21 | >When it is necessary to work with numerous objects that are particularly expensive to instantiate and each object is only needed for a short period of time, the performance of an entire application may be adversely affected. An object pool design pattern may be deemed desirable in cases such as these. 22 | > 23 | >The object pool design pattern creates a set of objects that may be reused. When a new object is needed, it is requested from the pool. If a previously prepared object is available, it is returned immediately, avoiding the instantiation cost. If no objects are present in the pool, a new item is created and returned. When the object has been used and is no longer needed, it is returned to the pool, allowing it to be used again in the future without repeating the computationally expensive instantiation process. It is important to note that once an object has been used and returned, existing references will become invalid. 24 | > 25 | >Object pools are primarily used for performance: in some circumstances, object pools significantly improve performance. Object pools complicate object lifetime, as objects obtained from and returned to a pool are not actually created or destroyed at this time, and thus require care in implementation. 26 | 27 | # Why 28 | When spawning a lot of actors at a high rate or many instantly you often encounter lag spikes due to constructing so many new objects. This can be a huge problem for certain types of projects, a bullet hell for example. To combat this problem we can use an object pool pattern to spawn the actors beforehand, often when the level loads and then simply hide/unhide them when needed. Setting this up for many different kinds of actors can be annoying to manage depending on how you structure the system. 29 | 30 | That's why I created this plugin a couple of years ago and recently rewrote it to be a better version of it. 31 | 32 | # Performance Example 33 | > [!WARNING] 34 | > This is an extreme example with many actors spawning each frame. Take this with a full fist of salt since the performance gain is unique to every project. 35 | 36 | > [!NOTE] 37 | > The **`RED`** graph represents the game thread which is responsible for this logic and the **`GREEN`** one is the total frame time. 38 | 39 | **In my test project I spawn 100 bullet actors each frame and then destroy them after 0.2 seconds.** 40 | 41 | | **Normal spawning** | **Pooled + pre-spawn** | **Pooled + no pre-spawn** | 42 | | --- | --- | --- | 43 | | You can see a consistent performance hit due to constructing so many new objects. This also causes bigger garbage collection hitches later due to all the objects being destroyed. | When using pooling with pre-spawning instead we se a big initial performance hit since we're spawning a lot of actors at the same time. But after that the only thing eating precious frame time is our general code which runs in both examples anyway. | When not pre-spawning any actors and letting the pool automatically expand with new actors as needed we can se a frame time which steadily moves down as it fills upp the pool and pulled actors dont have to be spawned.| 44 | |![Normal spawning performance](Images/unpooled_graph.jpg)|![Pooled spawning no pre spawning performance](Images/pooled_graph.jpg)|![Pooled spawning no pre spawning performance](Images/pooled_expanding_graph.jpg)| 45 | 46 | # How 47 | There's different ways to use the pool. You can let the pool automatically spawn your actors when you try to pull an actor and the pool is empty, or you can set a fixed amount of actors to pre-spawn and then have them ready, or a combination of them both. I recommend you pre-spawn an estimate of how many actors you're going to need at the same time and also allow it to expand automatically if needed. 48 | 49 | If you try to pull/push an actor to the pool which haven't been added, it will be added automatically with the default settings of spawning 0 extra actors and allowing expansion if needed. For this to work the actor still has to implement the interface. 50 | 51 | > [!WARNING] 52 | > If you pre-spawn a lot of actors (above ~200) I highly recommend making sure you don't have a bunch of components auto activating on spawn. Especially sound or vfx. This can cause the game to freeze for a long time due to the sheer number of things activating at the same time. 53 | 54 | ### Settings 55 | This can be done through code or by setting some defaults for the pool in the plugin settings. 56 | 57 | ![Add actor to pool through code](Images/pool-add-actor.png) 58 | 59 | The settings can be found in `Project Settings -> Plugins -> Object Pool`. 60 | 61 | Add the actor class you want to pool and specify its settings. 62 | 63 | ![Plugin settings](Images/project-settings-settings.png) 64 | 65 | ## Pool user 66 | For each world the engine automatically creates an object pool manager as an **UWorldSubsystem**. The lifetime is handled automatically, so you don't have to think about it. All you do is fetch a reference to the subsystem and use it. This can be any system which is responsible for pushing/pulling actors from the pool. 67 | 68 | ![Get subsystem node](Images/subsystem-node.png) 69 | 70 | ## Pooled actor 71 | There's one basic requirement for any actor you want to pool. It has to implement the provided interface **"Object Pooled Actor"** which has some functions which the pool will call. 72 | 73 | You need to decide what happens to an actor when its pushed/pulled from a pool. Often this would include disabling collision on the actor and hiding it. Here's an example of an actor that sets its visibility and activates it's niagara system when pulled. After a set time this actor will push itself to the pool again instead of destroying it. It can then be reused when something tries to pull an actor of that class from the pool. 74 | 75 | ![Pooled actor example](Images/pooled-actor-example.png) 76 | -------------------------------------------------------------------------------- /Resources/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennystarfighter/UnrealEngine-ObjectPool/5b1b13842b12d0223bec03c30a629fadb915d054/Resources/icon128.png -------------------------------------------------------------------------------- /Source/ObjectPool/ObjectPool.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class ObjectPool : ModuleRules 6 | { 7 | public ObjectPool(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicDependencyModuleNames.AddRange( 12 | new string[] 13 | { 14 | "Core", 15 | "Engine", 16 | "CoreUObject", 17 | "DeveloperSettings" 18 | } 19 | ); 20 | } 21 | } -------------------------------------------------------------------------------- /Source/ObjectPool/Private/ObjectPool.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "ObjectPool.h" 4 | 5 | #define LOCTEXT_NAMESPACE "FObjectPoolModule" 6 | 7 | void FObjectPoolModule::StartupModule() 8 | { 9 | } 10 | 11 | void FObjectPoolModule::ShutdownModule() 12 | { 13 | } 14 | 15 | #undef LOCTEXT_NAMESPACE 16 | 17 | IMPLEMENT_MODULE(FObjectPoolModule, ObjectPool) -------------------------------------------------------------------------------- /Source/ObjectPool/Private/ObjectPoolSubsystem.cpp: -------------------------------------------------------------------------------- 1 | #include "ObjectPoolSubsystem.h" 2 | #include "ObjectPooledActorInterface.h" 3 | #include "ObjectPoolSettings.h" 4 | #include "Kismet/GameplayStatics.h" 5 | 6 | DECLARE_LOG_CATEGORY_CLASS(LogObjectPool, Display, All); 7 | 8 | UObjectPool::UObjectPool() 9 | { 10 | } 11 | 12 | bool UObjectPool::DoesSupportWorldType(const EWorldType::Type WorldType) const 13 | { 14 | switch (WorldType) 15 | { 16 | case EWorldType::None: 17 | return false; 18 | case EWorldType::Game: 19 | return true; 20 | case EWorldType::Editor: 21 | return false; 22 | case EWorldType::PIE: 23 | return true; 24 | case EWorldType::EditorPreview: 25 | return false; 26 | case EWorldType::GamePreview: 27 | return true; 28 | case EWorldType::GameRPC: 29 | return true; 30 | case EWorldType::Inactive: 31 | return false; 32 | } 33 | 34 | return Super::DoesSupportWorldType(WorldType); 35 | } 36 | 37 | void UObjectPool::OnWorldBeginPlay(UWorld& InWorld) 38 | { 39 | Super::OnWorldBeginPlay(InWorld); 40 | 41 | const UObjectPoolSettings* Settings = GetDefault(); 42 | 43 | for (TTuple, FPooledActorSettings> Element : Settings->InitialActorsToPool) 44 | { 45 | if (!AddActorType(Element.Key, Element.Value)) 46 | { 47 | UE_LOG(LogObjectPool, Error, TEXT("Failed to spawn initial count of actor class \"%s\""), 48 | IsValid(Element.Key) ? *Element.Key->GetDisplayNameText().ToString() : *FString("Unknown class")) 49 | } 50 | } 51 | } 52 | 53 | void UObjectPool::Deinitialize() 54 | { 55 | const UObjectPoolSettings* Settings = GetDefault(); 56 | 57 | if (!Settings || !Settings->bDestroyOnEndPlay) 58 | { 59 | return; 60 | } 61 | 62 | for (TTuple, TTuple, TArray>> Element : Pool) 63 | { 64 | for (AActor* ActivePoolActor : Element.Value.Key) 65 | { 66 | if (IsValid(ActivePoolActor)) 67 | { 68 | ActivePoolActor->Destroy(); 69 | } 70 | } 71 | 72 | for (AActor* InactivePoolActor : Element.Value.Value) 73 | { 74 | if (IsValid(InactivePoolActor)) 75 | { 76 | InactivePoolActor->Destroy(); 77 | } 78 | } 79 | } 80 | 81 | Super::Deinitialize(); 82 | } 83 | 84 | bool UObjectPool::Push(AActor* Actor) 85 | { 86 | if (IsValid(Actor)) 87 | { 88 | if (Actor->GetClass()->ImplementsInterface(UObjectPooledActor::StaticClass())) 89 | { 90 | if (!Pool.Contains(Actor->GetClass())) 91 | { 92 | if (!AddActorType(Actor->GetClass(), FPooledActorSettings(0, true))) 93 | { 94 | UE_LOG(LogObjectPool, Error, TEXT("Pushed actor of type \"%s\" did not already exist in pool and could not be added either"), 95 | *Actor->GetClass()->GetDisplayNameText().ToString()) 96 | return false; 97 | } 98 | 99 | if (!Pool.Contains(Actor->GetClass())) 100 | { 101 | return false; 102 | } 103 | } 104 | 105 | TTuple, TArray>* Subpools = Pool.Find(Actor->GetClass()); 106 | Subpools->Key.Remove(Actor); 107 | Subpools->Value.AddUnique(Actor); 108 | IObjectPooledActor::Execute_OnPushedToPool(Actor); 109 | return true; 110 | } 111 | } 112 | 113 | return false; 114 | } 115 | 116 | bool UObjectPool::Pull(const TSubclassOf Class, AActor*& Actor_Out) 117 | { 118 | TTuple, TArray>* Subpool = Pool.Find(Class); 119 | if (!Subpool) 120 | { 121 | if (!AddActorType(Class, FPooledActorSettings(0, true))) 122 | { 123 | UE_LOG(LogObjectPool, Error, TEXT("Pulled actor type \"%s\" did not already exist in pool and could not be added either"), *Class->GetDisplayNameText().ToString()) 124 | return false; 125 | } 126 | 127 | Subpool = Pool.Find(Class); 128 | if (!Subpool) 129 | { 130 | UE_LOG(LogObjectPool, Error, TEXT("Could not find subpool even after adding actor type")) 131 | return false; 132 | } 133 | } 134 | 135 | AActor* PulledActor = nullptr; 136 | 137 | // inactive pool 138 | for (AActor* Element : Subpool->Value) 139 | { 140 | if (IsValid(Element)) 141 | { 142 | PulledActor = Element; 143 | Actor_Out = PulledActor; 144 | Subpool->Value.Remove(PulledActor); 145 | break; 146 | } 147 | } 148 | 149 | if (IsValid(PulledActor)) 150 | { 151 | Subpool->Key.AddUnique(PulledActor); 152 | IObjectPooledActor::Execute_OnPulledFromPool(PulledActor); 153 | Actor_Out = PulledActor; 154 | return true; 155 | } else 156 | { 157 | FPooledActorSettings* Settings = ActivePoolSettings.Find(Class); 158 | if (Settings && Settings->bCanExpand) 159 | { 160 | PulledActor = SpawnNewActor(Class); 161 | if (!IsValid(PulledActor)) 162 | { 163 | return false; 164 | } 165 | Subpool->Key.AddUnique(PulledActor); 166 | IObjectPooledActor::Execute_OnPulledFromPool(PulledActor); 167 | Actor_Out = PulledActor; 168 | return true; 169 | } 170 | 171 | return false; 172 | } 173 | } 174 | 175 | AActor* UObjectPool::SpawnNewActor(const TSubclassOf& Class) const 176 | { 177 | if (UWorld* World = this->GetWorld(); World != nullptr) 178 | { 179 | FActorSpawnParameters Params; 180 | Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; 181 | AActor* NewActor = World->SpawnActor(Class.Get(), FVector(0, 0, 0), FRotator(0, 0, 0), Params); 182 | if (!IsValid(NewActor)) 183 | { 184 | UE_LOG(LogObjectPool, Error, TEXT("Failed to spawn actor of class \"%s\""), *Class->GetDisplayNameText().ToString()) 185 | return nullptr; 186 | } 187 | 188 | return NewActor; 189 | } 190 | return nullptr; 191 | } 192 | 193 | bool UObjectPool::AddActorType(TSubclassOf Class, FPooledActorSettings ActorSettings) 194 | { 195 | if (IsValid(Class)) 196 | { 197 | if (!UKismetSystemLibrary::DoesClassImplementInterface(Class, UObjectPooledActor::StaticClass())) 198 | { 199 | UE_LOG(LogObjectPool, Error, TEXT("The actor class \"%s\" does not implement the \"%s\" interface"), *Class->GetDisplayNameText().ToString(), 200 | *UObjectPooledActor::StaticClass()->GetDisplayNameText().ToString()) 201 | return false; 202 | } 203 | 204 | if (!Pool.Contains(Class)) 205 | { 206 | TArray InactivePool; 207 | 208 | ActivePoolSettings.Add(Class, ActorSettings); 209 | 210 | for (int i = 0; i < ActorSettings.InitialSpawnCount; ++i) 211 | { 212 | AActor* NewActor = SpawnNewActor(Class); 213 | if (!IsValid(NewActor)) 214 | { 215 | UE_LOG(LogObjectPool, Error, TEXT("AddActorType() failed to spawn new actor")) 216 | continue; 217 | } 218 | InactivePool.AddUnique(NewActor); 219 | IObjectPooledActor::Execute_OnPushedToPool(NewActor); 220 | } 221 | 222 | Pool.Add(Class, TTuple, TArray>(TArray(), InactivePool)); 223 | return true; 224 | } 225 | } 226 | 227 | return false; 228 | } 229 | -------------------------------------------------------------------------------- /Source/ObjectPool/Public/ObjectPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "Modules/ModuleManager.h" 5 | 6 | class FObjectPoolModule : public IModuleInterface 7 | { 8 | public: 9 | 10 | /** IModuleInterface implementation */ 11 | virtual void StartupModule() override; 12 | virtual void ShutdownModule() override; 13 | }; 14 | -------------------------------------------------------------------------------- /Source/ObjectPool/Public/ObjectPoolSettings.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Engine/DeveloperSettings.h" 7 | #include "ObjectPoolSettings.generated.h" 8 | 9 | USTRUCT(BlueprintType, Blueprintable) 10 | struct FPooledActorSettings 11 | { 12 | GENERATED_BODY() 13 | 14 | UPROPERTY(EditAnywhere, BlueprintReadWrite) 15 | int32 InitialSpawnCount = 0; 16 | 17 | // Can expand actor pool if needed 18 | UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName="Can Expand If Needed") 19 | bool bCanExpand = true; 20 | }; 21 | 22 | /** 23 | * 24 | */ 25 | UCLASS(Config=Game, DefaultConfig, meta=(DisplayName="Object Pool")) 26 | class OBJECTPOOL_API UObjectPoolSettings : public UDeveloperSettings 27 | { 28 | GENERATED_BODY() 29 | 30 | UObjectPoolSettings() 31 | { 32 | }; 33 | 34 | public: 35 | virtual FName GetCategoryName() const override { return TEXT("Plugins"); }; 36 | virtual FName GetContainerName() const override { return TEXT("Project"); }; 37 | virtual FName GetSectionName() const override { return TEXT("ObjectPool"); }; 38 | 39 | // Destroy all pool actors when pool is destroyed 40 | UPROPERTY(Config, EditAnywhere, BlueprintReadOnly) 41 | bool bDestroyOnEndPlay = true; 42 | 43 | UPROPERTY(Config, EditAnywhere, BlueprintReadOnly) 44 | TMap, FPooledActorSettings> InitialActorsToPool; 45 | }; 46 | -------------------------------------------------------------------------------- /Source/ObjectPool/Public/ObjectPoolSubsystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "ObjectPoolSettings.h" 5 | #include "Runtime/Engine/Public/Subsystems/WorldSubsystem.h" 6 | #include "ObjectPoolSubsystem.generated.h" 7 | 8 | 9 | UCLASS() 10 | class OBJECTPOOL_API UObjectPool : public UWorldSubsystem 11 | { 12 | GENERATED_BODY() 13 | 14 | UObjectPool(); 15 | 16 | protected: 17 | // virtual void BeginPlay() override; 18 | virtual bool DoesSupportWorldType(const EWorldType::Type WorldType) const override; 19 | 20 | public: 21 | virtual void OnWorldBeginPlay(UWorld& InWorld) override; 22 | virtual void Deinitialize() override; 23 | 24 | UPROPERTY(EditAnywhere, BlueprintReadOnly) 25 | TMap, FPooledActorSettings> ActivePoolSettings; 26 | 27 | UFUNCTION(BlueprintInternalUseOnly) 28 | AActor* SpawnNewActor(const TSubclassOf& Class) const; 29 | 30 | UFUNCTION(BlueprintCallable, Category="ObjectPool", meta=( Description="Moves an actor into the object pool and sends a OnPushed event to the object pool interface" )) 31 | bool Push(AActor* Actor); 32 | 33 | UFUNCTION(BlueprintCallable, Category="ObjectPool", meta=( ToolTip= "Pulls an actor from the pool or spawns a new one if needed and allowed")) 34 | bool Pull(TSubclassOf Class, AActor* & Actor_Out); 35 | 36 | // Adds sub-pool of the chosen actor class to the object pool 37 | UFUNCTION(BlueprintCallable, Category="ObjectPool") 38 | bool AddActorType(TSubclassOf Class, FPooledActorSettings ActorSettings); 39 | 40 | // Tuple key = Active pool, Tuple Value = Inactive Pool 41 | TMap, TTuple, TArray>> Pool; 42 | }; 43 | -------------------------------------------------------------------------------- /Source/ObjectPool/Public/ObjectPooledActorInterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "ObjectPooledActorInterface.generated.h" 5 | 6 | UINTERFACE() 7 | class UObjectPooledActor : public UInterface 8 | { 9 | GENERATED_BODY() 10 | }; 11 | 12 | /** 13 | * 14 | */ 15 | class OBJECTPOOL_API IObjectPooledActor 16 | { 17 | GENERATED_BODY() 18 | 19 | public: 20 | UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="ObjectPool") 21 | void OnPushedToPool(); 22 | 23 | UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="ObjectPool") 24 | void OnPulledFromPool(); 25 | }; 26 | --------------------------------------------------------------------------------