편집기 환경에서 문자열에서 클래스 얻기
11473 단어 위 4UnrealEngine
문자열에서 UClass를 얻고 싶습니다.
에디터 환경에서 자동 배치나, 정기적인 처리를 달릴 때에 캐릭터 라인으로부터 UClass를 원할 경우가 있습니다.
예를 들어 외부에서 가져온 CSV에 클래스 이름과 위치 정보를 비롯한 정보가 있으며, 그것을 기반으로 에디터 월드에 자동 배치하고 싶을 때 등입니다.
UE4와 리플렉션
UE4에서는 리플렉션이 채용되고 있으므로, 캐릭터 라인으로부터 클래스를 취해 오거나 함수를 호출해 프로퍼티에 액세스 하는 등의 것이 RTTi를 사용하지 않고 실현할 수 있습니다. 이것이 BP와 cpp를 연결하는 키모의 부분이기도 합니다.
※게임에 있어서의 리플렉션에 대해서, UE 빼기로의 설명은 오마에씨의 MagicReflection의 슬라이드와 코드를 보는 것을 알기 쉽다고 생각합니다.
슬라이드
GitHub
구현
이번에는 FString을 전달하면 UClass를 반환하는 함수를 BP 함수 라이브러리 중 하나로 만듭니다. 이것만 할 수 있으면 후에는 어떻게 되든지 하므로, 예에 나타낸 것 같은 테이블을 보면서 배치하는 실전적인 실장은 단단히 접습니다.
이 구현을 생각할 때, FindObject 하는 것만으로 끝나는 것이라고 생각하거나 해 버립니다만, 그것이 잘 되는 것은, 예를 들어 컨텐츠 브라우저상으로부터 더블 클릭으로 열리는 등해, 에디터 기동 후의 어딘가입니다에서 패키지를 읽는 클래스입니다.
실제로는 다음을 고려하지 않으면 대부분의 경우에 의도한 동작이 되지 않습니다.
그것들을 고려한 것이 다음의 함수입니다.
※3/28 리팩토링&고속화, 함수명은 from보다 by라고 깨닫는 것도 화상 촬영이 맨드이므로 그대로 하고 있습니다.
UClass* UMyBlueprintFunctionLibrary::GetClassFromName(const FString& name) {
UClass* ret = nullptr;
#if UE_EDITOR
auto findClass = [](const FString& name) {
UClass* result = nullptr;
result = FindObject<UClass>(ANY_PACKAGE, *name);
if (nullptr == result) {
// 見つからなかった場合、BPクラスの可能性があるので_Cを付けて再検索.
FString bpname = name;
bpname.Append(TEXT("_C"));
result = FindObject<UClass>(ANY_PACKAGE, *bpname);
if (nullptr == result) {
// それでも見つからない場合、リダイレクタの可能性を探る.
UObjectRedirector* objRedirector = FindObject<UObjectRedirector>(ANY_PACKAGE, *name);
if (nullptr != objRedirector && nullptr != objRedirector->DestinationObject) {
result = Cast<UClass>(objRedirector->DestinationObject);
}
else {
objRedirector = FindObject<UObjectRedirector>(ANY_PACKAGE, *bpname);
if (nullptr != objRedirector && nullptr != objRedirector->DestinationObject) {
result = Cast<UClass>(objRedirector->DestinationObject);
}
}
}
}
return result;
};
// まずはロード済みの物から検索.
ret = findClass(name);
if (nullptr == ret) {
// 最後に読み込まれていない可能性があるので、ロードを試みる.
UPackage* package = LoadPackage(nullptr, *name, LOAD_Verify | LOAD_NoWarn);
if (nullptr != package) {
package->FullyLoad();
// もう一回検索.
ret = findClass(name);
}
}
#endif
return ret;
}
동작 테스트
테스트를 위해 다음과 같은 클래스 이름의 문자열, 위치, 레이블을 지정하여 배치하는 간단한 위젯을 만들었습니다.
위젯의 구현은, 작성한 “GetClassFromName” 함수로부터 클래스를 취득해 한편 클래스가 액터였을 경우 스폰 하도록(듯이) 하고 있습니다.
스폰 함수는 C++로 쓰고 있지만 테스트에 적합합니다. 본격적으로 한다면 UWorld::SpawnActor가 아니라 UWorld::SpawnActorDeferred를 사용하여 세밀한 속성을 설정하는 것이 좋습니다.
AActor* UMyBlueprintFunctionLibrary::SpawnActor(UObject* worldObj, UClass* actorClass, const FVector& location, const FName& label) {
AActor* ret = nullptr;
ret = worldObj->GetWorld()->SpawnActor<AActor>(actorClass, location, FRotator());
ret->SetActorLabel(label.ToString());
return ret;
}
시도에 StaticMeshActor를 배치해 보았습니다.
클래스명의 캐릭터 라인으로부터, 지정한 클래스, 위치, 라벨로 올바르게 스폰 되었습니다.
다음에 에디터 기동 후 한번도 로드되어 있지 않은 BP 클래스의 배치를 시도했습니다.
이쪽도 지정대로 배치할 수 있었습니다.
마지막으로
이번에는 4.24.3에서 움직이는 코드로 썼습니다. 4.25부터 Preview가 벗어났을 때에 다시 확인하려고 합니다.
옛날 실장했을 때는 좀 더 심플하게 쓸 수 있다고 생각하기 때문에, 그 근처의 돌진 있으면 기다리고 있습니다.
Reference
이 문제에 관하여(편집기 환경에서 문자열에서 클래스 얻기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/t-okugawa/items/d8f43f6fb2a3f5914b4d텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)