c++ containers and ue4 tutorial

en Tutoriales, UE4

Como añadir contenedores C++ a nuestros blueprints

Con la versión 4.17 de UE4 podemos usar tres tipos de contenedores en nuestros blueprints: TArray, TSet yTMap. Cada uno de ellos se corresponde con los contenedores de c++ vector, set y map respectivamente.

En este tutorial vamos a explicar como añadir otros contenedores para poder usarlos también en los blueprints.

Unreal Engine 4 tiene tres contenedores que pueden usarse en las variables de los blueprint TArray, TSet tTMap, pero también cuenta con más contenedores que son solo accesibles usando c++ code como por ejemplo TQueue, TList, TCircularBuffers. Vamos a crear una clase envoltorio para ser capaces de utilizar estos contenedores inaccesibles en un blueprint.

Podemos empezar por TQueue. TQueue es una template de las colas de c++. Solo cuenta con 5 funciones importantes:

  • Dequeue: Extrae y devuelve el primer elemento insertado en la cola.
  • Enqueue: Añade un elemento al final de la cola
  • Peek: Devuelve el primer elemento de la cola sin extraerlo
  • IsEmpty: Comprueba si la cola esta vacía.
  • Empty: Vacía la cola descartando todos sus elementos.

Si al crear nuestro proyecto cogimos la opción de utilizar solo blueprints ahora tenemos que prepararlo para que sea capaz de utilizar clases C++ también. Para ello hacemos click derecho en el explorador de contenido y seleccionamos New C++ class…

Elegimos crear una clase vacía (None) y le damos un nombre apropiado

Ahora Visual Studio debería abrirse automáticamente. Podemos ver dos proyectos en el explorados de la solución, el del motor UE4 y el de nuestro juego, y dentro de este nuestra nueva clase c++.

Visual Studio Solution Explorer

Si abrimos el fichero .h podemos ver una declaración básica de nuestra clase

1
2
3
4
5
6
7
8
#pragma once
#include "CoreMinimal.h"
class TUTORIAL_API MyQueue
{
public:
	MyQueue();
	~MyQueue();
};

Necesitamos convertir esta clase a una clase base aceptable para crear Blueprints (Blueprintable) y a un tipo que pueda usarse en variables en Blueprints (BlueprintType)usando la macro UCLASS antes de la declaración de la clase. Tambien tendremos que añadir la macro GENERATED_BODY() al principio del cuerpo de la clase macro, e incluir el “ClassName.generated.h“(que se creará automáticamente) en el último lugar de la lista de includes

1
UCLASS(Blueprintable, BlueprintType)

Nuestra cola será de tipo objecto por lo que necesitamos que herede de UObject y cambiar su nombre para que empiece por la letra ‘U’. Ahora la cabecera de nuestra clase debería parecerse a esto:

1
2
3
4
5
6
7
8
9
10
11
#pragma once
#include "Object.h"
#include "MyQueue.generated.h"
 
UCLASS(Blueprintable, BlueprintType)
class TUTORIAL_API UMyQueue :public UObject
{
	GENERATED_BODY()
private:
public:
};

El include a CoreMinimal.h puede eliminarse.

Ahora podemos crear una variable privada para contener el elemento de la clase que envuelve y también la implementación de sus funciones en la parte pública para interactuar con él. Tendremos que utilizar la macro UFUNCTION con los especificadores que más nos interesen, para este ejemplo:

  • BlueprintCallable: La función podrá ejecutarse en un grafo Blueprint
  • BlueprintPure: La función no modifica el objecto propietario y podrá ejecutarse en un grafo Blueprint.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#pragma once
#include "Object.h"
#include "Queue.h"#include "MyQueue.generated.h"
 
UCLASS(Blueprintable, BlueprintType)
class TUTORIAL_API UMyQueue :public UObject
{
	GENERATED_BODY()
private:
	TQueue<int32> _mainQueue;public:
 
	UFUNCTION(BlueprintCallable, Category = "Function")		bool Dequeue(int32& value); 	UFUNCTION(BlueprintCallable, Category = "Function")		bool Enqueue(const int32& value); 	UFUNCTION(BlueprintCallable, Category = "Function")		void Empty(); 	UFUNCTION(BlueprintPure, Category = "Function")		bool IsEmpty(); 	UFUNCTION(BlueprintPure, Category = "Function")		bool Peek(int32& value);};

Esta declaración es para crear una cola específica para almacenar elementos de tipo int32. Si quisiéramos tener una clase más genérica tendríamos que convertirla en una clase templatizada, desafortunadamente en este momento el motor no soporta templatizar blueprint clases :(.

Finalmente el fichero .cpp queda así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "MyQueue.h"
 
bool UMyQueue::Dequeue(int32&amp; value)
{
	return _mainQueue.Dequeue(value);
}
 
bool UMyQueue::Enqueue(const int32&amp; value)
{
	return _mainQueue.Enqueue(value);
}
 
void UMyQueue::Empty()
{
	_mainQueue.Empty();
}
 
bool UMyQueue::IsEmpty()
{
	return _mainQueue.IsEmpty();
}
 
bool UMyQueue::Peek(int32&amp; value)
{
	return _mainQueue.Peek(value);
}

Ahora podemos compilar el proyecto del juego y abrir el Unreal Editor.

Lo primero que haremos será crear una clase Blueprint de nuestra clase C++.

Click derecho en el explorador de contenido y seleccionamos Blueprint Class

Buscamos nuestra clase queue y creamos el blueprint

Ahora ya podemos crear variables con nuestro tipo de contenedor. No te opvides de seleccionar la clase blueprint en el campo de Variable type.

Antes de poder utilizar el objeto cola tenemos que inicializarlo con el nodo Construct Object from Class

Ahora ya podemos utilizar las funciones para interactuar con nuestro contenedor cola

Este método puede utilizarse tanto con otros contenedores de UE4 como con contenedores estándar de C++, y por supuesto con otras clases que no sean contenedores. Solo tenemos que reemplazar el elemento privado de nuestra clase envoltorio y definir las funciones para interactuar con él.


Ayudanos con este blog!

El último año he estado dedicando cada vez más tiempo a la creación de tutoriales, en su mayoria sobre desarrollo de videojuegos. Si crees que estos posts te han ayudado de alguna manera o incluso inspirado, por favor considera ayudarnos a mantener este blog con alguna de estas opciones. Gracias por hacerlo posible!


Escribe un comentario

Comentario

15 − 13 =