[언리얼 엔진] 액터 스폰과 틱
- ⭐ Game Programming/Unreal Document
- 2021. 10. 12.
액터 스폰
게임플레이 코드에서 Actor의 새 인스턴스를 생성하는 함수에 대한 설명
SpawnActor 함수
스폰(Spawn)은 Actor의 새 인스턴스를 생성하는 과정이다. Actor의 스폰은 UWorld::SpawnActor()함수를 사용한다. 이 함수는 새로 생성된 Actor 포인터를 반환한다.
AActor* UWorld::SpawnActor
(
UClass* Class,
FName InName,
FVector const* Location,
FRotator const* Rotation,
AActor* Template,
bool bNoCollisionFail,
bool bRemoteOwned,
AActor* Owner,
APawn* Instigator,
bool bNoFail,
ULevel* OverrideLevel,
bool bDeferConstruction
)
스폰 함수 템플릿
Actor 스폰을 위해 함수 템플릿이 제공된다.
T 인스턴스 스폰, T 포인터 반환
Actor의 루트 컴포넌트와 같은 위치 같은 방향에 T 템플릿 클래스의 인스턴스를 스폰시키는 함수 템플릿으로 템플릿 클래스와 같은 유형의 인스턴스 포인터 T*를 반환한다.
/** 클래스 T 를 스폰하고 반환, 루트 컴포넌트의 기본 방향과 위치를 따릅니다. */
template< class T >
T* SpawnActor
(
AActor* Owner=NULL,
APawn* Instigator=NULL,
bool bNoCollisionFail=false
)
{
return (T*)(GetWorld()->SpawnActor(T::StaticClass(), NAME_None, NULL, NULL, NULL, bNoCollisionFail, false, Owner, Instigator));
}
MyHUD = SpawnActor<AHUD>(this, Instigator);
트랜스폼 정보로 T 인스턴스 스폰, T 포인터 반환
Location과 Rotation을 지정하여 T 인스턴스를 스폰시키는 함수이다.
/** 클래스 T 스폰 후 반환, 월드 포지션은 강제 설정합니다. */
template< class T >
T* SpawnActor
(
FVector const& Location,
FRotator const& Rotation,
AActor* Owner=NULL,
APawn* Instigator=NULL,
bool bNoCollisionFail=false
)
{
return (T*)(GetWorld()->SpawnActor(T::StaticClass(), NAME_None, &Location, &Rotation, NULL, bNoCollisionFail, false, Owner, Instigator));
}
Controller = SpawnActor<AController>(GetLocation(), GetRotation(), NULL, Instigator, true);
클래스 인스턴스 스폰, T 포인터 반환
스폰을 수행하는 Actor의 루트 컴포넌트와 같은 Transform으로 클래스인스턴스를 스폰시킨다.
/** 주어진 클래스를 스폰하고 클래스 T 포인터를 반환, 루트 컴포넌트의 기본 방향과 위치를 따릅니다. */
template< class T >
T* SpawnActor
(
UClass* Class,
AActor* Owner=NULL,
APawn* Instigator=NULL,
bool bNoCollisionFail=false
)
{
return (Class != NULL) ? Cast<T>(GetWorld()->SpawnActor(Class, NAME_None, NULL, NULL, NULL, bNoCollisionFail, false, Owner, Instigator)) : NULL;
}
MyHUD = SpawnActor<AHUD>(NewHUDClass, this, Instigator);
트랜스폼 정보로 클래스 인스턴스 스폰, T 포인터 반환
Transform 정보를 지정하여 지정된 클래스 인스턴스를 스폰시키는 함수 템플릿이다.
/** 주어진 클래스를 스폰하고 클래스 T 포인터를 반환, 월드 포지션은 강제 설정합니다. */
template< class T >
T* SpawnActor
(
UClass* Class,
FVector const& Location,
FRotator const& Rotation,
AActor* Owner=NULL,
APawn* Instigator=NULL,
bool bNoCollisionFail=false
)
{
return (Class != NULL) ? Cast<T>(GetWorld()->SpawnActor(Class, NAME_None, &Location, &Rotation, NULL, bNoCollisionFail, false, Owner, Instigator)) : NULL;
}
APawn* ResultPawn = SpawnActor<APawn>(DefaultPawnClass, StartLocation, StartRotation, NULL, Instigator);
액터 틱
매 프레임 액터를 업데이트하는데 사용되는 Tick 시스템
틱
Tick 이란 일반적으로 프레임당 한 번씩 일정한 간격으로 액터나 컴포넌트에서 코드 또는 블루프린트 스크립트를 실행하는 것을 뜻한다. 게임 액터와 컴포넌트가 상대적으로 틱하는 순서와 엔진이 수행하는 프레임별 작업을 이해하는 것은 프레임별 문제를 예방하고 게임 실행 방식의 일관성을 보장하는데 도움된다.
틱 그룹
액터와 컴포넌트의 틱 주기는 최소 틱 간격을 지정하지 않앗다면 한 프레임에 한 번이다. 틱 발생은 틱 그룹에 따라 이루어지며, 틱 그룹은 코드나 블루프린트에서 할당할 수 있다. 틱 그룹은 주로 물리 시뮬레이션 같은 다른 엔진내 프레임 프로세스 기준 프레임 내 틱 발생 시점을 결정하는데 사용된다. 각 틱 그룹은 할당된 모든 액터와 컴포넌트 틱이 완료되어야 다음 틱 그룹을 시작한다. 액터나 컴포넌트는 틱 종속성을 설정할 수 있어, 다른 액터나 컴포넌트의 틱 함수가 완료되기 전까지 틱이 일어나지 않도록 한다.
틱 그룹 순서
- TG_PrePhysics - 물리 이전 = 프레임 시작
- TG_DuringPhysics - 물리 도중 = 물리 시뮬이 시작됨
- TG_PostPhysics - 물리 이후 = 물리 시뮬이 끝나고 엔진은 현재 프레임 데이터를 사용
- n/a - 잠복성 동작, 월드 타이머 매니저 틱, 카메라 업데이트, 레벨 스트리밍 볼륨과 스트리밍 작업 업데이트 처리
- TG_PostUpdateWork - n/a
- n/a - 프레임 전반에 생성된 액터의 유예식 스폰을 처리. 프레임과 렌더를 마침
TG_PryPhysics
- 액터가 물리기반 어태치먼트를 포함하여 물리 오브젝트와 상호작용할 의도가 있는 경우 사용하는 틱 그룹
- 이 틱 도중의 물리 시뮬레이션 데이터는 한 프레임 전, 즉 지난 프레임 화면에 렌더링된 데이터
TG_DuringPhysics
- 이는 물리 시뮬레이션과 동시에 실행되어, 이번 틱 도중의 물리 데이터가 전 프레임에서 온 것인지 현재 프레임에서 온 것인지 알 수 없다. 물리 시뮬레이션은 이 틱 그룹 내 언제든 완료 가능하며, 그러한 정보는 제공하지 않는다.
- 물리 시뮬레이션 데이터가 현재이거나 이전 프레임의 것일 수 있으므로, 이 틱 그룹은 물리 데이터와 상관없는 로직이나, 한 프레임 늦어져도 상관없는 경우에만 사용할 것을 추천한다.
TG_PostPhysics
- 이 프레임의 물리 시뮬레이션 결과는 이 틱 그룹 실행 시점에서 완료된다.
- 이 그룹은 무기나 무브먼트 트레이스에 사용하기 좋은데, 모든 물리 오브젝트는 최종 위치인 것으로 알려져 있어서 이 프레임이 렌더링 될 때 그려질 것이기 때문이다.
TG_PostUpdateWork
- TG_PostPhysics 이후 실행. 주요 기능은 파티클 시스템에 최후의 순간 정보를 물려주는 것.
- TG_PostUpdateWork 는 카메라 업데이트 이후에 일어난다. 카메라에 의존하고 있는 이펙트가 잇다면 해당 이펙트액터는 여기서 처리하자
- 프레임 내 모든 것 이후에 실행 시킬 게임 로직에 사용하기에 좋다. 격투 게임에서 같은 프레임에 서로를 잡으려하는 두 캐릭터를 알아내려는 경우가 대표적이다.
틱 종속성
AddTickPrerequisiteActor와 AddTickPrerequisiteComponent 함수는 액터와 컴포넌트 양쪽에 존재하며, 이 함수가 호출되는 액터나 컴포넌트는 지정된 다른 액터나 컴포넌트의 틱이 완료될 때까지 틱을 대기하도록 설정한다. 한 프레임 내에 거의 동시에 일어나지만, 하나의 액터나 컴포넌트에 다른 액터나 컴포넌트가 필요로 하는 데이터가 있는 경우 유용하다.
틱 그룹이 아닌 이 기능을 사용하는 이유는 액터가 같은 그룹에 있는 경우 다수의 액터가 병렬 업데이트 될 수가 있기 때문이다. 액터의 그룹을 옮기지 않아도 전체 그룹의 틱이 완료될 때까지 기다릴 필요가 없다.
액터 스폰
BeginPlay 에서, 액터는 주요 틱 함수와 그 컴포넌트의 틱 함수를 엔진에 등록한다. 액터의 틱 함수는 특정 틱 그룹에서 실행되도록 설정하거나, 비활성화시킬 수 있는데, PrimaryActorTick 멤버를 통해서 가능하다. 일반적으로 생성자 안에 코드를 넣는다.
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bTickEvenWhenPaused = true;
PrimaryActorTick.TickGroup = TG_PrePhysics;
컴포넌트 틱
액터를 각기 다른 틱 그룹으로 분리할 수 있듯이, 컴포넌트도 마찬가지다. 기본적으로에는 액터의 틱 도중 하위 모든 컴포넌트에 틱을 적용하고있지만, 다른 그룹에서 틱을 적용해야하는 컴포넌트는 별도의 틱 시기를 관리하는 리스트에 추가된다.
PrimaryActorTick은 액터의 Tick() 함수를 사용하고, PrimaryComponentTick은 액터 컴포넌트의 TickComponent() 함수를 사용한다.
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bTickEvenWhenPaused = true;
PrimaryComponentTick.TickGroup = TG_PrePhysics;
고급 틱 함수 기능
액터나 컴포넌트에 대한 기본 틱 함수는 AActor::SetActorTickEnabled와 UActorComponent::SetComponentTickEnabled 함수로 게임 도중 활성화/비활성화 할 수 있다. 추가로 액터나 컴포넌트는 다수의 틱 함수를 가질 수 있다. FTickFunction을 상속하는 구조체를 만들고 ExecuteTick과 DiagnostickMessage함수를 덮어쓰면 된다. EngineBaseTypes.h 에서 FActorTickFunction과 FComponentTickFunction 이름 아래에서 예시를 찾을 수 있다.
액터나 컴포넌트에 별도의 틱 함수 구조체를 추가하고나면, 보통 소유 클래스의 생성자에서 초기화가 가능하다. 틱 함수의 활성화와 등록을 위해선 보통 AActor::RegisterActorTickFunctions를 덮어쓰고, 틱 함수 구조체의 SetTickFunctionEnable 호출을 추가한뒤, 소유 액터의 레벨을 인수로 하여 RegisterTickFunction을 호출하면 된다. 틱 종속성을 수동 설정하려면, 틱 함수 구조체에서 AddPrerequisite를 호출한 뒤, 종속성으로 사용하고자 하는 틱 함수 구조체를 전달해 주면 된다.