Blog

Blueprints y C++ en Unreal Engine



27 de abril de 2023

Unreal Engine Blueprints C++

Cuando se trata de desarrollar juegos en Unreal Engine, es común pensar que se tiene que elegir entre programar en C++ o utilizar Blueprints. Existe la noción que C++ es la opción par programadores y Blueprints es para quienes no saben programar. Pero la realidad es que ambos son complementarios y pueden ser utilizados juntos para mejorar el proceso de desarrollo de un juego.

¿Qué son Blueprints y qué es C++?

Más que un motor de juegos, Unreal Engine es un framework de software que proporciona una amplia variedad de herramientas y recursos para el desarrollo experiencias interactivas en tiempo real. Como tal, tiene un paradigma de diseño que se centra en la modularidad y la reutilización de código. Es decir que se pueden crear componentes y sistemas que pueden ser utilizados en múltiples proyectos y que se pueden actualizar y mejorar de manera independiente.

Para el diseño de una implementación de software, por ejemplo para un juego de video, es útil pensar que sus funciones complejas de alto nivel están compuestas por funciones más simples de bajo nivel. Por ejemplo, se puede crear un cañón que tiene distintas funciones de alto nivel como disparar y apuntar. Pero estas abstracciones deben estar implementadas a partir de las funciones de bajo nivel que Unreal Engine provee, por ejemplo crear la instancia de una bala de cañón o rotar un objeto. Cómo es que se implementa las funciones de bajo nivel para que representen un cañón con sus funciones de alto nivel es precisamente el trabajo del desarrollador, y cada implementación será distinta dependiendo de los objetivos que el software final tenga.

Unreal Engine ofrece 2 formas para trabajar las implementaciones, una es utilizando C++ y la otra es utilizando Blueprints. C++ es un lenguaje de programación tradicional y es el lenguaje con el que se creó Unreal Engine. Es un lenguaje de bajo nivel y se puede utilizar hasta para modificar el motor. Por otro lado, Blueprints es un sistema y lenguaje de scripting visual de Unreal Engine que utiliza nodos para representar el flujo de datos y las funciones en un juego. Al igual que C++, puede utilizarse para crear clases y heredar propiedades de una clase a otra.

Las funciones de bajo nivel y el motor en sí están escritos en C++ y la mayoría de estas funciones son accesibles en el sistema de Blueprints. Es así como la implementación de un cañón puede ser construida con ambos lenguajes. Entonces llegamos a la pregunta, ¿cómo elegir qué lenguaje usar?

Niveles de Código

Para empezar a contestar esta pegunta debemos explorar un poco más el paradigma de diseño de Unreal Engine. En general, hay tres niveles de programación:

  1. El nivel de motor, que utiliza C++.
  2. Los sistemas base de la implementación (bajo nivel), podemos pensar en esto com los sistemas básicos de un juego. Estos que pueden ser escritos en C++ o Blueprints.
  3. Las abstracciones de la implementación (alto nivel), equivalentes a los objetos y personajes del juego que pueden ser C++ o Blueprints.

De nuevo, que tanto de los sistemas y abstracciones está escrito en cada lenguaje depende de otros factores como las necesidades del proyecto y las habilidades del equipo de desarrollo. Algunos proyectos pueden utilizar más C++, mientras que otros pueden utilizar más Blueprints.

Trabajo en Conjunto

Blueprints y C++ pueden utilizarse juntos en un proyecto principalmente porque el API es el mismo, ambos utilizan las mismas funciones y propiedades. Además, hay interoperabilidad entre ellos. Por ejemplo, se puede crear una función en C++ y luego llamarla desde Blueprints, manipular una instancia de un objeto creado en Blueprints utilizando C++ o crear una clase de Blueprints usando una clase de C++ como la clase madre. Esto es gracias al Unreal Header Tool, una herramienta que automatiza la implementación de C++ en Blueprints. El UHT se encarga de procesar el código C++ antes de ser compilado y añade funciones según las etiquetas que encuentre en el código para definir cómo se puede interactuar con ese código utilizando Blueprints.

Sin embargo, es importante tomar en cuenta que esta relación es unidireccional, en Blueprints se tiene acceso al código y clases de C++, pero en C++ no hay acceso directo al código o a las clases creadas en Blueprints.

Desempeño

Una de las comparaciones principales entre los lenguajes es la velocidad de ejecución de cada uno. Hay que recordar que Blueprints sigue siendo un sistema de scripting y como tal es interpretado en lugar de ser compilado. En lenguajes de programación como C++ el código debe ser compilado antes de poder ser ejecutarlo, o sea se traduce directamente a lenguaje de máquina que el procesador de una computadora puede ejecutar; el lenguaje compilado se ejecuta directamente en el procesador. A diferencia de ello, los lenguajes de scripting son interpretados, o sea no se compila en lenguaje de máquina sino que se ejecuta directamente. Entre el script de Blueprints y el procesador hay una capa de instrucciones básicas que interpreta lo que el Blueprint quiere hacer y construye su funcionamiento en lenguaje de máquina utilizando instrucciones precompiladas. Como resultado, el código escrito con Blueprints generalmente utiliza más instrucciones para lograr el mismo resultado que esa mismo código en C++, lo que toma más tiempo.

Normalmente se considera que el código escrito en Blueprints es más lento que su contraparte en C++, pero esto depende del contexto. Si un actor está ejecutando una función cada Tick, no se notaría la diferencia si el código está escrito en cualquiera de los 2 lenguajes. Pero si hay miles de actores ejecutando la misma función cada Tick, es probable notar la diferencia entre C++ y Blueprints.

