일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- animation
- gas
- gameplay effect
- nanite
- unity
- MAC
- 게임 개발
- Unreal Engine
- stride
- os
- Aegis
- 보안
- listen server
- rpc
- 유니티
- network object pooling
- gameplay tag
- UI
- Multiplay
- attribute
- map design
- CTF
- 언리얼 엔진
- 언리얼엔진
- 게임개발
- gameplay ability system
- photon fusion2
- ability task
- Replication
- local prediction
Archives
- Today
- Total
Replicated
** [Drag Down] Network Object Pooling (Subsystem + Interface + GameMode + DataAsset) ** 본문
언리얼 엔진/Drag Down
** [Drag Down] Network Object Pooling (Subsystem + Interface + GameMode + DataAsset) **
라구넹 2025. 4. 16. 18:22생각나는 구현 방법은 세가지
- 액터 기반
- 게임인스턴스 서브시스템 기반
- 월드 서브시스템 기반
액터 기반 -> 전역 풀 매니저인데 액터보단 서브시스템 기반이 더 적절. 레벨마다 액터 가져다 놓기도 좀 별로다
게임인스턴스 서브시스템 기반 -> 게임 내내 유지되어서 메모리 낭비가 있을 듯 함
월드 서브시스템 기반 -> 월드마다 원하는 풀링 오브젝트 초기화 시킬 수 있으니 메모리 낭비도 없고 좋은듯?
=> WorldSubsystem 기반으로 결정
최대한 확장성을 고려했고, 데이터 기반으로 개발하고자 했다
DataAsset 기반의 PooledObjectData의 BP를 GameMode가 읽어서 풀링 초기화
그 이후 다른 오브젝트들이 알아서 서브시스템에서 Get, Return하도록 한다
게임 모드도 BP라서 그냥 PooledObjectData만 갈아끼우면 월드마다 풀링 다르게되게 가능
단, 어쩔 수 없는 의존성이 하나 생긴다
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "DDPoolable.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UDDPoolable : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class DRAGDOWN_API IDDPoolable
{
GENERATED_BODY()
public:
/**
* Usage:
* void ClassName::OnRetrievedFromPool()
{
if ( HasAuthority() )
{
~~~ Timer Setting (if need) ~~~, timer needs to be activated in server, not client
NetMulticastOnRetrievedFromPool(GetActorLocation(), GetActorRotation()); // for multi sync
}
}
void ClassName::NetMulticastOnRetrievedFromPool_Implementation(FVector NewLocation, FRotator NewRotation)
{
~~~ Specific Setting (if need) ~~~
SetActorHiddenInGame(false);
SetActorEnableCollision(true);
SetActorTickEnabled(true);
SetActorLocationAndRotation(NewLocation, NewRotation);
}
*/
virtual void OnRetrievedFromPool() = 0;
/*
* void ClassName::OnReturnedToPool()
{
if ( HasAuthority() )
{
NetMulticastOnReturnedToPool(); // for multi sync
}
}
void ClassName::NetMulticastOnReturnedToPool_Implementation()
{
SetActorHiddenInGame(true);
SetActorEnableCollision(false);
SetActorTickEnabled(false);
}
*/
virtual void OnReturnedToPool() = 0;
};
서브시스템은 RPC가 없다
즉, 개별 액터에게 알아서 풀링 상태 관리를 맡겨야 한다
그렇기에 일단 풀 매니저는 인터페이스 IPoolable만 알면 되도록해서 최대한 분리하고,
사용 방법을 주석으로 적어두었다
// Fill out your copyright notice in the Description page of Project Settings.
#include "Actor/DDBulletBase.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Components/SphereComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Physics/DDCollision.h"
#include "GameFramework/Character.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Subsystem/DDNetworkObjectPoolingSubsystem.h"
#include "DragDown.h"
ADDBulletBase::ADDBulletBase()
{
bReplicates = true;
Trigger = CreateDefaultSubobject<USphereComponent>(TEXT("Trigger"));
Trigger->InitSphereRadius(5.0f);
Trigger->SetCollisionProfileName(CPROFILE_DDTRIGGER);
RootComponent = Trigger;
Trigger->OnComponentBeginOverlap.AddDynamic(this, &ADDBulletBase::OnComponentBeginOverlapCallback);
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComp"));
StaticMeshComp->SetupAttachment(RootComponent);
StaticMeshComp->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
StaticMeshComp->SetCollisionEnabled(ECollisionEnabled::NoCollision);
Movement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Movement"));
Movement->InitialSpeed = 3000.0f;
Movement->MaxSpeed = 3000.0f;
Movement->bRotationFollowsVelocity = true;
Movement->bShouldBounce = false;
Movement->ProjectileGravityScale = 0.0f;
Power = 3000.0f;
BulletLivingTime = 1.0f;
}
void ADDBulletBase::OnComponentBeginOverlapCallback(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepHitResult)
{
if ( HasAuthority() )
{
ACharacter* Character = Cast<ACharacter>(OtherActor);
if (Character)
{
PushCharacter(Cast<ACharacter>(OtherActor));
}
}
}
void ADDBulletBase::PushCharacter(ACharacter* Character)
{
if ( Character && Character->GetCharacterMovement() )
{
FVector Dir = GetActorForwardVector();
Character->LaunchCharacter(Dir * Power, true, true);
}
}
void ADDBulletBase::OnRetrievedFromPool()
{
if ( HasAuthority() )
{
GetWorld()->GetTimerManager().SetTimer(PoolingTimer, this, &ADDBulletBase::PoolBullet, BulletLivingTime, false);
NetMulticastOnRetrievedFromPool(GetActorLocation(), GetActorRotation());
}
}
void ADDBulletBase::OnReturnedToPool()
{
if ( HasAuthority() )
{
NetMulticastOnReturnedToPool();
}
}
void ADDBulletBase::NetMulticastOnRetrievedFromPool_Implementation(FVector NewLocation, FRotator NewRotation)
{
if (Movement)
{
Movement->StopMovementImmediately();
Movement->Velocity = GetActorForwardVector() * Movement->InitialSpeed;
}
SetActorHiddenInGame(false);
SetActorEnableCollision(true);
SetActorTickEnabled(true);
SetActorLocationAndRotation(NewLocation, NewRotation);
}
void ADDBulletBase::NetMulticastOnReturnedToPool_Implementation()
{
if ( Movement )
{
Movement->StopMovementImmediately();
Movement->Velocity = FVector();
}
SetActorHiddenInGame(true);
SetActorEnableCollision(false);
SetActorTickEnabled(false);
}
void ADDBulletBase::PoolBullet()
{
UDDNetworkObjectPoolingSubsystem* ObjectPool = GetWorld()->GetSubsystem<UDDNetworkObjectPoolingSubsystem>();
if (ObjectPool)
{
ObjectPool->ReturnPooledObject(Cast<AActor>(this));
}
}
void ADDBulletBase::FellOutOfWorld(const UDamageType& dmgType)
{
PoolBullet();
}
예시로 풀링되는 오브젝트는 이렇게 구현 가능하다
void ADDBulletBase::PoolBullet()
{
UDDNetworkObjectPoolingSubsystem* ObjectPool = GetWorld()->GetSubsystem<UDDNetworkObjectPoolingSubsystem>();
if (ObjectPool)
{
ObjectPool->ReturnPooledObject(Cast<AActor>(this));
}
}
풀에 넣는 건 ReturnPooledObject 호출
void ADDPeriodicSpawner::Spawn()
{
FVector SpawnLocation = GetActorLocation();
SpawnLocation.Z += Offset;
FRotator SpawnRotation = SpawningRot;
if ( GetWorld() )
{
UDDNetworkObjectPoolingSubsystem* PoolingSystem = GetWorld()->GetSubsystem<UDDNetworkObjectPoolingSubsystem>();
PoolingSystem->GetPooledObject(ActorClass, SpawnLocation, SpawnRotation);
}
}
풀에서 꺼내는 건 그냥 GetPooledObject만 해주면 된다
이제 다음부턴 여기서만 관리하면 된다
'언리얼 엔진 > Drag Down' 카테고리의 다른 글
[Drag Down] 미끄러지는 길 (Physical Material + Surface type + Data Asset) (0) | 2025.04.17 |
---|---|
** [Drag Down] Performance Enhancement of Network Object Pooling ** (0) | 2025.04.16 |
[Drag Down] 눈발사대 눈사람(주기적 발사 장애물) (0) | 2025.04.14 |
[Drag Down] Spring Boot 서버와 연동 - register/login (0) | 2025.04.14 |
[Drag Down] 기본 캐릭터 디자인 (0) | 2025.04.13 |