UE4/5 Ressourcen laden und Objekte erstellen

In UE4 werden alle Ressourcen im Projekt auf der Festplatte gespeichert. Wenn die Ressourcen benötigt werden, müssen sie zur Verwendung in den Speicher geladen werden. Um (Referenz-)Ressourcen besser darzustellen, bietet UE4 zwei Möglichkeiten zur Referenzierung von Ressourcen – harte Referenzen und weiche Referenzen.

Harter Verweis auf die Ressource

Eine harte Referenz bedeutet, dass Objekt A auf Objekt B verweist und bewirkt, dass Objekt B geladen wird, wenn Objekt A geladen wird. Laienhaft ausgedrückt wird die durch eine harte Referenz dargestellte Ressource bei der Initialisierung der Referenz in den Speicher geladen, sodass die durch die harte Referenz dargestellte Ressource fast keine Lademethode benötigt.

harter Zeiger

Der einfachste Weg, auf eine Ressource zu verweisen, besteht darin, einen Zeiger UProperty zu erstellen und ihm eine Kategorie zuzuweisen. Dies wird als harter Zeiger bezeichnet.
Wenn in UE4 eine harte UObject-Zeigereigenschaft vorhanden ist, die auf eine Ressource verweist (häufig wird die Referenz auf dem Blueprint festgelegt), wird die Ressource geladen, wenn das Objekt, das diese Eigenschaft enthält, geladen wird (in die Textur eingefügt oder über Gameinfo referenziert). usw.).

UPROPERTY(EditDefaultsOnly, Category=Building)
USoundCue* ConstructionStartStinger;

FObjectFinder / FClassFinder

Wenn Sie zum Festlegen von Referenzen C++-Code anstelle von Blaupausen verwenden müssen, benötigen Sie häufig FObjectFinder und FClassFinder.

#include "UObject/ConstructorHelpers.h" \\需要include的头文件

Im UE4-Quellcode ruft der FObjectFinder-Konstruktor LoadObject() auf, um Ressourcen zu laden, und der FClassFinder-Konstruktor ruft auch LoadObject() auf.

Beachten Sie, dass Sie bei der Verwendung folgende Regeln beachten müssen:

  • Es kann nur im Konstruktor einer Klasse verwendet werden. Wenn dieser Code in gewöhnlichen Logikcode verschachtelt ist, führt dies zum Absturz des gesamten Compilers. (Tatsächlich prüft der darin enthaltene Code, ob er sich im Konstruktor befindet, sonst stürzt er ab.)
  • Zweitens müssen FObjectFinder/FClassFinder-Variablen statisch sein, um sicherzustellen, dass es nur eine Ressourceninstanz gibt.
  1. FObjectFinder: Wird im Allgemeinen zum Laden von Nicht-Blueprint-Ressourcen wie StaticMesh, Material, SoundWave, ParticlesSystem, AnimSequence, SkeletalMesh und anderen Ressourcen verwendet:
static ConstructorHelpers::FObjectFinder<UTexture2D> ObjectFinder(TEXT("Texture2D'/Game/Textures/tex1.tex1'"));
UTexture2D* Texture2D = ObjectFinder.Object;
  1. FClassFinder: Wird im Allgemeinen zum Laden von Blueprint-Ressourcen und zum Abrufen der Blueprint-Klasse verwendet. Dies liegt daran, dass C++, wenn es ein Objekt mithilfe eines Blueprints erstellen möchte, zunächst die Klasse des Blueprints abrufen und dann das Blueprint-Objekt über die Klasse generieren muss:
