├── .gitignore ├── LICENSE ├── ObjectPool ├── ObjectPool.uplugin ├── Resources │ └── Icon128.png └── Source │ ├── ObjectPool.Build.cs │ ├── Private │ ├── ObjectPool.cpp │ ├── ObjectPoolComponent.cpp │ └── ObjectPoolInterface.cpp │ └── Public │ ├── ObjectPool.h │ ├── ObjectPoolComponent.h │ └── ObjectPoolInterface.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2015 user specific files 2 | .vs/ 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | *.ipa 33 | 34 | # These project files can be generated by the engine 35 | *.xcodeproj 36 | *.xcworkspace 37 | *.sln 38 | *.suo 39 | *.opensdf 40 | *.sdf 41 | *.VC.db 42 | *.VC.opendb 43 | 44 | # Precompiled Assets 45 | SourceArt/**/*.png 46 | SourceArt/**/*.tga 47 | 48 | # Binary Files 49 | Binaries/* 50 | Plugins/*/Binaries/* 51 | 52 | # Builds 53 | Build/* 54 | 55 | # Whitelist PakBlacklist-.txt files 56 | !Build/*/ 57 | Build/*/** 58 | !Build/*/PakBlacklist*.txt 59 | 60 | # Don't ignore icon files in Build 61 | !Build/**/*.ico 62 | 63 | # Built data for maps 64 | *_BuiltData.uasset 65 | 66 | # Configuration files generated by the Editor 67 | Saved/* 68 | 69 | # Compiled source files for the engine to use 70 | Intermediate/* 71 | Plugins/*/Intermediate/* 72 | 73 | # Cache files for the editor to use 74 | DerivedDataCache/* 75 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Dawid Slabkowski 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/ObjectPool.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0", 5 | "FriendlyName": "ObjectPool", 6 | "Description": "A quick implementation of the Object Pool pattern for blueprint.", 7 | "Category": "Other", 8 | "CreatedBy": "Dawid Slabkowski", 9 | "CreatedByURL": "https://github.com/dslabkowski", 10 | "DocsURL": "https://github.com/dslabkowski/ObjectPool/wiki/Documentation", 11 | "MarketplaceURL": "", 12 | "SupportURL": "https://github.com/dslabkowski/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 | } -------------------------------------------------------------------------------- /ObjectPool/Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dslabkowski/ObjectPool/97bd7390ff095a1e37a3af29a86229b509605403/ObjectPool/Resources/Icon128.png -------------------------------------------------------------------------------- /ObjectPool/Source/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 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] { 20 | // ... add other private include paths required here ... 21 | } 22 | ); 23 | 24 | 25 | PublicDependencyModuleNames.AddRange( 26 | new string[] 27 | { 28 | "Core", 29 | // ... add other public dependencies that you statically link with here ... 30 | } 31 | ); 32 | 33 | 34 | PrivateDependencyModuleNames.AddRange( 35 | new string[] 36 | { 37 | "CoreUObject", 38 | "Engine", 39 | "Slate", 40 | "SlateCore", 41 | // ... add private dependencies that you statically link with here ... 42 | } 43 | ); 44 | 45 | 46 | DynamicallyLoadedModuleNames.AddRange( 47 | new string[] 48 | { 49 | // ... add any modules that your module loads dynamically here ... 50 | } 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ObjectPool/Source/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 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 10 | } 11 | 12 | void FObjectPoolModule::ShutdownModule() 13 | { 14 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 15 | // we call this function before unloading the module. 16 | } 17 | 18 | #undef LOCTEXT_NAMESPACE 19 | 20 | IMPLEMENT_MODULE(FObjectPoolModule, ObjectPool) -------------------------------------------------------------------------------- /ObjectPool/Source/Private/ObjectPoolComponent.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | 4 | #include "ObjectPoolComponent.h" 5 | 6 | #include "AudioDevice.h" 7 | #include "ObjectPoolInterface.h" 8 | 9 | UObjectPoolComponent::UObjectPoolComponent() 10 | { 11 | PrimaryComponentTick.bCanEverTick = false; 12 | } 13 | 14 | void UObjectPoolComponent::AddActorsToPool(int const ActorsNumber) 15 | { 16 | if (PoolActorClass && ActorsNumber > 0) 17 | { 18 | FActorSpawnParameters SpawnParameters; 19 | SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; 20 | 21 | for (int i=0; i < ActorsNumber; i++) 22 | { 23 | if (AActor* SpawnedActor = GetWorld()->SpawnActor(PoolActorClass, FVector().ZeroVector, FRotator().ZeroRotator, SpawnParameters)) 24 | { 25 | SetPoolActorHidden(SpawnedActor, true); 26 | InactiveActors.Add(SpawnedActor); 27 | } 28 | } 29 | } 30 | } 31 | 32 | void UObjectPoolComponent::SpawnActorFromPool(FTransform SpawnTransform, AActor* Owner, APawn* Instigator, 33 | bool SpawnActorIfPoolIsEmpty, TEnumAsByte& Branch, AActor*& SpawnedActor) 34 | { 35 | if(!HasPoolFreeActor() && !SpawnActorIfPoolIsEmpty) 36 | { 37 | Branch = EOutputStates::Failed; 38 | SpawnedActor = nullptr; 39 | return; 40 | } 41 | 42 | AActor* PoolActorToSpawn; 43 | 44 | if(HasPoolFreeActor()) 45 | { 46 | PoolActorToSpawn = InactiveActors.Top(); 47 | 48 | PoolActorToSpawn->SetActorTransform(SpawnTransform); 49 | PoolActorToSpawn->SetOwner(Owner); 50 | PoolActorToSpawn->SetInstigator(Instigator); 51 | SetPoolActorHidden(PoolActorToSpawn, false); 52 | 53 | InactiveActors.Remove(PoolActorToSpawn); 54 | } 55 | 56 | else if(SpawnActorIfPoolIsEmpty) 57 | { 58 | FActorSpawnParameters SpawnInfo; 59 | SpawnInfo.Owner = Owner; 60 | SpawnInfo.Instigator = Instigator; 61 | 62 | PoolActorToSpawn = GetWorld()->SpawnActor(PoolActorClass, SpawnTransform, SpawnInfo); 63 | } 64 | 65 | ActiveActors.Add(PoolActorToSpawn); 66 | 67 | if (PoolActorToSpawn->GetClass()->ImplementsInterface(UObjectPoolInterface::StaticClass())) 68 | { 69 | IObjectPoolInterface::Execute_OnActorSpawnedFromPool(PoolActorToSpawn); 70 | } 71 | 72 | OnActorSpawnedFromPool.Broadcast(PoolActorToSpawn); 73 | 74 | Branch = EOutputStates::Success; 75 | SpawnedActor = PoolActorToSpawn; 76 | return; 77 | } 78 | 79 | bool UObjectPoolComponent::HasPoolFreeActor() const 80 | { 81 | return !InactiveActors.IsEmpty(); 82 | } 83 | 84 | void UObjectPoolComponent::ReturnActorToPool(AActor* Actor) 85 | { 86 | if(ActiveActors.Contains(Actor)) 87 | { 88 | SetPoolActorHidden(Actor, true); 89 | 90 | ActiveActors.Remove(Actor); 91 | InactiveActors.Add(Actor); 92 | 93 | if (Actor->GetClass()->ImplementsInterface(UObjectPoolInterface::StaticClass())) 94 | { 95 | IObjectPoolInterface::Execute_OnActorDespawnedToPool(Actor); 96 | } 97 | 98 | OnActorReturnedToPool.Broadcast(Actor); 99 | } 100 | } 101 | 102 | int32 UObjectPoolComponent::GetPoolSize() const 103 | { 104 | return ActiveActors.Num() + InactiveActors.Num(); 105 | } 106 | 107 | void UObjectPoolComponent::EmptyPool() 108 | { 109 | TArray Pool; 110 | Pool.Append(ActiveActors); 111 | Pool.Append(InactiveActors); 112 | 113 | for (AActor* ActorInPool : Pool) 114 | { 115 | ActorInPool->Destroy(); 116 | } 117 | 118 | ActiveActors.Empty(); 119 | InactiveActors.Empty(); 120 | } 121 | 122 | bool UObjectPoolComponent::IsActorInUse(AActor* Actor) const 123 | { 124 | if (Actor) return ActiveActors.Contains(Actor); 125 | return false; 126 | } 127 | 128 | void UObjectPoolComponent::BeginPlay() 129 | { 130 | Super::BeginPlay(); 131 | 132 | if (bSpawnPoolObjectsOnBeginPlay) AddActorsToPool(InitialPoolSize); 133 | 134 | } 135 | 136 | void UObjectPoolComponent::SetPoolActorHidden(AActor* Actor, bool bNewHidden) 137 | { 138 | Actor->SetActorHiddenInGame(bNewHidden); 139 | Actor->SetActorEnableCollision(!bNewHidden); 140 | Actor->SetActorTickEnabled(!bNewHidden); 141 | } 142 | 143 | -------------------------------------------------------------------------------- /ObjectPool/Source/Private/ObjectPoolInterface.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | 4 | #include "ObjectPoolInterface.h" 5 | 6 | -------------------------------------------------------------------------------- /ObjectPool/Source/Public/ObjectPool.h: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | 8 | class FObjectPoolModule : public IModuleInterface 9 | { 10 | public: 11 | 12 | /** IModuleInterface implementation */ 13 | virtual void StartupModule() override; 14 | virtual void ShutdownModule() override; 15 | }; 16 | -------------------------------------------------------------------------------- /ObjectPool/Source/Public/ObjectPoolComponent.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 "Components/ActorComponent.h" 7 | #include "ObjectPoolComponent.generated.h" 8 | 9 | UENUM(BlueprintType) 10 | enum EOutputStates 11 | { 12 | Success UMETA(DisplayName = "Success"), 13 | Failed UMETA(DisplayName = "Failed"), 14 | }; 15 | 16 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FActorStateChangedDelegate, AActor*, Actor); 17 | 18 | 19 | UCLASS(Blueprintable, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) 20 | class OBJECTPOOL_API UObjectPoolComponent : public UActorComponent 21 | { 22 | GENERATED_BODY() 23 | 24 | public: 25 | UObjectPoolComponent(); 26 | 27 | // Should pool actors be spawned on this component event begin play. 28 | UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn="true")) 29 | bool bSpawnPoolObjectsOnBeginPlay = true; 30 | 31 | // Subclass of AActor class to use in the pool. 32 | UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (ExposeOnSpawn="true")) 33 | TSubclassOf PoolActorClass; 34 | 35 | // Define how big should be pool by default. 36 | UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn="true")) 37 | int32 InitialPoolSize; 38 | 39 | // Dispatcher. Each time an actor from the pool is spawned. 40 | UPROPERTY(BlueprintAssignable, BlueprintReadWrite) 41 | FActorStateChangedDelegate OnActorSpawnedFromPool; 42 | 43 | // Dispatcher. Each time an actor is returned to the pool. 44 | UPROPERTY(BlueprintAssignable, BlueprintReadWrite) 45 | FActorStateChangedDelegate OnActorReturnedToPool; 46 | 47 | // Adds the specified number of actors to the pool. 48 | UFUNCTION(BlueprintCallable, Meta = (Keywords = "object pool, pool, object")) 49 | void AddActorsToPool(int const ActorsNumber); 50 | 51 | /*** 52 | * Returns an actor from the pool if any is available. 53 | * @param SpawnActorIfPoolIsEmpty If there is no available actor in the pool spawn another actor and add it to pool. 54 | */ 55 | UFUNCTION(BlueprintCallable, Meta = (ExpandEnumAsExecs = "Branch", Keywords = "object pool, pool, object")) 56 | void SpawnActorFromPool(FTransform SpawnTransform, AActor* Owner, APawn* Instigator, bool SpawnActorIfPoolIsEmpty, 57 | TEnumAsByte& Branch, AActor*& SpawnedActor); 58 | 59 | // Returns whether the pool has at least one free actor. 60 | UFUNCTION(BlueprintCallable, BlueprintPure, Meta = (Keywords = "object pool, pool, object")) 61 | bool HasPoolFreeActor() const; 62 | 63 | // Returns given actor back to the pool. 64 | UFUNCTION(BlueprintCallable, Meta = (Keywords = "object pool, pool, object")) 65 | void ReturnActorToPool(AActor* Actor); 66 | 67 | // Returns array of active actors in the pool. 68 | UFUNCTION(BlueprintCallable, Meta = (Keywords = "object pool, pool, object")) 69 | TArray GetActiveActorsFromPool() const {return ActiveActors;} 70 | 71 | // Return array of inactive actors in the pool. 72 | UFUNCTION(BlueprintCallable, Meta = (Keywords = "object pool, pool, object")) 73 | TArray GetInactiveActorsFromPool() const {return InactiveActors;} 74 | 75 | // Return total number of actors in the pool. 76 | UFUNCTION(BlueprintCallable, Meta = (Keywords = "object pool, pool, object")) 77 | int32 GetPoolSize() const; 78 | 79 | /*** 80 | * Destroys all the actors in the pool and releases the memory. 81 | * @warning Calling this function will cause all actors in the pool to be removed. 82 | * @warning Can cause hitch. 83 | */ 84 | UFUNCTION(BlueprintCallable, Meta = (Keywords = "object pool, pool, object")) 85 | void EmptyPool(); 86 | 87 | // Is given actor used by this pool right now. 88 | UFUNCTION(BlueprintCallable, BlueprintPure, Meta = (Keywords = "object pool, pool, object")) 89 | bool IsActorInUse(AActor* Actor) const; 90 | 91 | protected: 92 | virtual void BeginPlay() override; 93 | 94 | private: 95 | UPROPERTY() 96 | TArray ActiveActors; 97 | 98 | UPROPERTY() 99 | TArray InactiveActors; 100 | 101 | void SetPoolActorHidden(AActor* Actor, bool bNewHidden); 102 | 103 | }; 104 | -------------------------------------------------------------------------------- /ObjectPool/Source/Public/ObjectPoolInterface.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 "UObject/Interface.h" 7 | #include "ObjectPoolInterface.generated.h" 8 | 9 | UINTERFACE(BlueprintType) 10 | class UObjectPoolInterface : public UInterface 11 | { 12 | GENERATED_BODY() 13 | }; 14 | 15 | class OBJECTPOOL_API IObjectPoolInterface 16 | { 17 | GENERATED_BODY() 18 | 19 | public: 20 | 21 | UFUNCTION(BlueprintNativeEvent, BlueprintCallable) 22 | void OnActorSpawnedFromPool(); 23 | 24 | UFUNCTION(BlueprintNativeEvent, BlueprintCallable) 25 | void OnActorDespawnedToPool(); 26 | }; 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ObjectPooling for Unreal Engine 2 | 3 | ### What is object pooling? 4 | 5 | Object Pooling is a great way to optimize your projects and lower the burden that is placed on the CPU when having to rapidly create and destroy GameObjects. It is a good practice and design pattern to keep in mind to help relieve the processing power of the CPU to handle more important tasks and not become inundated by repetitive create and destroy calls. 6 | 7 | 8 | With this plugin you can create and use object pooling straight from your blueprints, any class (inheriting from an actor) can become a pool element without any changes! 9 | ObjectPool Plugin is a single class in C++ that contains all needed functions exposed to blueprints. There is no need to use C++. 10 | 11 | Learn more about [object pooling pattern](https://gameprogrammingpatterns.com/object-pool.html). 12 | 13 | ### Documentation 14 | 15 | Check [how to use plugin](https://github.com/dslabkowski/UE4ObjectPooling/wiki/Documentation). 16 | 17 | ### License 18 | 19 | Copyright (c) 2022 Dawid Slabkowski 20 | This project is licensed under the terms of the **MIT license**. 21 | You can check out full license [here](https://github.com/dslabkowski/UE4ObjectPooling/blob/main/LICENSE). 22 | --------------------------------------------------------------------------------