对象池是用泛型实现的,可以自动管理结构体和对象,可以用泛型去获取对象,可以用可变参去构建对象,也可以用虚幻的类型引用来获取对象,对于类对象可以传入自定义的初始化回调函数/重置函数来修改对象的数据或状态,可以目前是用泛型获取对象的UClass*或UScriptStruct*来存储对象,后续可以考虑用Level为单位去管理对象池。同时目前对象池继承的类是组件类,后面可以考虑继承UTickableWorldSubsystem来实现这个对象池。 在用到虚幻的反射去或者对象的分类的时候,发现其实虚幻的发射也不是纯动态的,也会通过生成部分静态函数,这就和我以前见过的一个宏,宏内部是静态函数,去注册药反射的字段和函数。
PooledObject.h这个结构体用来描述单个对象。
#include "CoreMinimal.h" #include "PooledObject.generated.h" USTRUCT() struct FPooledObject { GENERATED_BODY() UPROPERTY() UObject* Object; TSharedPtr<void> StructData; UPROPERTY() bool bIsInUse; UPROPERTY() FDateTime LastUseTime; };
ObjectPoolManager.h用来管理对象池
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GenericClassObjectPool.h" #include "GenericStructObjectPool.h" #include "Components/ActorComponent.h" #include "ObjectPoolManager.generated.h" USTRUCT() struct FPoolKey { GENERATED_BODY() UPROPERTY() UClass* ObjectClass; UPROPERTY() UScriptStruct* StructClass; FPoolKey() : ObjectClass(nullptr), StructClass(nullptr) {} FPoolKey(UClass* InObjectClass) : ObjectClass(InObjectClass), StructClass(nullptr) {} FPoolKey(UScriptStruct* InStructClass) : ObjectClass(nullptr), StructClass(InStructClass) {} bool operator==(const FPoolKey& Other) const { return ObjectClass == Other.ObjectClass && StructClass == Other.StructClass; } bool operator!=(const FPoolKey& Other) const { return !(*this == Other); } friend uint32 GetTypeHash(const FPoolKey& Key) { uint32 Hash = 0; if (Key.ObjectClass) { Hash = GetTypeHash(Key.ObjectClass); } else if (Key.StructClass) { Hash = GetTypeHash(Key.StructClass); } return Hash; } }; UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) class YRP_API UObjectPoolManager : public UActorComponent { GENERATED_BODY() public: UObjectPoolManager(); //仅用于创建类对象,不能传入结构体 template <class T, class ... Args> T* GetObject(TSubclassOf<T> ObjectClass, Args&& ... InitialParams); template<typename T, typename... Args> T* GetObject(Args&&... InitialParams); template<typename T> void ReturnObject(T* Object); template<typename T> void ReturnObject(TSubclassOf<T> ObjectClass, T* Object); void SetMaxPoolSize(int32 MaxSize); void SetAutoCleanupInterval(float Interval); template<typename T, typename... Args> void PreloadObjects(int32 Count, Args&&... InitialParams); // 设置初始化回调函数 template<typename T> void SetInitializeCallback(TFunction<void(T*)> Callback); // 设置重置回调函数 template<typename T> void SetResetCallback(TFunction<void(T*)> Callback); void LogPerformanceStats(); protected: virtual void BeginPlay() override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; private: UPROPERTY() TMap<FPoolKey, UObject*> Pools; FCriticalSection PoolMutex; int32 MaxPoolSize; float AutoCleanupInterval; float PoolAdjustInterval; float TimeSinceLastCleanup; float TimeSinceLastPoolAdjust; template<typename T> UObject* GetOrCreatePool(FPoolKey& Key); UObject* GetOrCreatePool(FPoolKey& Key); }; template <typename T, typename ... Args> T* UObjectPoolManager::GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams) { FPoolKey PoolKey(ObjectClass.Get()); if (UObject* Pool = GetOrCreatePool(PoolKey)) { if constexpr (TIsDerivedFrom<T, UObject>::Value) { return Cast<UGenericClassObjectPool>(Pool)->GetObject<T>(ObjectClass, Forward<Args>(InitialParams)...); } } return nullptr; } template <typename T, typename ... Args> T* UObjectPoolManager::GetObject(Args&&... InitialParams) { FPoolKey PoolKey; if( UObject* Pool = GetOrCreatePool<T>(PoolKey)) { if constexpr (TIsDerivedFrom<T, UObject>::Value) { return Cast<UGenericClassObjectPool>(Pool)->GetObject<T>(Forward<Args>(InitialParams)...); } else if (TBaseStructure<T>::Get() != nullptr) { return Cast<UGenericStructObjectPool>(Pool)->GetObject<T>(Forward<Args>(InitialParams)...); } } return nullptr; } template <typename T> void UObjectPoolManager::ReturnObject(T* Object) { if (Object) { FPoolKey PoolKey; PoolMutex.Lock(); if (UObject* Pool = GetOrCreatePool<T>(PoolKey)) { if constexpr (TIsDerivedFrom<T, UObject>::Value) { Cast<UGenericClassObjectPool>(Pool)->ReturnObject(Object); } else if (TBaseStructure<T>::Get() != nullptr) { Cast<UGenericStructObjectPool>(Pool)->ReturnObject(Object); } } PoolMutex.Unlock(); } } template <typename T> void UObjectPoolManager::ReturnObject(TSubclassOf<T> ObjectClass, T* Object) { if (Object) { FPoolKey PoolKey(ObjectClass.Get()); PoolMutex.Lock(); if (UObject* Pool = GetOrCreatePool(PoolKey)) { if constexpr (TIsDerivedFrom<T, UObject>::Value) { Cast<UGenericClassObjectPool>(Pool)->ReturnObject(ObjectClass,Object); } } PoolMutex.Unlock(); } } template <typename T, typename... Args> void UObjectPoolManager::PreloadObjects(int32 Count, Args&&... InitialParams) { FPoolKey PoolKey; if ( UObject* Pool = GetOrCreatePool<T>(PoolKey)) { if constexpr (TIsDerivedFrom<T, UObject>::Value) { Cast<UGenericClassObjectPool>(Pool)->PreloadObjects(Count, Forward<Args>(InitialParams)...); } else if (TBaseStructure<T>::Get() != nullptr) { Cast<UGenericStructObjectPool>(Pool)->PreloadObjects(Count, Forward<Args>(InitialParams)...); } } } template <typename T> void UObjectPoolManager::SetInitializeCallback(TFunction<void(T*)> Callback) { FPoolKey PoolKey; if ( UObject* Pool = GetOrCreatePool<T>(PoolKey)) { if constexpr (TIsDerivedFrom<T, UObject>::Value) { Cast<UGenericClassObjectPool>(Pool)->SetInitializeCallback(Callback); } } } template <typename T> void UObjectPoolManager::SetResetCallback(TFunction<void(T*)> Callback) { FPoolKey PoolKey; if (UObject* Pool = GetOrCreatePool<T>(PoolKey)) { if constexpr (TIsDerivedFrom<T, UObject>::Value) { Cast<UGenericClassObjectPool>(Pool)->SetResetCallback(Callback); } } } template <typename T> UObject* UObjectPoolManager::GetOrCreatePool(FPoolKey& Key) { if constexpr (TIsDerivedFrom<T, UObject>::Value) { Key.ObjectClass = T::StaticClass(); } else if (TBaseStructure<T>::Get() != nullptr) { Key.StructClass = T::StaticStruct(); } PoolMutex.Lock(); if (!Pools.Contains(Key)) { if (Key.ObjectClass) { UGenericClassObjectPool* Pool = NewObject<UGenericClassObjectPool>(this); if (Pool) { Pool->SetMaxPoolSize(MaxPoolSize); Pool->SetAutoCleanupInterval(AutoCleanupInterval); Pools.Add(Key, Pool); } } else if (Key.StructClass) { UGenericStructObjectPool* Pool = NewObject<UGenericStructObjectPool>(this); if (Pool) { Pool->SetMaxPoolSize(MaxPoolSize); Pool->SetAutoCleanupInterval(AutoCleanupInterval); Pools.Add(Key, Pool); } } } UObject* Pool = Pools[Key]; PoolMutex.Unlock(); return Pool; }
ObjectPoolManager.cpp
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "PooledObject.h" #include "UObject/Object.h" #include "GenericClassObjectPool.generated.h" UCLASS() class YRP_API UGenericClassObjectPool : public UObject { GENERATED_BODY() public: friend class UObjectPoolManager; UGenericClassObjectPool(); template <class T, class ... Args> T* GetObject(Args&& ... InitialParams); template<typename T, typename... Args> T* GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams); template<typename T> void ReturnObject(T* Object); template<typename T> void ReturnObject(TSubclassOf<T> ObjectClass, T* Object); void SetMaxPoolSize(int32 MaxSize); void SetAutoCleanupInterval(float Interval); template<typename T, typename... Args> void PreloadObjects(int32 Count, Args&&... InitialParams); // 设置初始化回调函数 template<typename T> void SetInitializeCallback(TFunction<void(T*)> Callback); // 设置重置回调函数 template<typename T> void SetResetCallback(TFunction<void(T*)> Callback); protected: virtual void BeginDestroy() override; TMap<UClass*, TArray<FPooledObject>> PooledObjects; FCriticalSection PoolMutex; int32 MaxPoolSize; float AutoCleanupInterval; float PoolAdjustInterval; float TimeSinceLastCleanup; float TimeSinceLastPoolAdjust; // 初始化回调函数映射 TMap<UClass*, TFunction<void(UObject*)>> InitializeCallbacks; // 重置回调函数映射 TMap<UClass*, TFunction<void(UObject*)>> ResetCallbacks; void ManagePool(); void LogPerformanceStats(); template<typename T, typename... Args> void PreloadObjectsInternal(int32 Count, Args&&... InitialParams); template <class T, class ... Args> T* CreateObject(TSubclassOf<T> ObjectClass, Args&& ... InitialParams); template <class T, class ... Args> T* CreateObject(Args&& ... InitialParams); }; template <typename T, typename... Args> T* UGenericClassObjectPool::GetObject(Args&&... InitialParams) { UClass* ObjectClass = T::StaticClass(); PoolMutex.Lock(); if (PooledObjects.Contains(ObjectClass)) { TArray<FPooledObject>& Objects = PooledObjects[ObjectClass]; for (FPooledObject& PooledObject : Objects) { if (!PooledObject.bIsInUse) { PooledObject.bIsInUse = true; PooledObject.LastUseTime = FDateTime::UtcNow(); T* Object = Cast<T>(PooledObject.Object); if (InitializeCallbacks.Contains(ObjectClass)) { InitializeCallbacks[ObjectClass](Object); } else if (ObjectClass->IsChildOf(AActor::StaticClass())) { // 默认初始化回调函数 AActor* Actor = Cast<AActor>(Object); Actor->SetActorHiddenInGame(false); Actor->SetActorEnableCollision(true); Actor->SetActorTickEnabled(true); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return Object; } } } { T* NewObject = CreateObject<T>(ObjectClass, Forward<Args>(InitialParams)...); const FPooledObject PooledObject = { NewObject, nullptr, true, FDateTime::UtcNow() }; if (!PooledObjects.Contains(ObjectClass)) { PooledObjects.Add(ObjectClass, TArray<FPooledObject>()); } if(PooledObjects[ObjectClass].Num() < MaxPoolSize) { PooledObjects[ObjectClass].Add(PooledObject); } else { PoolMutex.Unlock(); return nullptr; } if (InitializeCallbacks.Contains(ObjectClass)) { InitializeCallbacks[ObjectClass](NewObject); } else if (ObjectClass->IsChildOf(AActor::StaticClass())) { // 默认初始化回调函数 AActor* Actor = Cast<AActor>(NewObject); Actor->SetActorHiddenInGame(false); Actor->SetActorEnableCollision(true); Actor->SetActorTickEnabled(true); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return NewObject; } } template <typename T, typename ... Args> T* UGenericClassObjectPool::GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams) { UClass* Class = ObjectClass.Get(); PoolMutex.Lock(); if (PooledObjects.Contains(Class)) { TArray<FPooledObject>& Objects = PooledObjects[Class]; for (FPooledObject& PooledObject : Objects) { if (!PooledObject.bIsInUse) { PooledObject.bIsInUse = true; PooledObject.LastUseTime = FDateTime::UtcNow(); T* Object = Cast<T>(PooledObject.Object); if (InitializeCallbacks.Contains(Class)) { InitializeCallbacks[Class](Object); } else if (Class->IsChildOf(AActor::StaticClass())) { // 默认初始化回调函数 AActor* Actor = Cast<AActor>(Object); Actor->SetActorHiddenInGame(false); Actor->SetActorEnableCollision(true); Actor->SetActorTickEnabled(true); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return Object; } } } { T* NewObject = CreateObject<T>(ObjectClass, Forward<Args>(InitialParams)...); const FPooledObject PooledObject = { NewObject, nullptr, true, FDateTime::UtcNow() }; if (!PooledObjects.Contains(Class)) { PooledObjects.Add(Class, TArray<FPooledObject>()); } if(PooledObjects[Class].Num() < MaxPoolSize) { PooledObjects[Class].Add(PooledObject); } else { PoolMutex.Unlock(); return nullptr; } if (InitializeCallbacks.Contains(Class)) { InitializeCallbacks[Class](NewObject); } else if (Class->IsChildOf(AActor::StaticClass())) { // 默认初始化回调函数 AActor* Actor = Cast<AActor>(NewObject); Actor->SetActorHiddenInGame(false); Actor->SetActorEnableCollision(true); Actor->SetActorTickEnabled(true); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return NewObject; } } template <typename T> void UGenericClassObjectPool::ReturnObject(T* Object) { if (Object) { const UClass* ObjectClass = T::StaticClass(); PoolMutex.Lock(); if (PooledObjects.Contains(ObjectClass)) { TArray<FPooledObject>& Objects = PooledObjects[ObjectClass]; for (FPooledObject& PooledObject : Objects) { if (PooledObject.Object == Object) { PooledObject.bIsInUse = false; PooledObject.LastUseTime = FDateTime::UtcNow(); if (ResetCallbacks.Contains(ObjectClass)) { ResetCallbacks[ObjectClass](Object); } else if (ObjectClass->IsChildOf(AActor::StaticClass())) { // 默认重置回调函数 AActor* Actor = Cast<AActor>(Object); Actor->SetActorHiddenInGame(true); Actor->SetActorEnableCollision(false); Actor->SetActorTickEnabled(false); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return; } } } PoolMutex.Unlock(); } } template <typename T> void UGenericClassObjectPool::ReturnObject(TSubclassOf<T> ObjectClass, T* Object) { if (Object) { UClass* tObject = ObjectClass.Get(); PoolMutex.Lock(); if (PooledObjects.Contains(tObject)) { TArray<FPooledObject>& Objects = PooledObjects[tObject]; for (FPooledObject& PooledObject : Objects) { if (PooledObject.Object == Object) { PooledObject.bIsInUse = false; PooledObject.LastUseTime = FDateTime::UtcNow(); if (ResetCallbacks.Contains(tObject)) { ResetCallbacks[tObject](Object); } else if (tObject->IsChildOf(AActor::StaticClass())) { // 默认重置回调函数 AActor* Actor = Cast<AActor>(Object); Actor->SetActorHiddenInGame(true); Actor->SetActorEnableCollision(false); Actor->SetActorTickEnabled(false); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return; } } } PoolMutex.Unlock(); } } template <typename T, typename... Args> void UGenericClassObjectPool::PreloadObjects(int32 Count, Args&&... InitialParams) { PreloadObjectsInternal<T>(Count, Forward<Args>(InitialParams)...); } template <typename T> void UGenericClassObjectPool::SetInitializeCallback(TFunction<void(T*)> Callback) { UClass* ObjectClass = T::StaticClass(); InitializeCallbacks.Add(ObjectClass, [Callback](UObject* Object) { Callback(Cast<T>(Object)); }); } template <typename T> void UGenericClassObjectPool::SetResetCallback(TFunction<void(T*)> Callback) { UClass* ObjectClass = T::StaticClass(); ResetCallbacks.Add(ObjectClass, [Callback](UObject* Object) { Callback(Cast<T>(Object)); }); } template <typename T, typename... Args> void UGenericClassObjectPool::PreloadObjectsInternal(int32 Count, Args&&... InitialParams) { UClass* ObjectClass = T::StaticClass(); PoolMutex.Lock(); if (!PooledObjects.Contains(ObjectClass)) { PooledObjects.Add(ObjectClass, TArray<FPooledObject>()); } TArray<FPooledObject>& Objects = PooledObjects[ObjectClass]; for (int32 i = 0; i < Count; ++i) { T* NewObject = CreateObject<T>(Forward<Args>(InitialParams)...); FPooledObject PooledObject = { NewObject, nullptr, false, FDateTime::UtcNow() }; Objects.Add(PooledObject); } PoolMutex.Unlock(); } template <typename T, typename... Args> T* UGenericClassObjectPool::CreateObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams) { UClass* Class = ObjectClass.Get(); if (Class->IsChildOf(AActor::StaticClass())) { UWorld* World = GetWorld(); if (World) { return World->SpawnActor<T>(ObjectClass, Forward<Args>(InitialParams)...); } } else { return NewObject<T>(GetOuter(), ObjectClass, Forward<Args>(InitialParams)...); } return nullptr; } template <typename T, typename... Args> T* UGenericClassObjectPool::CreateObject(Args&&... InitialParams) { UClass* Class = T::StaticClass(); if (Class->IsChildOf(AActor::StaticClass())) { UWorld* World = GetWorld(); if (World) { return World->SpawnActor<T>(Forward<Args>(InitialParams)...); } } else { T* NewObj = NewObject<T>(GetOuter(), Forward<Args>(InitialParams)...); return NewObj; } return nullptr; }
GenericClassObjectPool.h泛型类对象池
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "PooledObject.h" #include "UObject/Object.h" #include "GenericClassObjectPool.generated.h" UCLASS() class YRP_API UGenericClassObjectPool : public UObject { GENERATED_BODY() public: friend class UObjectPoolManager; UGenericClassObjectPool(); template <class T, class ... Args> T* GetObject(Args&& ... InitialParams); template<typename T, typename... Args> T* GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams); template<typename T> void ReturnObject(T* Object); template<typename T> void ReturnObject(TSubclassOf<T> ObjectClass, T* Object); void SetMaxPoolSize(int32 MaxSize); void SetAutoCleanupInterval(float Interval); template<typename T, typename... Args> void PreloadObjects(int32 Count, Args&&... InitialParams); // 设置初始化回调函数 template<typename T> void SetInitializeCallback(TFunction<void(T*)> Callback); // 设置重置回调函数 template<typename T> void SetResetCallback(TFunction<void(T*)> Callback); protected: virtual void BeginDestroy() override; TMap<UClass*, TArray<FPooledObject>> PooledObjects; FCriticalSection PoolMutex; int32 MaxPoolSize; float AutoCleanupInterval; float PoolAdjustInterval; float TimeSinceLastCleanup; float TimeSinceLastPoolAdjust; // 初始化回调函数映射 TMap<UClass*, TFunction<void(UObject*)>> InitializeCallbacks; // 重置回调函数映射 TMap<UClass*, TFunction<void(UObject*)>> ResetCallbacks; void ManagePool(); void LogPerformanceStats(); template<typename T, typename... Args> void PreloadObjectsInternal(int32 Count, Args&&... InitialParams); template <class T, class ... Args> T* CreateObject(TSubclassOf<T> ObjectClass, Args&& ... InitialParams); template <class T, class ... Args> T* CreateObject(Args&& ... InitialParams); }; template <typename T, typename... Args> T* UGenericClassObjectPool::GetObject(Args&&... InitialParams) { UClass* ObjectClass = T::StaticClass(); PoolMutex.Lock(); if (PooledObjects.Contains(ObjectClass)) { TArray<FPooledObject>& Objects = PooledObjects[ObjectClass]; for (FPooledObject& PooledObject : Objects) { if (!PooledObject.bIsInUse) { PooledObject.bIsInUse = true; PooledObject.LastUseTime = FDateTime::UtcNow(); T* Object = Cast<T>(PooledObject.Object); if (InitializeCallbacks.Contains(ObjectClass)) { InitializeCallbacks[ObjectClass](Object); } else if (ObjectClass->IsChildOf(AActor::StaticClass())) { // 默认初始化回调函数 AActor* Actor = Cast<AActor>(Object); Actor->SetActorHiddenInGame(false); Actor->SetActorEnableCollision(true); Actor->SetActorTickEnabled(true); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return Object; } } } { T* NewObject = CreateObject<T>(ObjectClass, Forward<Args>(InitialParams)...); const FPooledObject PooledObject = { NewObject, nullptr, true, FDateTime::UtcNow() }; if (!PooledObjects.Contains(ObjectClass)) { PooledObjects.Add(ObjectClass, TArray<FPooledObject>()); } if(PooledObjects[ObjectClass].Num() < MaxPoolSize) { PooledObjects[ObjectClass].Add(PooledObject); } else { PoolMutex.Unlock(); return nullptr; } if (InitializeCallbacks.Contains(ObjectClass)) { InitializeCallbacks[ObjectClass](NewObject); } else if (ObjectClass->IsChildOf(AActor::StaticClass())) { // 默认初始化回调函数 AActor* Actor = Cast<AActor>(NewObject); Actor->SetActorHiddenInGame(false); Actor->SetActorEnableCollision(true); Actor->SetActorTickEnabled(true); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return NewObject; } } template <typename T, typename ... Args> T* UGenericClassObjectPool::GetObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams) { UClass* Class = ObjectClass.Get(); PoolMutex.Lock(); if (PooledObjects.Contains(Class)) { TArray<FPooledObject>& Objects = PooledObjects[Class]; for (FPooledObject& PooledObject : Objects) { if (!PooledObject.bIsInUse) { PooledObject.bIsInUse = true; PooledObject.LastUseTime = FDateTime::UtcNow(); T* Object = Cast<T>(PooledObject.Object); if (InitializeCallbacks.Contains(Class)) { InitializeCallbacks[Class](Object); } else if (Class->IsChildOf(AActor::StaticClass())) { // 默认初始化回调函数 AActor* Actor = Cast<AActor>(Object); Actor->SetActorHiddenInGame(false); Actor->SetActorEnableCollision(true); Actor->SetActorTickEnabled(true); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return Object; } } } { T* NewObject = CreateObject<T>(ObjectClass, Forward<Args>(InitialParams)...); const FPooledObject PooledObject = { NewObject, nullptr, true, FDateTime::UtcNow() }; if (!PooledObjects.Contains(Class)) { PooledObjects.Add(Class, TArray<FPooledObject>()); } if(PooledObjects[Class].Num() < MaxPoolSize) { PooledObjects[Class].Add(PooledObject); } else { PoolMutex.Unlock(); return nullptr; } if (InitializeCallbacks.Contains(Class)) { InitializeCallbacks[Class](NewObject); } else if (Class->IsChildOf(AActor::StaticClass())) { // 默认初始化回调函数 AActor* Actor = Cast<AActor>(NewObject); Actor->SetActorHiddenInGame(false); Actor->SetActorEnableCollision(true); Actor->SetActorTickEnabled(true); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return NewObject; } } template <typename T> void UGenericClassObjectPool::ReturnObject(T* Object) { if (Object) { const UClass* ObjectClass = T::StaticClass(); PoolMutex.Lock(); if (PooledObjects.Contains(ObjectClass)) { TArray<FPooledObject>& Objects = PooledObjects[ObjectClass]; for (FPooledObject& PooledObject : Objects) { if (PooledObject.Object == Object) { PooledObject.bIsInUse = false; PooledObject.LastUseTime = FDateTime::UtcNow(); if (ResetCallbacks.Contains(ObjectClass)) { ResetCallbacks[ObjectClass](Object); } else if (ObjectClass->IsChildOf(AActor::StaticClass())) { // 默认重置回调函数 AActor* Actor = Cast<AActor>(Object); Actor->SetActorHiddenInGame(true); Actor->SetActorEnableCollision(false); Actor->SetActorTickEnabled(false); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return; } } } PoolMutex.Unlock(); } } template <typename T> void UGenericClassObjectPool::ReturnObject(TSubclassOf<T> ObjectClass, T* Object) { if (Object) { UClass* tObject = ObjectClass.Get(); PoolMutex.Lock(); if (PooledObjects.Contains(tObject)) { TArray<FPooledObject>& Objects = PooledObjects[tObject]; for (FPooledObject& PooledObject : Objects) { if (PooledObject.Object == Object) { PooledObject.bIsInUse = false; PooledObject.LastUseTime = FDateTime::UtcNow(); if (ResetCallbacks.Contains(tObject)) { ResetCallbacks[tObject](Object); } else if (tObject->IsChildOf(AActor::StaticClass())) { // 默认重置回调函数 AActor* Actor = Cast<AActor>(Object); Actor->SetActorHiddenInGame(true); Actor->SetActorEnableCollision(false); Actor->SetActorTickEnabled(false); Actor->SetActorLocation(FVector::ZeroVector); Actor->SetActorRotation(FRotator::ZeroRotator); } PoolMutex.Unlock(); return; } } } PoolMutex.Unlock(); } } template <typename T, typename... Args> void UGenericClassObjectPool::PreloadObjects(int32 Count, Args&&... InitialParams) { PreloadObjectsInternal<T>(Count, Forward<Args>(InitialParams)...); } template <typename T> void UGenericClassObjectPool::SetInitializeCallback(TFunction<void(T*)> Callback) { UClass* ObjectClass = T::StaticClass(); InitializeCallbacks.Add(ObjectClass, [Callback](UObject* Object) { Callback(Cast<T>(Object)); }); } template <typename T> void UGenericClassObjectPool::SetResetCallback(TFunction<void(T*)> Callback) { UClass* ObjectClass = T::StaticClass(); ResetCallbacks.Add(ObjectClass, [Callback](UObject* Object) { Callback(Cast<T>(Object)); }); } template <typename T, typename... Args> void UGenericClassObjectPool::PreloadObjectsInternal(int32 Count, Args&&... InitialParams) { UClass* ObjectClass = T::StaticClass(); PoolMutex.Lock(); if (!PooledObjects.Contains(ObjectClass)) { PooledObjects.Add(ObjectClass, TArray<FPooledObject>()); } TArray<FPooledObject>& Objects = PooledObjects[ObjectClass]; for (int32 i = 0; i < Count; ++i) { T* NewObject = CreateObject<T>(Forward<Args>(InitialParams)...); FPooledObject PooledObject = { NewObject, nullptr, false, FDateTime::UtcNow() }; Objects.Add(PooledObject); } PoolMutex.Unlock(); } template <typename T, typename... Args> T* UGenericClassObjectPool::CreateObject(TSubclassOf<T> ObjectClass, Args&&... InitialParams) { UClass* Class = ObjectClass.Get(); if (Class->IsChildOf(AActor::StaticClass())) { UWorld* World = GetWorld(); if (World) { return World->SpawnActor<T>(ObjectClass, Forward<Args>(InitialParams)...); } } else { return NewObject<T>(GetOuter(), ObjectClass, Forward<Args>(InitialParams)...); } return nullptr; } template <typename T, typename... Args> T* UGenericClassObjectPool::CreateObject(Args&&... InitialParams) { UClass* Class = T::StaticClass(); if (Class->IsChildOf(AActor::StaticClass())) { UWorld* World = GetWorld(); if (World) { return World->SpawnActor<T>(Forward<Args>(InitialParams)...); } } else { T* NewObj = NewObject<T>(GetOuter(), Forward<Args>(InitialParams)...); return NewObj; } return nullptr; }
GenericClassObjectPool.cpp
#include "GenericClassObjectPool.h" UGenericClassObjectPool::UGenericClassObjectPool() { MaxPoolSize = 100; AutoCleanupInterval = 60.0f; // 每60秒清理一次 PoolAdjustInterval = 5.0f; // 每5秒调整一次池大小 TimeSinceLastCleanup = 0.0f; } void UGenericClassObjectPool::BeginDestroy() { Super::BeginDestroy(); for (auto& Entry : PooledObjects) { for (FPooledObject& PooledObject : Entry.Value) { if(PooledObject.Object) { if (AActor* actor= Cast<AActor>(PooledObject.Object) ) { actor->Destroy(); }else if(UActorComponent* actorComponent= Cast<UActorComponent>(PooledObject.Object)) { actorComponent->DestroyComponent(); } else { PooledObject.Object->ConditionalBeginDestroy(); } } } } PooledObjects.Empty(); } void UGenericClassObjectPool::SetMaxPoolSize(int32 MaxSize) { MaxPoolSize = MaxSize; } void UGenericClassObjectPool::SetAutoCleanupInterval(float Interval) { AutoCleanupInterval = Interval; } void UGenericClassObjectPool::ManagePool() { PoolMutex.Lock(); for (auto& Entry : PooledObjects) { UClass* ObjectClass = Entry.Key; TArray<FPooledObject>& Objects = Entry.Value; int32 InUseCount = 0; for (int32 i = Objects.Num() - 1; i >= 0; --i) { if (Objects[i].bIsInUse) { InUseCount++; } else if ((FDateTime::UtcNow() - Objects[i].LastUseTime).GetTotalSeconds() > AutoCleanupInterval) { Objects[i].Object->ConditionalBeginDestroy(); Objects.RemoveAt(i); } } int32 TargetSize = FMath::Clamp(InUseCount * 2, 10, MaxPoolSize); if (Objects.Num() > TargetSize) { // 释放多余的对象 for (int32 i = Objects.Num() - 1; i >= TargetSize; --i) { if (!Objects[i].bIsInUse) { Objects[i].Object->ConditionalBeginDestroy(); Objects.RemoveAt(i); } } } } PoolMutex.Unlock(); } void UGenericClassObjectPool::LogPerformanceStats() { // 记录性能统计数据 for (auto& Entry : PooledObjects) { TSubclassOf<UObject> ObjectClass = Entry.Key; TArray<FPooledObject>& Objects = Entry.Value; int32 InUseCount = 0; for (const FPooledObject& PooledObject : Objects) { if (PooledObject.bIsInUse) { InUseCount++; } } UE_LOG(LogTemp, Display, TEXT("ObjectPool: Class %s, Total: %d, InUse: %d"), *ObjectClass->GetName(), Objects.Num(), InUseCount); } }
GenericStructObjectPool.h泛型结构体对象池
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "PooledObject.h" #include "UObject/Object.h" #include "GenericStructObjectPool.generated.h" UCLASS() class YRP_API UGenericStructObjectPool : public UObject { GENERATED_BODY() public: friend class UObjectPoolManager; UGenericStructObjectPool(); template<typename T, typename... Args> T* GetObject(Args&&... InitialParams); template<typename T> void ReturnObject(T* Object); void SetMaxPoolSize(int32 MaxSize); void SetAutoCleanupInterval(float Interval); template<typename T, typename... Args> void PreloadObjects(int32 Count, Args&&... InitialParams); protected: virtual void BeginDestroy() override; private: TMap<UScriptStruct*, TArray<FPooledObject>> PooledStructs; FCriticalSection PoolMutex; int32 MaxPoolSize; float AutoCleanupInterval; float PoolAdjustInterval; float TimeSinceLastCleanup; float TimeSinceLastPoolAdjust; template<typename T, typename... Args> T* CreateObject(Args&&... InitialParams); void ManagePool(); void LogPerformanceStats(); template<typename T, typename... Args> void PreloadObjectsInternal(int32 Count, Args&&... InitialParams); }; template <typename T, typename... Args> T* UGenericStructObjectPool::GetObject(Args&&... InitialParams) { UScriptStruct* StructClass = TBaseStructure<T>::Get(); PoolMutex.Lock(); if (PooledStructs.Contains(StructClass)) { TArray<FPooledObject>& Objects = PooledStructs[StructClass]; for (FPooledObject& PooledObject : Objects) { if (!PooledObject.bIsInUse) { PooledObject.bIsInUse = true; PooledObject.LastUseTime = FDateTime::UtcNow(); T* Object = (T*)PooledObject.StructData.Get(); *Object = T(Forward<Args>(InitialParams)...); // 使用初始参数 PoolMutex.Unlock(); return Object; } } } { T* NewObject = CreateObject<T>(Forward<Args>(InitialParams)...); const FPooledObject PooledObject = { nullptr, TSharedPtr<void>(NewObject), true, FDateTime::UtcNow() }; if(!PooledStructs.Contains(StructClass)) { PooledStructs.Add(StructClass, TArray<FPooledObject>()); } if (PooledStructs[StructClass].Num() < MaxPoolSize) { PooledStructs[StructClass].Add(PooledObject); } else { PoolMutex.Unlock();return nullptr; } PoolMutex.Unlock();return NewObject; } } template <typename T> void UGenericStructObjectPool::ReturnObject(T* Object) { if (Object) { const UScriptStruct* StructClass = TBaseStructure<T>::Get(); PoolMutex.Lock(); if (PooledStructs.Contains(StructClass)) { TArray<FPooledObject>& Objects = PooledStructs[StructClass]; for (FPooledObject& PooledObject : Objects) { if (PooledObject.StructData.Get() == Object) { PooledObject.bIsInUse = false; PooledObject.LastUseTime = FDateTime::UtcNow(); PoolMutex.Unlock(); return; } } } PoolMutex.Unlock(); } } template <typename T, typename... Args> void UGenericStructObjectPool::PreloadObjects(int32 Count, Args&&... InitialParams) { PreloadObjectsInternal<T>(Count, Forward<Args>(InitialParams)...); } template <typename T, typename... Args> T* UGenericStructObjectPool::CreateObject(Args&&... InitialParams) { T* NewObject = (T*)FMemory::Malloc(sizeof(T)); new (NewObject) T(Forward<Args>(InitialParams)...); return NewObject; } template <typename T, typename... Args> void UGenericStructObjectPool::PreloadObjectsInternal(int32 Count, Args&&... InitialParams) { UScriptStruct* StructClass = TBaseStructure<T>::Get(); PoolMutex.Lock(); if (!PooledStructs.Contains(StructClass)) { PooledStructs.Add(StructClass, TArray<FPooledObject>()); } TArray<FPooledObject>& Objects = PooledStructs[StructClass]; for (int32 i = 0; i < Count; ++i) { T* NewObject = CreateObject<T>(Forward<Args>(InitialParams)...); FPooledObject PooledObject = { nullptr, TSharedPtr<void>(NewObject), false, FDateTime::UtcNow() }; Objects.Add(PooledObject); } PoolMutex.Unlock(); }
GenericStructObjectPool.cpp
#include "GenericStructObjectPool.h" UGenericStructObjectPool::UGenericStructObjectPool() { MaxPoolSize = 100; AutoCleanupInterval = 60.0f; // 每60秒清理一次 PoolAdjustInterval = 5.0f; // 每5秒调整一次池大小 TimeSinceLastCleanup = 0.0f; } void UGenericStructObjectPool::BeginDestroy() { Super::BeginDestroy(); PooledStructs.Empty(); } void UGenericStructObjectPool::SetMaxPoolSize(int32 MaxSize) { MaxPoolSize = MaxSize; } void UGenericStructObjectPool::SetAutoCleanupInterval(float Interval) { AutoCleanupInterval = Interval; } void UGenericStructObjectPool::ManagePool() { PoolMutex.Lock(); for (auto& Entry : PooledStructs) { UScriptStruct* StructClass = Entry.Key; TArray<FPooledObject>& Objects = Entry.Value; int32 InUseCount = 0; for (int32 i = Objects.Num() - 1; i >= 0; --i) { if (Objects[i].bIsInUse) { InUseCount++; } else if ((FDateTime::UtcNow() - Objects[i].LastUseTime).GetTotalSeconds() > AutoCleanupInterval) { FMemory::Free(Objects[i].StructData.Get()); Objects.RemoveAt(i); } } int32 TargetSize = FMath::Clamp(InUseCount * 2, 10, MaxPoolSize); if (Objects.Num() > TargetSize) { // 释放多余的对象 for (int32 i = Objects.Num() - 1; i >= TargetSize; --i) { if (!Objects[i].bIsInUse) { FMemory::Free(Objects[i].StructData.Get()); Objects.RemoveAt(i); } } } } PoolMutex.Unlock(); } void UGenericStructObjectPool::LogPerformanceStats() { // 记录性能统计数据 for (auto& Entry : PooledStructs) { UScriptStruct* StructClass = Entry.Key; TArray<FPooledObject>& Objects = Entry.Value; int32 InUseCount = 0; for (const FPooledObject& PooledObject : Objects) { if (PooledObject.bIsInUse) { InUseCount++; } } UE_LOG(LogTemp, Display, TEXT("ObjectPool: Struct %s, Total: %d, InUse: %d"), *StructClass->GetName(), Objects.Num(), InUseCount); } }
标签:PooledObject,对象,void,Object,Actor,ObjectClass,template,UE From: https://www.cnblogs.com/zjr0/p/18338364