¿Entonces Cuándo Usar Cuál?

La flexibilidad de Unreal Engine permite que cada equipo de trabajo pueda trabajar con uno o ambos lenguajes según sus necesidades. Pero podemos definir ciertos casos generales en los que es más recomendable utilizar un lenguaje sobre otro.

Blueprints

Sus usos son más recomendados para desarrollo de alto nivel. Su sistema visual de nodos y rápida ejecución permite que usuarios que no son programadores se familiaricen y construyan sistemas en Unreal Engine. Es recomendable utilizar Blueprints en los siguientes casos:

  1. Iteración y Prototipado

    Cuando se está experimentando con ideas sobre cómo implementar funciones o se estén poniendo a prueba diferentes tipos de funciones. La facilidad de comprender la ejecución de eventos en los nodos de Blueprints y el hecho que no tienen que ser compilados, permite realizar cambios en sus instrucciones de manera rápida e intuitiva, lo que tomaría considerablemente más tiempo en C++. Esto puede incluir desde ideas para una habilidad o un arma, hasta el prototipo de un juego completo.

  2. Secuencias de Eventos

    Cuando se quiere programar una secuencia de acciones que los actores de un juego deben realizar de forma automática. Si bien se puede realizar en C++, la coordinación de eventos y temporizadores es mucho más engorrosa y desordenada que en Blueprints. Además Unreal Cuenta con una herramienta llamada Sequencer para coordinar eventos como secuencias cinematográficas y esta herramienta esta integrada con el sistema de eventos del motor utilizando Blueprints.

  3. Implementación de Assets

    Cuando se quieren implementar diferentes tipos de archivos como sonidos, modelos 3D, materiales, etc. (conocidos como Assets) en diferentes clases de objetos o en diferentes instancias de objetos. Hacer esto en C++ requiere que el código tenga referencias a los archivos del juego por su dirección en el directorio de archivos; y por ser compilado, requeriría que la clase de C++ que implementa estos archivos deba conocer todos los tipos de archivos disponibles. Esto implica 2 grandes cosas, primero que cambiar de lugar o nombre el archivo requiere que el código que lo referencia en C++ deba compilarse de nuevo, y segundo que al correr el juego todos estos archivos se estarían cargando en memoria haciendo el juego menos eficiente. Los Blueprints como tal son assets y por lo tanto la referencia entre assets se mantiene sin necesidad de volver a compilar código; de esta manera los Blueprints permiten cambiar y reordenar los archivos y sus referencias de forma más eficiente y menos complicada que en C++.

C++

Su uso es para desarrollo de bajo nivel. Siendo el lenguaje usado para crear Unreal Engine, se utiliza para modificar el código base del motor. Se recomienda para los siguientes casos:

  1. Funciones Complejas

    Cuando hay necesidad de ejecutar funciones que tengan un proceso complejo y una cantidad considerable de instrucciones. Por ser un lenguaje compilado, la cantidad de instrucciones para ejecutar código en C++ es mucho menor a la cantidad que necesita la misma ejecución en Blueprints, por lo que funciones complejas son más eficientes en este lenguaje.

  2. Código Base

    Cuando se esté planificando el código que describirá los sistemas y objetos base de un proyecto. Cuando se crean clases que serán la base de muchos objetos en un proyecto, con C++ se puede mantener una base más eficiente que permita mantener un buen desempeño cuando haya múltiples objetos utilizando esa base de código al mismo tiempo.

  3. Integración de Bibliotecas Externas

    Cuando se quieran integrar bibliotecas de software que no fueron diseñadas para ser implementadas directamente en Unreal Engine. Por ser un lenguaje longevo y de amplio uso, hay muchas bibliotecas que permiten expandir la funcionalidad de distintos programas de computadora. Unreal Engine es al final de cuentas uno de estos programas y con C++ se pueden integrar diferentes bibliotecas que ofrecen diferentes tipos de funcionalidad mas allá de la que el motor puede hacer.

Control de Versiones

Existe una última consideración a la hora de trabajar con Blueprints y C++, y esta es la integración con sistemas de control de versiones. Unreal Engine recomienda Perforce o SVN como las herramientas de control de versiones integradas con el motor, pero Git también tiene soporte. Esta integración con el motor es importante porque los Blueprints son assets, son archivos binarios y no código en archivos de texto. Lo que esto implica es que los Blueprints sólo pueden ser comparados con otras versiones dentro del motor, ya que sólo ahí pueden editarse. Como estos archivos guardan referencias a otros archivos, las comparaciones con versiones que tengan referencias a archivos que ya no existen pueden generar errores a la hora de revisarlos. Además, no pueden ser combinados automáticamente, siempre requieren la intervención de un usuario para definir cómo 2 archivos con conflictos deben mezclarse.

Conclusión

Tanto Blueprints como C++ son lenguajes de programación bastante poderosos para el desarrollo de juegos en Unreal Engine. Hay una clara intención que promueve que la base del código de un proyecto se escribe en C++ para luego ser implementada utilizando Blueprints, pero la línea que los divide se deja a discreción de cada proyecto y cada desarrollador. De cualquier manera, se utilice el lenguaje que se prefiera, tanto Unreal Engine como los dispositivos modernos permiten que no haya casi ninguna desventaja al favorecer un lenguaje por sobre otro.

Si te interesa saber mas...

Puedes escribirme a me@rodaraujo.com.



Rodrigo Araujo Soria, 2023