static ConstructorHelpers::FClassFinder<AActor> BPClassFinder(TEXT("/Game/Blueprints/MyBP"));
TSubclassOf<AActor> BPClass = BPClassFinder.Class;
...//利用Class生成蓝图对象
  • Der Vorlagenname von FClassFinder kann nicht direkt als UBlueprint geschrieben werden. Beispiel: FClassFinder ist falsch. Welche übergeordnete Klasse wurde beim Erstellen des Blueprints ausgewählt, dann schreiben Sie den entsprechenden Namen der übergeordneten Klasse. Wenn es sich um Actor handelt, schreiben Sie: FClassFinder, andernfalls kann es nicht erfolgreich geladen werden.
  • Der Vorlagenname von FClassFinder muss mit dem Vorlagennamen der TSubclassOf-Variablen übereinstimmen. Natürlich kann anstelle von TSubclassOf auch UClass verwendet werden. Tatsächlich ist TSubclassOf auch eine UClass , es wird jedoch stärker betont, dass diese Klasse von T abgeleitet ist.
  • Wenn beim Starten des Spiels eine Fehlermeldung darauf hinweist, dass die Datei nicht gefunden werden kann und abstürzt (z. B. Warnungen und Fehler bei Standardeigenschaften: Fehler: COD-
    Konstruktor (MyGameMode): /Game/MyProject/MyBP.MyBP konnte nicht gefunden werden
    ), ist dies der Fall Da der UE4-Ressourcenpfad ein Standardisierungsproblem ist, gibt es zwei Lösungen:
    • Fügen Sie _C nach dem Dateipfad aus der Kopierreferenz hinzu, zum Beispiel: „Blueprint‘/Game/Blueprints/MyBP.MyBP_C‘“ (_C kann so verstanden werden, dass es „Klasse erhalten“ bedeutet).
    • Entfernen Sie das Pfadpräfix, zum Beispiel: „/Game/Blueprints/MyBP“

Sanfter Bezug zur Ressource

Weiche Referenz, dh Objekt A verweist über einen indirekten Mechanismus (z. B. einen Objektpfad in Form einer Zeichenfolge) auf Objekt B.

Das Problem bei harten Referenzen besteht darin, dass alle durch harte Referenzen dargestellten Ressourcen zu Beginn geladen werden, was dazu führen kann, dass die Ladezeit der Ressourcen zu lang ist. Eine Soft-Referenz ist eine Referenz, die Ressourcen jederzeit flexibel laden kann, ohne sie zu Beginn laden zu müssen.

FSoftObjectPaths、FStringAssetReference

  1. FSoftObjectPath: ist eine einfache Struktur, die den vollständigen Namen der Ressource (eine Zeichenfolge) enthält. Sein Kern besteht darin, eine Zeichenfolge zur Darstellung der entsprechenden Ressource zu verwenden, sodass die Zielressource auf der Festplatte jederzeit über die Zeichenfolge gefunden und in den Speicher geladen werden kann.

FSoftObjectPath.SolveObject() kann prüfen, ob die Ressource, auf die es verweist, in den Speicher geladen wurde. Wenn sie geladen ist, gibt sie den Ressourcenobjektzeiger zurück, andernfalls gibt sie null zurück.
FSoftObjectPath.IsPending() prüft, ob die Ressource für den Zugriff bereit ist. Wie Sie FSoftObjectPath zum Laden von Ressourcen in den Speicher verwenden, wird später erläutert.

  1. FStringAssetReference: Es ist eigentlich nur ein Alias, der leichter zu verstehen klingt. Im UE4-Quellcode sieht es tatsächlich so aus:
typedef FSoftObjectPath FStringAssetReference;

TSoftObjectPtr

TSoftObjectPtr ist ein TWeakObjectPtr, das FSoftObjectPath enthält. Bestimmte Ressourcentypen können über Vorlagenparameter festgelegt werden, sodass die Editor-Benutzeroberfläche nur zur Auswahl bestimmter Ressourcentypen ausgewählt werden kann.

TSoftObjectPtr.Get() kann prüfen, ob die Ressource, auf die es verweist, in den Speicher geladen wurde. Wenn sie geladen wurde, gibt sie den Ressourcenobjektzeiger zurück, andernfalls gibt sie null zurück. Wenn Sie möchten, dass Ressourcen in den Speicher geladen werden, können Sie ToSoftObjectPath() aufrufen, um FSoftObjectPaths zum Laden abzurufen.

Laden Sie Ressourcen synchron

LoadObject/LoadClass

  1. LoadObject (): UObject laden, wird im Allgemeinen zum Laden von Nicht-Blueprint-Ressourcen verwendet.
UTexture2D* Texture2D  = LoadObject<UTexture2D>(nullptr,TEXT("Texture2D'/Game/Textures/tex1.tex1'"));
  1. LoadClass(): UClass laden, wird im Allgemeinen zum Laden von Blueprint-Ressourcen und zum Abrufen der Blueprint-Klasse verwendet. Tatsächlich besteht die Implementierung von LoadClass im Quellcode darin, LoadObject aufzurufen und den Typ abzurufen.
  • Der Vorlagenname von LoadClass ist derselbe wie der von FClassFinder oben, und UBlueprint kann nicht direkt geschrieben werden.
  • Die LoadClass-Pfadspezifikation ist auch die gleiche wie beim FClassFinder oben, mit dem Suffix _C oder ohne Präfix.

