UE4/5 Cargar recursos y crear objetos.

En UE4, todos los recursos del proyecto se almacenan en el disco duro y, cuando se necesitan, es necesario cargarlos en la memoria para su uso. Para representar mejor los recursos (de referencia), UE4 proporciona dos formas de hacer referencia a los recursos: referencias físicas y referencias suaves.

referencia dura al recurso

Una referencia estricta significa que el objeto A se refiere al objeto B y hace que el objeto B se cargue cuando se carga el objeto A. En términos sencillos, el recurso representado por una referencia física se carga en la memoria cuando se inicializa la referencia, por lo que el recurso representado por una referencia física casi no necesita un método de carga.

puntero duro

La forma más sencilla de hacer referencia a un recurso es crear un puntero UProperty y asignarle una categoría, lo que se denomina puntero físico.
En UE4, si hay una propiedad de puntero UObject que hace referencia a un recurso (a menudo la referencia se establece en el plano), el recurso se cargará cuando se cargue el objeto que contiene esta propiedad (colocado en la textura o referenciado desde gameinfo). , etcétera).

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

FObjectFinder / FClassFinder

Si necesita utilizar código C++ en lugar de planos para establecer referencias, a menudo necesitará FObjectFinder y FClassFinder.

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

En el código fuente UE4, el constructor FObjectFinder llama a LoadObject () para cargar recursos, y el constructor FClassFinder también llama a LoadObject ().

Tenga en cuenta que debe cumplir con las siguientes reglas al usarlos:

  • Solo se puede usar en el constructor de una clase. Si este código está anidado en código lógico ordinario, provocará que todo el compilador falle. (De hecho, el código interno verifica si está en el constructor; de lo contrario, fallará)
  • En segundo lugar, las variables FObjectFinder/FClassFinder deben ser estáticas para garantizar que solo haya una instancia de recurso.
  1. FObjectFinder: generalmente se utiliza para cargar recursos que no son planos, como StaticMesh, Material, SoundWave, ParticlesSystem, AnimSequence, SkeletalMesh y otros recursos:
static ConstructorHelpers::FObjectFinder<UTexture2D> ObjectFinder(TEXT("Texture2D'/Game/Textures/tex1.tex1'"));
UTexture2D* Texture2D = ObjectFinder.Object;
  1. FClassFinder: generalmente se utiliza para cargar recursos de planos y obtener clases de planos. Esto se debe a que si C ++ quiere crear un objeto usando un plano, primero debe obtener la Clase del plano y luego generar el objeto del plano a través de Clase:
static ConstructorHelpers::FClassFinder<AActor> BPClassFinder(TEXT("/Game/Blueprints/MyBP"));
TSubclassOf<AActor> BPClass = BPClassFinder.Class;
...//利用Class生成蓝图对象
  • El nombre de la plantilla de FClassFinder no se puede escribir directamente como UBlueprint, por ejemplo: FClassFinder es incorrecto. Qué clase principal se seleccionó al crear el plano, luego escriba el nombre de la clase principal correspondiente, si es Actor, escriba: FClassFinder, de lo contrario no se podrá cargar correctamente.
  • El nombre de la plantilla de FClassFinder debe ser coherente con el nombre de la plantilla de la variable TSubclassOf. Por supuesto, también se puede utilizar UClass en lugar de TSubclassOf. De hecho, TSubclassOf también es UClass , pero se enfatiza más que esta clase se deriva de T.
  • Al iniciar el juego, si un mensaje de error indica que no se puede encontrar el archivo y falla (por ejemplo: Advertencias y errores de propiedad predeterminada: Error: COD
    Constructor (MyGameMode): No se pudo encontrar
    /Game/MyProject/MyBP.MyBP) esto es porque la ruta de recursos UE4 es una. Hay dos soluciones a los problemas de estandarización:
    • Agregue _C después de la ruta del archivo de la referencia de copia, por ejemplo: "Blueprint'/Game/Blueprints/MyBP.MyBP_C'" (_C puede entenderse como obtener Clase).
    • Elimine el prefijo de ruta, por ejemplo: "/Game/Blueprints/MyBP"

