이번 InitState의 주요 맹점은 Component의 부착 순서라고 서두에 언급했습니다만,
해당 주제가 끝나갈 지금 시점에 와서 다시 정리해본다면.... Component라는게 우리가 만든 클래스 Component가 아니라
클래스를 구성하는 구성요소, 예를 들면 PawnData라던가, 다른 멤버들이 준비되었다던가 하는 추상적 개념이 포함되어 있었습니다.
PawnExtensionComponent
InitState_Spawned로 넘어가는 조건은 Pawn이 존재하는지 여부를 검사합니다.
Component가 생성되었을 때 Pawn은 생성되어 있을 확률이 높습니다.
(이건 짬날 때 아닌 케이스의 경우에 대해 찾아봐야 하겠습니다)
InitState_DataAvailable로 넘어가는 조건은 PawnData가 존재하는지 입니다.
PawnExtensionComponent는 멤버변수로 PawnData를 캐싱해두고 있습니다.
그렇다면 PawnData를 누군가 넣어줘야 할텐데? 언제?
정답은 GameModeBase의 SpawnDefaultPawnAtTransform_Implementation에서 해주고 있습니다.
이 함수는 Lyra에서 Override한 함수인데요, DefaultPawn을 우리가 정한 Pawn으로 변환하여 소환해주는 함수입니다.
그 과정에서 FindComponentByClass<...>를 통해서 PawnExtensionComponent를 가져오고,
GetPawnDataForController 함수를 통해 PawnData를 가져와 SetPawnData로 넣어주게 됩니다.
가장 중요한 것은 InitState_DataAvailable에서 InitState_DataInitialized로 넘어갈 때인데요.
if (CurrentState == InitTags.InitState_DataAvailable && DesiredState == InitTags.InitState_DataInitialized)
{
// Pawn이 소유한 모든 컴포넌트가 InitState_DataAvailable이라면 true를 반환
return Manager->HaveAllFeaturesReachedInitState(Pawn, InitTags.InitState_DataAvailable);
}
HaveAllFeaturesReachedInitState는 PawnExtensionComponent를 포함한 모든 Component가 모두 InitState_DataAvailable인 경우, true를 반환합니다.
그리고 종속된 다른 Component들은 이 PawnExtensionComponent가 InitState_DataInitialized인 경우에 DataInitialized 상태로 변환합니다.
그 말인 즉슨, 모든 Component들은 모두 한 시점에서 반드시 DataAvailable 상태로 동기화됩니다.
그 상태를 관찰하던 PawnExtensionComponent는 그 순간 HaveAllFeaturesReachedInitState가 true가 되며,
Initialized 상태가 되고, 이걸 포착한 다른 Component들도 Initialized 상태가 됩니다.
그렇다면 이걸 어디서 체크하는가?
1. 콜백 등록
void UHmPawnExtensionComponent::BeginPlay()
{
Super::BeginPlay();
// NAME_None은 Owning Actor에 등록된 Feature들의 상태가 변하면 모두 관찰하겠다는 뜻
// FGameplayTag()를 넣으면 모든 상태 (InitState_Spawned, Init...)를 다 관찰하겠다는 뜻
BindOnActorInitStateChanged(NAME_None, FGameplayTag(), false);
// InitState_Spawned로 넘어가려고 시도한다!
ensure(TryToChangeInitState(FHmGameplayTags::Get().InitState_Spawned));
CheckDefaultInitialization();
}
- BeginPlay에서 걸어줬던 BindOnActorInitStateChanged에서 Component들의 State를 관찰합니다.
// 관찰하고 있는 Component의 상태가 변경되면 이 함수가 호출된다.
void UHmPawnExtensionComponent::OnActorInitStateChanged(const FActorInitStateChangedParams& Params)
{
// 나 자신을 제외
if (Params.FeatureName != NAME_ActorFeatureName)
{
const FHmGameplayTags& InitTags = FHmGameplayTags::Get();
if (Params.FeatureState == InitTags.InitState_DataAvailable)
{
CheckDefaultInitialization();
}
}
IGameFrameworkInitStateInterface::OnActorInitStateChanged(Params);
}
- 변경이 관찰되면, Delegate가 실행되고, CheckDefaultInitialization 함수가 실행됩니다.
2. 상태 변경할 수 있는지 체크
void UHmPawnExtensionComponent::CheckDefaultInitialization()
{
// 자신을 제외한 연결된 컴포넌트들의 CheckDefaultInitialization을 전부 호출한다
CheckDefaultInitializationForImplementers();
const FHmGameplayTags& InitTags = FHmGameplayTags::Get();
static const TArray<FGameplayTag> StateChain = {
InitTags.InitState_Spawned,
InitTags.InitState_DataAvailable,
InitTags.InitState_DataInitialized,
InitTags.InitState_GameplayReady,
};
// 내부에서 While문으로 각 상태에 대해 CanChangeInitState를 계~속 호출한다
ContinueInitStateChain(StateChain);
}
이로써 InitState에 의한 순차적인 상태 변경이 이루어지게 됩니다.
'Unreal Engine > [Inflearn_rookiss] UE5 Lyra 분석' 카테고리의 다른 글
10. Camera의 부분적 구현 (0) | 2024.10.12 |
---|---|
9. Pawn Extension 및 Init State 내용 정리 (0) | 2024.10.11 |
7. Pawn Extension (1) | 2024.10.07 |
6. InitState (0) | 2024.10.03 |
5. Experience Loading Complete (0) | 2024.10.02 |
댓글