Es gibt zwei weitere Funktionen namens StaticLoadObject() und StaticLoadClass(), die frühe Versionen von LoadObject() und LoadClass() sind. Die ersten beiden erfordern eine manuelle erzwungene Übertragung und das Ausfüllen komplexer Parameter, während die beiden letzteren Kapselungen der ersten sind Zweitens ist die Verwendung bequemer und es wird empfohlen, Letzteres zu verwenden.

TSubclassOf<AActor> BPClass = LoadClass<AActor>(nullptr, TEXT("/Game/Blueprints/MyBP"));

Darüber hinaus gibt es eine häufig verwendete globale Funktion FindObject (), mit der abgefragt wird, ob die Ressource in den Speicher geladen ist. Wenn sie vorhanden ist, wird der Ressourcenobjektzeiger zurückgegeben, andernfalls wird Null zurückgegeben. Wir müssen jedoch nicht zuerst eine Abfrage durchführen und dann LoadXXX verwenden, da FindObject in LoadXXX verwendet wird, um die Existenz zu überprüfen.

TryLoad/LoadSynchronous

  1. TryLoad(): Die Methode von FSoftObjectPaths, die Ressourcen direkt entsprechend dem Pfad lädt.
  2. LoadSynchronous(): Die Methode von TSoftObjectPtr lädt Ressourcen auch direkt entsprechend dem Pfad.

Da die Soft-Referenz den vollständigen Pfadnamen der Ressource enthält, muss der Pfadname nicht erneut geschrieben werden. Stattdessen wird die obige Mitgliedsmethode aufgerufen, um die Ressource in den Speicher zu laden. Die Rolle von Soft-Referenzen besteht nicht nur darin, sie können auch für das unten vorgestellte asynchrone Laden von Ressourcen verwendet werden.

Laden Sie Ressourcen asynchron

Selbst wenn der Zeitpunkt des Ladens von Ressourcen gesteuert werden kann, kommt es dennoch zu Verzögerungen, wenn das geladene Ressourcenobjekt groß ist (oder mehrere Ressourcen gleichzeitig geladen werden). Um ein Blockieren des Hauptthreads zu vermeiden, ist asynchrones Laden unerlässlich.

FStreamableManager.RequestAsyncLoad()

Zuerst müssen Sie einen FStreamableManager erstellen. Die offizielle Empfehlung besteht darin, ihn in einem bestimmten Typ eines globalen Spiel-Singleton-Objekts zu platzieren, z. B. dem in DefaultEngine.ini mit GameSingletonClassName angegebenen Objekt.

FStreamableManager.RequestAsyncLoad(): Lädt asynchron eine Reihe von Ressourcen und ruft nach Abschluss den Delegaten auf.

void UGameCheatManager::GrantItems()
{
    
          
       //获取 FStreamableManager的单例对象引用
       FStreamableManager& Streamable = ...;

       //得到一组软引用
       TArray<FSoftObjectPath> ItemsToStream;
       for(int32 i = 0; i < ItemList.Num(); ++i)
       ItemsToStream.AddUnique(ItemList[i].ToStringReference());

       //根据一组软引用来异步加载一组资源,加载完后调用委托
       Streamable.RequestAsyncLoad(ItemsToStream, FStreamableDelegate::CreateUObject(this, &UGameCheatManager::GrantItemsDeferred));
}

void UGameCheatManager::GrantItemsDeferred()
{
    
    
       //do something....
}

FStreamableManager verfügt tatsächlich auch über eine synchrone Lademethode: Die SynchronousLoad()-Methode führt einen einfachen Blockladevorgang durch und gibt das Objekt zurück.

Ressourcen entladen

Wenn die Ressource nie wieder verwendet wird und Sie das Ressourcenobjekt aus dem Speicher entladen möchten, lautet der Code wie folgt:

Texture2D* mytex; //这里假设mytex合法有效  

mytex->ConditionalBeginDestroy();  
mytex = NULL;  
GetWorld()->ForceGarbageCollection(true); 

Objekt erstellen