Referencia suave al recurso.

Referencia suave, es decir, el objeto A se refiere al objeto B a través de un mecanismo indirecto (como una ruta de objeto en forma de cadena).

El problema con las referencias físicas es que todos los recursos representados por referencias físicas se cargan al principio, lo que puede provocar que el tiempo de carga de los recursos sea demasiado largo. Una referencia suave es una referencia que puede cargar recursos de manera flexible en cualquier momento, sin tener que cargarlos al principio.

FSoftObjectPaths, FStringAssetReference

  1. FSoftObjectPath: es una estructura simple que contiene el nombre completo del recurso (una cadena). Su esencia es utilizar una cadena para representar el recurso correspondiente, de modo que el recurso de destino en el disco duro pueda encontrarse en cualquier momento a través de la cadena y cargarse en la memoria.

FSoftObjectPath.SolveObject () puede verificar si el recurso al que hace referencia se ha cargado en la memoria, si está cargado, devolverá el puntero del objeto de recurso; de lo contrario, devolverá nulo.
FSoftObjectPath.IsPending() comprueba si el recurso está listo para acceder. Más adelante se explicará cómo utilizar FSoftObjectPath para cargar recursos en la memoria.

  1. FStringAssetReference: en realidad es solo un alias que suena más fácil de entender. De hecho, se ve así en el código fuente de UE4:
typedef FSoftObjectPath FStringAssetReference;

TSoftObjectPtr

TSoftObjectPtr es un TWeakObjectPtr que contiene FSoftObjectPath. Los tipos de recursos específicos se pueden configurar a través de parámetros de plantilla, de modo que la interfaz de usuario del editor solo se puede seleccionar para seleccionar tipos de recursos específicos.

TSoftObjectPtr.Get() puede verificar si el recurso al que hace referencia se ha cargado en la memoria, si se ha cargado devolverá el puntero del objeto de recurso, de lo contrario devolverá nulo. Si desea que los recursos se carguen en la memoria, puede llamar a ToSoftObjectPath() para obtener FSoftObjectPaths para cargar.

Cargar recursos sincrónicamente

CargarObjeto/CargarClase

  1. LoadObject (): carga UObject, generalmente utilizado para cargar recursos que no son planos.
UTexture2D* Texture2D  = LoadObject<UTexture2D>(nullptr,TEXT("Texture2D'/Game/Textures/tex1.tex1'"));
  1. LoadClass (): carga UClass, generalmente se usa para cargar recursos de planos y obtener clases de planos. De hecho, la implementación de LoadClass en el código fuente es llamar a LoadObject y obtener el tipo.
  • El nombre de la plantilla de LoadClass es el mismo que el de FClassFinder anterior y UBlueprint no se puede escribir directamente.
  • La especificación de ruta de LoadClass también es la misma que la de FClassFinder anterior, con el sufijo _C o sin el prefijo.

Hay otras dos funciones llamadas: StaticLoadObject() y StaticLoadClass(), que son las primeras versiones de LoadObject() y LoadClass(). Las dos primeras requieren transferencia forzada manual y completar parámetros complejos, mientras que las dos últimas son encapsulaciones de la primera. 2. Es más cómodo de usar y se recomienda utilizar este último.

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

Además, existe una función global FindObject () que puede usarse comúnmente, que se usa para consultar si el recurso está cargado en la memoria, si existe, se devuelve el puntero del objeto de recurso, de lo contrario devuelve nulo. Pero no necesitamos consultar primero y luego usar LoadXXX, porque FindObject se usa en LoadXXX para verificar la existencia.

Pruebe cargar/cargar sincrónico

  1. TryLoad(): el método de FSoftObjectPaths, que carga recursos directamente según la ruta.
  2. LoadSynchronous(): el método de TSoftObjectPtr también carga recursos directamente según la ruta.

