이번 시간에는 몬스터를 스폰하는 기능을 구현할 것이다. 이때 메모리 최적화를 위해 유니티에 있는 개념인 pool을 쓸 계획이다.
메모리를 제거하고 생성하는 과정이 메모리소모와 시간이 많이 걸려 그거를 보완하고자 만든 개념이다. 미리 오브젝트를 max로 만들고 일부로 안보이게 해서 spawn을 하면 그 pool에 있는 오브젝트 중 하나를 보이게 하는 것이다. 만약 몬스터가 죽는다면 destory하는 게 아닌 시각적으로 안보이게 한다. 이런 방식으로 시간과 메모리 소모를 막는 방법이라고 보면 된다.
나는 pool을 놓을 위치를 gamemode로 정했다. 이후 pool에 쓸 배열 자료구조는 TArray로 선택했다. 원래 C++이라면 vector가 적합하지만 언리얼에서는 따로 TArray 자료클래스가 존재하는 거 같았다.
SpawnActor를 쓰면 된다.
GetWorld()->SpawnActor<생성할클래스>(BP_생성할클래스?,위치,회전, param)
참고로 초반에 액터를 생성할때 같은 위치에 스폰하면 생성이 안되는 경우가 있다.
그래서 나는 파라미터를 수정할 것이다.
FVector SpawnLocation = FVector(100, 0, 50);
FRotator SpawnRotation = FRotator::ZeroRotator;
// SpawnParameters 설정 => 같은 position이 있어도 충돌되지않고 스폰됨
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
// Enemy 스폰
AEnemy* newEnemy = GetWorld()->SpawnActor<AEnemy>(
EnemyClass,
FVector(100, 0, 50),
SpawnRotation,
SpawnParams
);
근데 SpawnActor를 쓰면 AIController가 없다.
그래서 따로 AIController를 넣어줘야 한다.
SpawnDefaultController(); //강제 호출
유니티에서는 SetActive() 함수인걸로 아는데
언리얼에서는 무슨 함수일까?
NewEnemy->SetActorHiddenInGame(true); 이거 쓰면 된다.
//.h
TArray<AEnemy*> enemyPool;
TArray<AActor*> coinPool;
public:
UPROPERTY(EditDefaultsOnly, Category = "Coin")
TSubclassOf<AActor> CoinClass;
기본적으로 GetRandomReachablePointInRadius함수를 써서 주변에 적이나 코인같은 오브젝트의 위치를 만들어준다.
주의 원 둘레로 nav가 가능한 지형에만 스폰한다.
void AZombieSlayerGameMode::initEnemy()
{
FVector SpawnLocation = FVector(100, 0, 50);
FRotator SpawnRotation = FRotator::ZeroRotator;
// SpawnParameters 설정
FActorSpawnParameters spawnParams;
spawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
// Enemy 스폰
AEnemy* newEnemy = GetWorld()->SpawnActor<AEnemy>(
EnemyClass,
FVector(100, 0, 50),
SpawnRotation,
spawnParams
);
if (newEnemy)
{
enemyPool.Add(newEnemy); // 풀에 추가
newEnemy->SetActorHiddenInGame(true); // 비활성화
}
else {
}
}
void AZombieSlayerGameMode::SpawnEnemy()
{
if (MAX_ENEMY_SIZE <= enemy_size)
return;
AEnemy *enemy = enemyPool[enemy_size];
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());
float radius = 500;
AMyPlayer* myPlayer =
Cast<AMyPlayer>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
FVector playerLocation = myPlayer->GetActorLocation();
FNavLocation resultLocation;
// 플레이어 주변 Radius 내 랜덤 도달가능 위치 찾기
bool bSuccess = NavSys->GetRandomReachablePointInRadius(playerLocation, radius, resultLocation);
if (bSuccess)
{
enemy->SetActorLocation(resultLocation.Location);
enemy->SetActorHiddenInGame(false);
}
enemy_size++;
}