Für UE4-Objekte (d. h. von UObject abgeleitete Klassenobjekte) ist es am besten, nicht C++s new/delete zu verwenden, sondern die von UE4 bereitgestellte Objektgenerierungsmethode zu verwenden, da sonst die von UObject geerbte Garbage-Collection-Funktion nutzlos ist.

Erstellen Sie ein allgemeines Objekt

Wenn es eine abgeleitete Klasse von UObject gibt (kein Akteur, keine Komponente), können Sie die Vorlagenfunktion NewObject() verwenden, um ihr Instanzobjekt zu erstellen:

UMyObject* MyObject = NewObject<UMyObject>();

Erstellen Sie ein von Actor abgeleitetes Klassenobjekt

Verwenden Sie nicht NewObject oder new, um von AActor abgeleitete Klassenobjekte zu generieren, sondern verwenden Sie UWorld::SpawnActor()

UWorld* World = GetWorld();
FVector pos(150, 0, 20);
AMyActor* MyActor = World->SpawnActor<AMyActor>(pos,FRotator::ZeroRotator);

Beachten Sie, dass SpawnActor nicht im Konstruktor platziert werden kann, sondern in Funktionen anderer Perioden wie BeginPlay(), Tick().... Andernfalls kann es nach der Kompilierung zum Absturz kommen.

Erstellen Sie ein von der Komponente abgeleitetes Klassenobjekt

Um eine Komponente für einen Akteur zu erstellen, können Sie die Vorlagenfunktion UObject::CreateDefaultSubobject() verwenden

UCameraComponent* Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera0"));
  • CreateDefaultSubobject muss im Parameterlosen Konstruktor von Actor geschrieben werden, sonst stürzt es ab.
  • Die Parameter TEXT oder FName in CreateDefaultSubobject können nicht im selben Akteur wiederholt werden, da es sonst zum Absturz kommt.
  • Stellen Sie sicher, dass Sie RegisterComponent() hinzufügen, andernfalls wird der Editor nicht angezeigt.

Erstellen Sie ein Blueprint-Objekt

Da es sich bei Blueprint im Wesentlichen um ein Skript und nicht um eine direkte C++-Klasse handelt, ist es häufig erforderlich, dynamische Typisierung zum Generieren von Blueprint-Objekten zu verwenden. Alle Methoden zum Laden und Erstellen von Ressourcen in der Szene sind untrennbar mit dem SpawnActor-Code verbunden.

  1. Generieren Sie Blueprint-Objekte über die bestimmte übergeordnete Klasse
AMyActor* spawnActor = GetWorld()->SpawnActor<AMyActor>(AMyActor::StaticClass());  

Wenn Ihr Blueprint von einer C++-Klasse abgeleitet ist, können Sie direkt auf die StaticClass() dieser Klasse zugreifen und sie mit SpawnActor verwenden, um ein Blueprint-Objekt zu erstellen.

  1. Generieren Sie Blueprint-Objekte über UClass
UClass* BPClass = LoadClass<AActor>(nullptr, TEXT("/Game/Blueprints/MyBP"));    //TSubclassOf<AActor>同理
AActor* spawnActor = GetWorld()->SpawnActor<AActor>(BPClass);
  1. Generieren Sie Blueprint-Objekte über UObject

Wenn Sie UObject erhalten, müssen Sie es zuerst in UBlueprint konvertieren und dann UClass über GeneratedClass abrufen, um das Blueprint-Objekt zu generieren.

FStringAssetReference asset = "Blueprint'/Game/BluePrint/TestObj.TestObj'";  
UObject* itemObj = asset.ResolveObject();  
UBlueprint* gen = Cast<UBlueprint>(itemObj); 
if (gen != NULL){
    
      
    AActor* spawnActor = GetWorld()->SpawnActor<AActor>(gen->GeneratedClass);  
}

Vom Akteur abgeleitetes Klassenobjekt kopieren

AActor* CloneActor(AActor* InputActor)
{
    
    
   UWorld * World = InputActor->GetWorld();
   FActorSpawnParameters params;
   params.Template = InputActor;

	UClass* ItemClass = InputActor->GetClass();
	AActor* const SpawnedActor = World->SpawnActor<AActor>(ItemClass, params);
	return SpawnedActor;
}

Guess you like

Origin blog.csdn.net/weixin_41130251/article/details/131634553