오브젝트 풀링

끄적끄적·2025년 4월 11일

오브젝트 풀링이란?

액터를 매번 SpawnActor/Destroy 하지 않고

미리 생성해둔 객체들을 재활용(Reuse) 하는 방식

성능 이득: GC 감소, 메모리 할당 최소화, 프레임 드랍 방지

기본 개념 흐름

풀 생성: 시작할 때 액터를 N개 미리 생성해 비활성화 상태로 저장

요청 시 꺼냄: 필요한 순간에 활성화하고, 위치/상태 초기화

사용 후 반환: 다 쓰면 다시 비활성화하고 풀에 되돌림

간단 예제: 총알 풀링

  1. 풀링 가능한 액터 클래스 예시 (ABullet)
UCLASS()
class ABullet : public AActor
{
	GENERATED_BODY()

public:
	void ActivateBullet(FVector Location);
	void DeactivateBullet();
};
  1. 오브젝트 풀 매니저 클래스
UCLASS()
class ABulletPoolManager : public AActor
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere)
	TSubclassOf<ABullet> BulletClass;

	UPROPERTY(EditAnywhere)
	int32 PoolSize = 20;

	TArray<ABullet*> BulletPool;

	virtual void BeginPlay() override;

	ABullet* GetBullet();
	void ReturnBullet(ABullet* Bullet);
};
  1. 초기화 & 꺼내기
void ABulletPoolManager::BeginPlay()
{
	Super::BeginPlay();

	for (int32 i = 0; i < PoolSize; ++i)
	{
		ABullet* Bullet = GetWorld()->SpawnActor<ABullet>(BulletClass, FVector::ZeroVector, FRotator::ZeroRotator);
		Bullet->DeactivateBullet();
		BulletPool.Add(Bullet);
	}
}

ABullet* ABulletPoolManager::GetBullet()
{
	for (ABullet* Bullet : BulletPool)
	{
		if (!Bullet->IsActorTickEnabled()) // 간단한 비활성화 체크
		{
			Bullet->ActivateBullet(SomeSpawnLocation);
			return Bullet;
		}
	}
	return nullptr; // 풀에 남은게 없을 경우
}
  1. 되돌리기
void ABulletPoolManager::ReturnBullet(ABullet* Bullet)
{
	if (Bullet)
	{
		Bullet->DeactivateBullet();
	}
}

사용처

총알, 이펙트, 파편 등 성능 이슈 많은 액터에 적극 사용

GC 호출 횟수도 줄어들어 런타임 성능 향상

TQueue, TArray, TObjectPtr 등으로 풀 구조 다양하게 가능

나이아가라 파티클도 Deactivate() & Activate()로 재활용 가능함

풀링이 필요하지 않은 경우

맵에 몇 개만 존재하고

자주 파괴되지 않거나, 재사용 빈도가 낮은 경우

예: 맵에 고정된 상자, 유니크한 무기 드롭 등

이런 경우엔 그냥 SpawnActor로 생성하고 Destroy()로 제거해도 충분. 오히려 풀링은 오버킬일 수 있다.

풀링이 유용한 경우

  • 초당 여러 개 생성/삭제 ->> 총알, 폭발, 이펙트, 타격 이펙트

  • 여러 번 재사용됨 ->> 몬스터 리스폰, 수류탄

  • 짧은 시간 안에 많이 생성됨 ->> UI 팝업, 데미지 텍스트, 파티클

0개의 댓글