Dado que la referencia suave contiene el nombre de ruta completo del recurso, no es necesario volver a escribir el nombre de la ruta, sino que se llama al método miembro anterior para cargar el recurso en la memoria. El papel de las referencias suaves no es solo eso, también se puede usar para la carga asincrónica de recursos que se presenta a continuación.

Cargar recursos de forma asincrónica

Incluso si se puede controlar el tiempo de carga de los recursos, si el objeto de recurso cargado es grande (o se cargan varios recursos al mismo tiempo), aún causará retraso. Para evitar bloquear el hilo principal, la carga asincrónica es esencial.

FStreamableManager.RequestAsyncLoad()

Primero, debe crear un FStreamableManager. La recomendación oficial es colocarlo en un determinado tipo de objeto singleton de juego global, como el objeto especificado en DefaultEngine.ini usando GameSingletonClassName.

FStreamableManager.RequestAsyncLoad(): cargará de forma asincrónica un conjunto de recursos y llamará al delegado cuando esté completo.

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 en realidad también tiene un método de carga sincrónica: el método SynchronousLoad() realizará una carga de bloque simple y devolverá el objeto.

Descargar recursos

Si el recurso nunca se vuelve a utilizar y desea descargar el objeto de recurso de la memoria, el código es el siguiente:

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

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

Crear objeto

Es mejor que los objetos UE4 (es decir, los objetos de clase derivados de UObject) no utilicen la función nueva/eliminar de C++, pero deben utilizar el método de generación de objetos proporcionado por UE4; de lo contrario, la capacidad de recolección de basura heredada de UObject será inútil.

Crear un objeto general

Si hay una clase derivada de UObject (no Actor, no Componente), puede usar la función de plantilla NewObject() para crear su objeto de instancia:

UMyObject* MyObject = NewObject<UMyObject>();

Crear objeto de clase derivada de actor

No use NewObject o new para generar objetos de clase derivados de AActor, pero use UWorld::SpawnActor()

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

Tenga en cuenta que SpawnActor no se puede colocar en el constructor, pero se puede colocar en funciones de otros períodos, como BeginPlay(), Tick()... De lo contrario, puede fallar después de la compilación.

Crear objeto de clase derivado de componente

Para crear un componente para un Actor, puede utilizar la función de plantilla UObject::CreateDefaultSubobject()

UCameraComponent* Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera0"));
  • CreateDefaultSubobject debe escribirse en el constructor sin parámetros de Actor; de lo contrario, fallará.
  • Los parámetros TEXT o FName en CreateDefaultSubobject no se pueden repetir en el mismo actor; de lo contrario, fallará.
  • Asegúrese de agregar RegisterComponent(); de lo contrario, el editor no aparecerá.

Crear un objeto de plano

Dado que blueprint es esencialmente un script, no una clase directa de C++, a menudo es necesario utilizar escritura dinámica para generar objetos de blueprint. Todos los métodos para cargar recursos y crearlos en la escena son inseparables del código SpawnActor.

  1. Generar objetos planos a través de la clase principal determinada.
AMyActor* spawnActor = GetWorld()->SpawnActor<AMyActor>(AMyActor::StaticClass());  

Si su Blueprint se deriva de una clase C++, puede acceder directamente a StaticClass() de esa clase y usarlo con SpawnActor para crear un objeto Blueprint.

  1. Generar objetos planos a través de UClass
UClass* BPClass = LoadClass<AActor>(nullptr, TEXT("/Game/Blueprints/MyBP"));    //TSubclassOf<AActor>同理
AActor* spawnActor = GetWorld()->SpawnActor<AActor>(BPClass);
  1. Generar objetos planos a través de UObject

Si obtiene UObject, primero debe convertirlo a UBlueprint y luego obtener UClass a través de GeneratedClass para generar el objeto de plano.

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);  
}

Copiar objeto de clase derivada de actor

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;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_41130251/article/details/131634553
Recomendado
Clasificación