Godot Engine Documentation (latest Version) Español PDF

Document Details

Uploaded by Deleted User

2017

Juan Linietsky, Ariel Manzur and the Godot community

Tags

Godot Engine game development programming tutorial

Summary

This document is Godot Engine Documentation (latest Version) in Spanish. It's a comprehensive guide to Godot, covering various aspects from basic tutorials to advanced features, including creating scenes, nodes, and instantiating, all within the context of game development using this popular engine. The document also highlights Godot's open-source nature and community contribution.

Full Transcript

Godot Engine Documentation Versión latest Juan Linietsky, Ariel Manzur and the Godot community 15 de noviembre de 2017 Tutoriales 1. Aprendiendo paso a paso 3 2. Motor...

Godot Engine Documentation Versión latest Juan Linietsky, Ariel Manzur and the Godot community 15 de noviembre de 2017 Tutoriales 1. Aprendiendo paso a paso 3 2. Motor 57 3. Tutoriales 2D 83 4. Tutoriales 3D 161 5. Redes 235 6. Plugins de Editor 241 7. Misceláneo 243 8. Conducto de Asset 293 9. Class reference 329 10. Languages 835 11. Cheat sheets 871 12. Compiling 879 13. Advanced 917 14. Contributing 955 I II Godot Engine Documentation, Versión latest Nota: El Motor Godot es un proyecto de código abierto desarrollado por una comunidad de voluntarios. Esto implica que el equipo de documentación siempre puede utilizar tus devoluciones y ayudas para mejorar nuestros tutoriales y referencia de clases. Por lo que si no logras entender algo, o no puedes encontrar lo que necesitas en los documentos, ayúdanos a hacer una mejor documentación y déjanos saber! Envía un problema al repositorio GitHub, o moléstanos en nuestro canal IRC #godotengine-devel! La documentación principal de este sitio esta organizada en algunas secciones: Tutoriales Referencia Comunidad Tutoriales 1 Godot Engine Documentation, Versión latest 2 Tutoriales CAPÍTULO 1 Aprendiendo paso a paso 1.1 Escenas y nodos 1.1.1 Introducción Imagina por un segundo que ya no eres un desarrollador de juegos. En su lugar, eres un chef! Cambia tu atuendo hípster por un un gorro de cocinero y una chaqueta doblemente abotonada. Ahora, en lugar de hacer juegos, creas nuevas y deliciosas recetas para tus invitados. Entonces, ¿Cómo crea un chef su receta? Las recetas se dividen en dos secciones, la primera son los ingredientes y en segundo lugar las instrucciones para prepararlos. De esta manera, cualquiera puede seguir la receta y saborear tu magnífica creación. Hacer juegos en Godot se siente prácticamente igual. Usar el motor es como estar en una cocina. En esta cocina, los nodos son como un refrigerador lleno de ingredientes frescos con los cuales cocinar. 3 Godot Engine Documentation, Versión latest Hay muchos tipos de nodos, algunos muestran imágenes, otros reproducen sonido, otros muestran modelos 3D, etc. Hay docenas de ellos. 1.1.2 Nodos Pero vayamos a lo básico. Un nodo es el elemento básico para crear un juego, tiene las siguientes características: Tiene un nombre. Tiene propiedades editables. Puede recibir una llamada a procesar en cada frame. Puede ser extendido (para tener mas funciones). Puede ser agregado a otros nodos como hijo. La última es muy importante. Los nodos pueden tener otros nodos como hijos. Cuando se ordenan de esta manera, los nodos se transforman en un árbol. En Godot, la habilidad para ordenar nodos de esta forma crea una poderosa herramienta para organizar los proyectos. Dado que diferentes nodos tienen diferentes funciones, combinarlos permite crear funciones mas complejas. Esto probablemente no es claro aun y tiene poco sentido, pero todo va a encajar unas secciones más adelante. El hecho mas importante a recordar por ahora es que los nodos existen y pueden ser ordenados de esa forma. 1.1.3 Escenas Ahora que la existencia de nodos ha sido definida, el siguiente paso lógico es explicar qué es una Escena. 4 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Una escena esta compuesta por un grupo de nodos organizados jerárquicamente (con estilo de árbol). Tiene las si- guientes propiedades: Una escena siempre tiene un solo nodo raíz. Las escenas pueden ser guardadas a disco y cargadas nuevamente. Las escenas pueden ser instanciadas (mas sobre esto después). Correr un juego significa ejecutar una escena. Puede haber varias escenas en un proyecto, pero para iniciar, una de ellas debe ser seleccionada y cargada primero. Básicamente, el motor Godot es un editor de escenas. Tiene más que suficientes herramientas para editar escenas 2D y 3D así como interfaces de usuario, pero el editor gira entorno al concepto de editar una escena y los nodos que la componen. 1.1.4 Creando un Nuevo Proyecto La teoría es aburrida, así que vamos a cambiar de enfoque y ponernos prácticos. Siguiendo una larga tradición de tutoriales, el primer proyecto va a ser el “Hola Mundo!”. Para esto, se usará el editor. Cuando godot se ejecuta sin un proyecto, aparecerá el Gestor Proyectos. Esto ayuda a los desarrolladores a administrar sus proyectos. Para crear un nuevo proyecto, la opción “Nuevo Proyecto” debe ser utilizada. Elije y crea una ruta para el proyecto y especificá el nombre del proyecto. 1.1. Escenas y nodos 5 Godot Engine Documentation, Versión latest 1.1.5 Editor Una vez que el “Nuevo Proyecto” es creado, el siguiente paso es abrirlo. Esto abrirá el editor Godot. Así luce el editor cuando se abre: Como mencionamos antes, hacer juegos en Godot se siente como estar en una cocina, así que abramos el refrigerador y agreguemos algunos nodos frescos al proyecto. Comenzaremos con un “Hola Mundo!” Para hacer esto, el botón “Nuevo Nodo” debe ser presionado. 6 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Esto abrirá el diálogo de Crear Nodo, mostrando una larga lista de nodos que pueden ser creados: Desde allí, selecciona el nodo Label (Etiqueta) primero. Buscarlo es probablemente la forma más rápida: Y finalmente, crea el Label! Un montón de cosas suceden cuando Crear es presionado: 1.1. Escenas y nodos 7 Godot Engine Documentation, Versión latest Primero que nada, la escena cambia hacia el editor 2D (porque Label es un Nodo de tipo 2D), y el Label aparece, seleccionada, en la esquina superior izquierda del viewport (ventana de visualización). El nodo aparece en el editor de árbol de escena (caja en la esquina superior izquierda), y las propiedades de Label están en el Inspector (caja en el costado derecho) El siguiente paso será cambiar la propiedad “Text” de la etiqueta, vamos a cambiarla a “Hola, Mundo!”: Bien, todo esta listo para correr la escena! Presiona el botón “PLAY SCENE” en la barra superior (o presiona F6): Y... Uups. 8 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Las escenas necesitan ser salvadas para correr, por lo que guarda la escena en algo como hola.scn en Escena -> Guardar: Y aquí es donde algo gracioso sucede. El de archivo es especial, y solo permite guardar dentro del proyecto. La raiz del proyecto es “res://” que significa “resource path” (camino de recursos). Esto significa que los archivos sólo pueden ser guardados dentro del proyecto. En el futuro, cuando hagas operaciones con archivos en Godot, recuerda que “res://” es el camino de recursos, y no importa la plataforma o lugar de instalación, es la forma de localizar donde están los archivos de recursos dentro del juego. Luego de salvar la escena y presionar Reproducir Escena nuevamente, el demo “Hola, Mundo!” debería finalmente ejecutarse: Éxito! 1.1.6 Configurando el proyecto Ok, es momento de hacer algunas configuraciones en el proyecto. En este momento, la única forma de correr algo es ejecutar la escena actual. Los proyectos, sin embargo, tienen varias escenas por lo que una de ellas debe ser configurada como la escena principal. Esta escena es la que será cargada cuando el proyecto corre. 1.1. Escenas y nodos 9 Godot Engine Documentation, Versión latest Estas configuraciones son todas guardadas en el archivo engine.cfg, que es un archivo de texto plano en el formato win.ini, para una edición fácil. Hay docenas de configuraciones que pueden ser configuradas en ese archivo para alterar como un proyecto se ejecuta, por lo que para hacer más simple el proceso, existe un cuadro de diálogo de configuración del proyecto, el cual es un tipo de interfaz para editar engine.cfg Para acceder al cuadro de diálogo, simplemente ve a Escena -> Configuración de proyecto. Cuando la ventana abre, la tarea será seleccionar la escena principal. Esto puede ser hecho fácilmente cambiando la propiedad application/main_scene y seleccionando ‘hola.scn’ Con este cambio, presionar el botón de Play regular (o F5) va a correr el proyecto, no importa la escena que se está editando. Yendo atrás con el diálogo de configuración de proyecto. Este diálogo permite una cantidad de opciones que pueden ser agregadas a engine.cfg y mostrar sus valores por omisión. Si el valor por defecto está bien, entonces no hay necesidad de cambiarlo. Cuando un valor cambia, se marca un tick a la izquierda del nombre. Esto significa que la propiedad va a ser grabada al archivo engine.cfg y recordada. Como una nota aparte, para futura referencia y un poco fuera de contexto (al fin de cuentas este es el primer tutorial!), también es posible agregar opciones de configuración personalizadas y leerlas en tiempo de ejecución usando el singleton Globals 1.1.7 Continuará... Este tutorial habla de “escenas y nodos”, pero hasta ahora ha habido sólo una escena y un nodo! No te preocupes, el próximo tutorial se encargará de ello... 10 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest 1.2 Instanciar 1.2.1 Fundamento Tener una escena y tirar nodos en ella puede funcionar para proyectos pequeños, pero en la medida que el proyecto crece, más y más nodos son usados y rápidamente se puede volver inmanejable. Para resolver esto, Godot permite que un proyecto este separado en varias escenas. Esto, sin embargo, no funciona de la misma forma que en otros motores de juegos. De hecho, es bastante diferente, por lo que por favor no saltes este tutorial! Para resumir: Una escena es una colección de nodos organizados como un árbol, donde soló pueden tener un nodo particular como nodo raíz. En Godot, una escena puede ser creada y salvada a disco. Se pueden crear y guardar tantas escenas como se desee. Luego, mientras editas una escena existente o creas una nueva, otras escenas pueden ser instanciadas como parte de está: 1.2. Instanciar 11 Godot Engine Documentation, Versión latest En la imagen anterior, la escena B fue agregada a la escena A como una instancia. Puede parecer extraño al principio, pero al final de este tutorial va a tener completo sentido! 1.2.2 Instanciar, paso a paso Para aprender como instanciar, comencemos descargando un proyecto de muestra: instancing.zip. Descomprime esta escena en el lugar de tu preferencia. Luego, agrega esta escena al gestor de proyectos usando la opción ‘Importar’: Simplemente navega hasta el lugar donde está el proyecto y abre “engine.cfg”. El nuevo proyecto aparecerá en la lista de proyectos. Edita el proyecto usando la opción ‘Editar’. Este proyecto contiene dos escenas “ball.scn”(pelota) y “container.scn”(contenedor). La escena ball es solo una pelota con física, mientras que la escena container tiene una linda forma de colisión, de forma que las pelotas pueden tirarse allí. 12 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Abre la escena container, luego selecciona el nodo raíz: 1.2. Instanciar 13 Godot Engine Documentation, Versión latest Después, presiona el botón con forma de cadena, este es el botón de instanciar! Selecciona la escena de la pelota (ball.scn), la pelota debería aparecer en el origen (0,0), la mueves hasta el centro de la escena, algo así: 14 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Presiona Reproducir y Voilà! La pelota instanciada cayó hasta el fondo del pozo. 1.2.3 Un poco más Puede haber tantas instancias como se desee en una escena, simplemente intenta instanciar más pelotas, o duplícalas (Ctrl-D o botón derecho -> Duplicar): 1.2. Instanciar 15 Godot Engine Documentation, Versión latest Luego intenta correr la escena nuevamente: 16 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Está bueno, eh? Así es como funciona instanciar. 1.2.4 Editando instancias Selecciona una de las muchas copias de las pelotas y ve al Inspector. Hagamos que rebote mucho más, por lo que busca el parámetro bounce(rebote) y configúralo en 1.0: Lo próximo que sucederá es que un botón de “revertir” con forma de “flecha en círculo” aparecerá. Cuando este botón está presente, significa que hemos modificado una propiedad en la escena instanciada, ignorando el valor original. Aún si esa propiedad es modificada en la escena original, el valor personalizado siempre lo sobrescribirá. Tocando el botón de revertir restaurará la propiedad al valor original que vino de la escena. 1.2.5 Conclusión Instanciar parece útil, pero hay más de lo que se ve a simple vista! La próxima parte del tutorial de instanciar cubrirá el resto... 1.3 Instanciar (continuación) 1.3.1 Recapitulación Instanciar tiene muchos usos. A simple vista, al instanciar tienes: La habilidad de subdividir las escenas y hacerlas mas fáciles de administrar. Una alternativa flexible a los prefabricados (y mucho mas poderoso dado que las instancias trabajan en varios niveles) Una forma de diseñar flujos de juegos mas complejos o incluso UIs (interfaces de usuario) (Los elementos de UIs son nodos en Godot también) 1.3.2 Lenguaje de diseño Pero el verdadero punto fuerte de instanciar escenas es que como un excelente lenguaje de diseño. Esto es básicamente lo que hace especial a Godot y diferente a cualquier otro motor en existencia. Todo el motor fue diseñado desde cero en torno a este concepto. 1.3. Instanciar (continuación) 17 Godot Engine Documentation, Versión latest Cuando se hacen juegos con Godot, el enfoque recomendado es dejar a un costado otros patrones de diseño como MVC o diagramas de entidad-relación y empezar a pensar en juegos de una forma mas natural. Comienza imaginando los elementos visibles en un juego, los que pueden ser nombrados no solo por un programador sino por cualquiera. Por ejemplo, aquí esta como puede imaginarse un juego de disparo simple: Es bastante sencillo llegar a un diagrama como este para casi cualquier tipo de juego. Solo anota los elementos que te vienen a la cabeza, y luego las flechas que representan pertenencia. Una vez que este diagrama existe, hacer el juego se trata de crear una escena para cada uno de esos nodos, y usar instancias (ya sea por código o desde el editor) para representar la pertenencia. La mayoría del tiempo programando juegos (o software en general) es usada diseñando una arquitectura y adecuando los componentes del juego a dicha arquitectura. Diseñar basado en escenas reemplaza eso y vuelve el desarrollo mucho mas rápido y directo, permitiendo concentrarse en el juego. El diseño basado en Escenas/Instancias es extremadamente eficiente para ahorrar una gran parte de ese trabajo, ya que la mayoría de los componentes diseñados se mapean directamente a una escena. De esta forma, se precisa poco y nada de código de arquitectura. El siguiente es un ejemplo mas complejo, un juego de mundo abierto con un montón de assets(activos) y partes que interactúan. Crea algunas habitaciones con muebles, luego conectalos. Crea una casa mas tarde, y usa esas habitaciones como su interior. La casa puede ser parte de la ciudadela, que tiene muchas casas. Finalmente la ciudadela puede ser colocada en el terreno del mapa del mundo. También agrega guardias y otros NPCs(personajes no jugador) a la ciudadela, creando previamente sus escenas. Con Godot, los juegos pueden crecer tan rápido como se desee, ya que se trata de crear mas escenas e instanciarlas. 18 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest El editor UI(interfaz de usuario) también esta diseñado para ser operado por personas que no son programadores, por lo que un equipo usual de desarrollo consiste de artistas 2D o 3D, diseñadores de niveles, diseñadores de juegos, animadores, etc todos trabajando en la interfaz del editor. 1.3.3 Sobrecarga de información! No te preocupes demasiado, la parte importante de este tutorial es crear la conciencia de como las escenas e instanciar son usados en la vida real. La mejor forma de entender todo esto es hacer algunos juegos. Todo se volverá muy obvio cuando se pone en practica, entonces, por favor no te rasques la cabeza y ve al siguiente tutorial! 1.4 Scripting 1.4.1 Introducción Mucho se ha dicho sobre herramientas que permiten a los usuarios crear juegos sin programar. Ha sido un sueño para muchos desarrolladores independientes el crear juegos sin aprender a escribir código. Esto ha sido así por un largo tiempo, aun dentro de compañías, donde los desarrolladores de juegos desean tener mas control del flujo del juego (game flow). Muchos productos han sido presentados prometiendo un entorno sin programación, pero el resultado es generalmente incompleto, demasiado complejo o ineficiente comparado con el código tradicional. Como resultado, la programación esta aquí para quedarse por un largo tiempo. De hecho, la dirección general en los motores de jugos ha sido agre- gar herramientas que reducen la cantidad de código que necesita ser escrito para tareas especificas, para acelerar el desarrollo. En ese sentido, Godot ha tomado algunas decisiones de diseño útiles con ese objetivo. La primera y mas importante es el sistema de escenas. El objetivo del mismo no es obvio al principio, pero trabaja bien mas tarde. Esto es, descargar a los programadores de la responsabilidad de la arquitectura del código. Cuando se diseñan juegos usando el sistema de escenas, el proyecto entero esta fragmentado en escenas complemen- tarias (no individuales). Las escenas se complementar entre si, en lugar de estar separadas. Tendremos un montón de ejemplos sobre esto mas tarde, pero es muy importante recordarlo. Para aquellos con una buena base de programación, esto significa que un patrón de diseño diferente a MVC(modelo- vista-controlador). Godot promete eficiencia al costo de dejar los hábitos MVC, los cuales se reemplazan por el patrón escenas como complementos. Godot también utiliza el ‘__ patrones para scripting, por lo que los scripts se extienden desde todas las clases disponibles. 1.4.2 GDScript GDScript es un lenguaje de scripting de tipado dinámico hecho a medida de Godot. Fue diseñado con los siguientes objetivos: El primero y mas importante, hacerlo simple, familiar y fácil, tan fácil de aprender como sea posible. Hacer el código legible y libre de errores. La sintaxis es principalmente extraída de Python. A los programadores generalmente les toma unos días aprenderlo, y entre las primeras dos semanas para sentirse cómodos con el. 1.4. Scripting 19 Godot Engine Documentation, Versión latest Como con la mayoría de los lenguajes de tipado dinámico, la mayor productividad (el código es mas fácil de aprender, mas rápido de escribir, no hay compilación, etc) es balanceada con una pena de rendimiento, pero el código mas critico esta escrito en C++ en primer lugar dentro del motor (vector ops, physics, match, indexing, etc), haciendo que la rendimiento resultante sea mas que suficiente para la mayoría de los juegos. En cualquier caso, si se requiere rendimiento, secciones criticas pueden ser reescritas en C++ y expuestas transparen- temente al script. Esto permite reemplazar una clase GDScript con una clase C++ sin alterar el resto del juego. 1.4.3 Scripting de una Escena Antes de continuar, por favor asegúrate de leer la referencia GDScript Es un lenguaje simple y la referencia es corta, no debería llevar mas que algunos minutos darle un vistazo. Configuración de la Escena Este tutorial comenzara programando una simple escena. Usa el botón de agregar nodo (+) para crear la siguiente jerarquía, con los siguientes nodos: Panel Label Button Debería verse así en el árbol de la escena: Y trata de que quede así en el editor 2D, para que tenga sentido: Finalmente, guarda la escena, un nombre acorde podría ser “dihola.scn” Agregando un script Selecciona el nodo del Panel, y presiona click derecho en el mouse, luego selecciona Agregar Script: 20 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest El dialogo de creación de script aparecerá. Este dialogo permite seleccionar el lenguaje, nombre de clase, etc. GDScript no usa nombres de clase en los archivos de script, por lo que este campo no es editable. El script debería heredar de “Panel” (ya que su función es extender el nodo, que es de tipo Panel, esto se llena automáticamente de todas formas). Selecciona el nombre de archivo para el script (si ya salvaste la escena previamente, uno se generara automáticamente como dihola.gd) y presiona “Crear”: Una vez hecho, el script se creara y se agregara al nodo. Puedes verlo tanto como el icono en el nodo, como en la propiedad script: 1.4. Scripting 21 Godot Engine Documentation, Versión latest Para editar el script, presionar arriba del icono debería hacerlo ( aunque, la UI(interfaz de usuario) te llevara directa- mente a la ventana de edicion de Script). Asique, aquí esta la plantilla del script: 22 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest No hay mucho allí. La función “_ready()” es llamada cuando el nodo (y todos sus hijos) entran en la escena activa. (Recuerda, no es un constructor, el constructor es “_init()” ). El rol del script Un script básicamente agrega un comportamiento al nodo. Es usado para controlar las funciones del nodo así como otros nodos (hijos, padres, primos, etc). El alcance local del script es el nodo (como en cualquier herencia) y las funciones virtuales del nodo son capturadas por el script. 1.4. Scripting 23 Godot Engine Documentation, Versión latest Manipulando una señal Las señales son usadas principalmente en los nodos GUI(interfaz grafica de usuario) (aunque otros nodos también las tienen). Las señales se emiten cuando una acción especifica sucede, y pueden estar conectadas a cualquier otra función en cualquier de cualquier instancia de script. En este paso, la señal “pressed” del botón será conectada a una función personalizada. En la pestaña “Nodo” puedes ver las señales disponibles para el nodo seleccionado: 24 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Pero este ejemplo no lo usara. No queremos hacer las cosas demasiado fáciles. Asique por favor, cierra esa pantalla! En cualquier caso, a esta altura es claro que estamos interesados en la señal “pressed”(presionado), asique en lugar de hacerlo con la interfaz visual, la conexión será hecha por código. Para esto, existe una función que es probablemente la que los programadores de Godot usaran mas, esta es No- de.get_node(). Esta función usa caminos para traer nodos en el árbol actual o en cualquier parte de la escena, relativa al nodo que posee el script. Para traer el botón, lo siguiente debe ser utilizado: get_node("Button") Entonces, a continuación, un callback(llamada de retorno) será agregado cuando el botón sea presionado, que cambiara el texto de la etiqueta: func _on_button_pressed(): get_node("Label").set_text("HELLO!") Finalmente, la señal “pressed” sera conectada al callback en _ready(), usando Object.connect(). func _ready(): get_node("Button").connect("pressed",self,"_on_button_pressed") El script final debería verse así: extends Panel # member variables here, example: # var a=2 # var b="textvar" func _on_button_pressed(): get_node("Label").set_text("HOLA!") 1.4. Scripting 25 Godot Engine Documentation, Versión latest func _ready(): get_node("Button").connect("pressed",self,"_on_button_pressed") Correr la escena debería tener el resultado esperado cuando se presiona el botón: Nota: Ya que es un error común en este tutorial, clarifiquemos nuevamente que get_node(camino) funciona regresando el hijo inmediato del nodo que es controlado por el script (en este caso, Panel), por lo que Button debe ser un hijo de Panel para que el código anterior funcione. Para darle mas contexto a esta aclaración, si Button fuese hijo de Label, el código para obtenerlo sería: # not for this case # but just in case get_node("Label/Button") Y, también, trata de recordar que los nodos son referenciados por nombre, no por tipo. 1.5 Scripting (continuación) 1.5.1 Procesando Varias acciones en godot son disparadas por callbacks o funciones virtuales, por lo que no hay necesidad de escribir código de chequeo que corre todo el tiempo. Además, mucho puede ser hecho con animation players (reproductores de animación). Sin embargo, es aun un caso muy común tener un script procesando en cada frame. Hay dos tipos de procesamiento, procesamiento idle(inactivo) y procesamiento fixed(fijo). El procesamiento Idle es activado con la funcion Node.set_process() Una vez activado, el callback Node._process() podrá ser llamado en cada frame(cuadro). Ejemplo: func _ready(): set_process(true) func _process(delta): # hacer algo... El parámetro delta describe el tiempo que paso (en segundos, como numero de punto flotante) desde la llamada previa a la funcion _process(). El procesamiento fijo es similar, pero solo se necesita para sincronización con el motor de física. Una forma simple de probar esto es crear una escena con un solo nodo Label, con el siguiente script: 26 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest extends Label var accum=0 func _ready(): set_process(true) func _process(delta): accum += delta set_text(str(accum)) Lo que mostrara un contador aumentando cada segundo. 1.5.2 Grupos Los nodos pueden ser agregados a grupos (tantos como se desee por nodo). Esta es una característica simple pero efectiva para organizar escenas grandes. Hay dos formas de hacer esto, la primera es por la UI, con el botón Grupos en la pestaña Nodo. Y la segunda desde el código. Un ejemplo útil podría ser, por ejemplo, marcar escenas que son enemigos. func _ready(): add_to_group("enemigos") De esta forma, si el jugador, entrando sigilosamente a la base secreta, es descubierto, todos los enemigos pueden ser notificados sobre la alarma activada, usando SceneTree.call_group(): func _on_discovered(): get_tree().call_group(0, "guardias", "jugador_fue_descubierto") El código superior llama la función “jugador_fue_descubierto” en cada miembro del grupo “guardias”. Opcionalmente, es posible obtener la lista completa de nodos “guardias” llamando a SceneTree.get_nodes_in_group(): var guardias = get_tree().get_nodes_in_group("guardias") Luego agregaremos mas sobre SceneTree 1.5. Scripting (continuación) 27 Godot Engine Documentation, Versión latest 1.5.3 Notificaciones Godot utiliza un sistema de notificaciones. Usualmente no son necesarias desde scripts, debido a que es demasiado bajo nivel y las funciones virtuales están disponibles para la mayoría de ellas. Es solo que es bueno saber que existen. Simplemente agrega una funcion Object._notification() en tu script: func notificacion (what): if (what == NOTIFICATION_READY): print("Esto es lo mismo que sobrescribir _ready()...") elif (what == NOTIFICATION_PROCESS): var delta = get_process_time() print("Esto es lo mismo que sobrescribir _process()...") La documentación de cada clase en Class Reference muestra las notificaciones que puede recibir. Sin embargo, nue- vamente, para la mayoría de los casos los scripts proveen funciones mas simples Sobreescribibles. 1.5.4 Funciones Sobreescribibles Como mencionamos antes, es mejor usar estas funciones. Los nodos proveen muchas funciones sobreescribibles útiles, las cuales se describen a continuación: func _enter_tree(): # Cuando el nodo entre en la _Scene Tree_. se vuelve activa # y esta función se llama. Los nodos hijos aun no entraron # la escena activa. En general, es mejor usar _ready() # para la mayoría de los casos. pass func _ready(): # Esta función es llamada luego de _enter_tree, pero se # aseguro que todos los nodos hijos también hayan entrado # a _Scene Tree_, y se volvieron activas. pass func _exit_tree(): # Cuando el nodo sale de _Scene Tree_. esta funcion es # llamada. Los nodos hijos han salido todos de _Scene Tree_ # en este punto y todos están activos. pass func _process(delta): # Cuando set_process() esta habilitado, esta función es # llamada en cada frame. pass func _fixed_process(delta): # Cuando set_fixed_process() esta habilitado, esto es # llamado en cada frame de física. pass func _paused(): # Se llama cuando el juego esta en pausa, Luego de esta # llamada, el nodo no recibirá mas callbacks de proceso. pass func _unpaused(): 28 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest # Llamada cuando el juego se reanuda. pass 1.5.5 Creando nodos Para crear nodos desde código, solo llama el método.new(), (al igual que para cualquier otra clase basada en tipo de dato). Ejemplo: var s func _ready(): s = Sprite.new() # crear un nuevo sprite! add_child(s) # lo agrega como hijo de este nodo Para borrar el nodo, sea dentro o fuera de la escena, free() debe ser usado: func _someaction(): s.free() # inmediatamente remueve el nodo de la escena y # lo libera Cuando un nodo es liberado, también son liberados todos los nodos hijos. Por este motivo, borrar nodos manualmente es mucho mas simple de lo que parece. Solo libera el nodo base y todo lo demás en el sub árbol se ira con el. Sin embargo, puede suceder muy seguido que queramos borrar un nodo que esta actualmente “blocked”(bloqueado), esto significa, el nodo esta emitiendo una señal o llamado a función. Esto resultara en que el juego se cuelgue. Correr Godot en el debugger (depurador) a menudo va a capturar este caso y advertirte sobre el. La forma mas segura de borrar un nodo es usando Node.queue_free() en su lugar. Esto borrara el nodo mientras esta inactivo, de forma segura. func _someaction(): s.queue_free() # remueve el nodo y lo borra mientras nada esta sucediendo. 1.5.6 Instanciando escenas Instancias una escena desde código es bastante fácil y se hace en dos pasos. El primero es cargar la escena desde el disco. var scene = load("res://myscene.scn") # cargara cuando el script es instanciado Precargar es mas conveniente a veces, ya que sucede en tiempo de parse (análisis gramatical). var scene = preload("res://myscene.scn") # será cargado cuando el # script es "parseado" Pero ‘escena’ todavía no es un nodo que contiene sub nodos. Esta empaquetado en un recurso especial llamado Pac- kedScene. Para crear el nodo en si, la función PackedScene.instance() debe ser llamada. Esta regresara el árbol de nodos que puede ser agregado a la escena activa: var node = scene.instance() add_child(node) 1.5. Scripting (continuación) 29 Godot Engine Documentation, Versión latest La ventaja de este proceso en dos pasos es que una escena empaquetada puede mantenerse cargada y listo para usar, por lo que puede ser usada para crear tantas instancias como se quiera. Esto es especialmente útil, por ejemplo, para instanciar varios enemigos, armas, etc. de forma rápida en la escena activa. 1.6 Juego 2D Simple 1.6.1 Pong En este sencillo tutorial, un juego básico de Pong será creado. Hay un montón de ejemplos mas complejos que de pueden descargar desde el sitio oficial de Godot, pero esto debería servir como introducción a la funcionalidad básica para juegos 2D. 1.6.2 Assets (activos) Algunos assets son necesarios para este tutorial: pong_assets.zip. 1.6.3 Configuración de la escena Para recordar viejos tiempos, el juego tendrá una resolución de 640x400 pixels. Esto puede ser configurado en Confi- guración de Proyecto (ve Configurando el proyecto). El color de fondo debe ajustarse a negro. Crea un nodo :ref:‘class_Node2D‘como raíz del proyecto. Node2D es el tipo base para el motor 2D. Luego de esto, agrega algunos sprites (:ref:‘class_Sprite‘node) y ajusta cada uno a su textura correspondiente. El diseño de la escena final debe verse similar a esto (nota: la pelota esta en el medio!): 30 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest El árbol de escena, entonces, luce similar a esto: Guarda la escena como “pong.scn” y ajusta la escena principal en las propiedades del proyecto. 1.6.4 Configuración de acciones de entrada Hay tantos métodos de entrada para videojuegos... Teclado, Pad, Mouse, Pantalla táctil (Multitouch). Pero esto es pong. El único control que importa es que los pads vayan arriba y abajo. Manejar todos los posibles métodos de entrada puede ser muy frustrante y tomar un montón de código. El hecho de que la mayoría de los juegos permiten personalizar los controles hacen que este problema empeore. Para esto, Godot creo las “Acciones de Entrada”. Una acción se define, luego se agregan métodos de entrada que disparan esa acción. Abre el dialogo de propiedades de proyecto nuevamente, pero esta vez ve a la pestaña “Mapa de entradas”. 1.6. Juego 2D Simple 31 Godot Engine Documentation, Versión latest Allí, agrega 4 acciones: izq_mover_arriba, izq_mover_abajo, der_mover_arriba, der_mover_abajo. Asigna las teclas que deseas. A/Z (para el jugador de la izquierda) y Flecha arriba/Flecha abajo (para el jugador de la derecha) como teclas debería funcionar en la mayoría de los casos. 1.6.5 Script Crea un script para el nodo raíz de la escena y ábrelo (como se explica en Agregando un script). El script heredara Node2D: extends Node2D func _ready(): pass En el constructor, se harán 2 cosas. Primero es habilitar el procesamiento, y la segunda guardar algunos valores útiles. Esos valores son las dimensiones de la pantalla y el pad: extends Node2D var pantalla_tamano var pad_tamano func _ready(): pantalla_tamano = get_viewport_rect().size pad_tamano = get_node("izquierda").get_texture().get_size() set_process(true) Luego, algunas variables usadas para el procesamiento dentro del juego serán agregadas: #velocidad de la bola (en pixeles/segundo) var bola_velocidad = 80 #dirección de la bola (vector normal) var direccion = Vector2(-1, 0) #constante para la velocidad de los pads (también en 32 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest # pixeles/segundo) const PAD_VELOCIDAD = 150 Finalmente, la función de procesamiento: func _process(delta): Toma algunos valores útiles para computar. La primera es la posición de la bola (desde el nodo), la segunda es el rectángulo (Rect2) para cada uno de los pads. Los sprites tienen sus texturas centradas por defecto, por lo que un pequeño ajuste de pad_size / 2 debe ser agregado. var bola_posicion = get_node("bola").get_pos() var rect_izq = Rect2( get_node("izquierda").get_pos() - pad_tamano/2,pad_tamano) var rect_der = Rect2 ( get_node("derecha").get_pos() - pad_tamano/2,pad_tamano) Debido a que la posición de la bola ha sido obtenida, integrarla debería ser simple: bola_posicion += direccion * bola_velocidad * delta Luego, ahora que la bola tiene una nueva posición, debería ser probada contra todo. Primero, el piso y el techo: if ( (bola_posicion.y < 0 and direccion.y < 0) or (bola_posicion.y > pantalla_tamano. ˓→y and direccion.y > 0)): direccion.y = -direccion.y Si se toco uno de los pads, cambiar la dirección e incrementar la velocidad un poco if ( (rect_izq.has_point(posicion_bola) and direccion.x < 0) or (rect_der.has_ ˓→point(bola_posicion) and direccion.x > 0)): direccion.x = -direccion.x bola_velocidad *= 1.1 direccion.y = randf() * 2.0 - 1 direccion = direccion.normalized() Si la bola sale de la pantalla, el juego termina. Luego se reinicia: if (bola_posicion.x < 0 or bola_posicion.x > pantalla_tamano.x): bola_posicion = pantalla_tamano * 0.5 # la bola va al centro de la pantalla bola_velocidad = 80 direccion = Vector2 (-1, 0) Una vez que todo fue hecho con la bola, el nodo es actualizado con la nueva posición: get_node("bola").set_pos(bola_posicion) Solo actualizar los pads de acuerdo a la entrada del jugador. La clase Input es realmente útil aquí: #mover pad izquierdo var izq_posicion = get_node("izquierda").get_pos() if (izq_posicion.y > 0 and Input.is_action_pressed("izq_mover_arriba")): izq_posicion.y += -PAD_SPEED * delta if (izq_posicion.y < pantalla_tamano.y and Input.is_action_pressed("izq_mover_abajo ˓→")): izq_posicion.y += PAD_SPEED * delta 1.6. Juego 2D Simple 33 Godot Engine Documentation, Versión latest get node("izquierda").set_pos(izq_posicion) #mover pad derecho var der_posicion = get_node("derecha").get_pos() if (der_posicion.y > 0 and Input.is_action_pressed("der_mover_arriba")) der_posicion.y += -PAD_SPEED * delta if (der_posicion.y < pantalla_tamano.y and Input.is_action_pressed("der_mover_abajo ˓→")): der_posicion.y += PAD_SPEED * delta get_node("derecha").set_pos(der_posicion) Y eso es todo! Un simple Pong fue escrito con unas pocas líneas de código. 1.7 Tutorial GUI (Interfaz Grafica de Usuario) 1.7.1 Introduccion Si hay algo que la mayoria de los programadores realmente odian, es programar interfaces graficas de usuario (GUIs). Es aburrido, tedioso y no ofrece retos. Varios aspectos hacen este problema peor como: La alineacion de los elementos de la UI (interfaz de usuario) es dificil (para que se vea justo como el diseñador queria). Las UIs son cambiadas constantemente debido a los problemas de apariencia y usabilidad que aparecen durante el testing(prueba). Manejar apropiadamente el cambio de tamaño de pantalla para diferentes resoluciones de pantallas. Animar varios componentes de pantalla, para hacerlo parecer menos estatico. La programacion GUI es ona de las principales causas de frustracion de los programadores. Durante el desarrollo de Godot (y previas iteraciones del motor), varias tecnicas y filosoficas para el desarrollo UI fueron puestas en practica, como un modo inmediato, contenedores, anclas, scripting, etc. Esto fue siempre hecho con el objetivo principal de reducir el estres que los programadores tienen que enfrentar cuando crear interfaces de usuario Al final, el sistema UI resultante en Godot es una eficiente solucion para este problema, y funciona mezclando jun- tos algunos enfoques. Mientras que la curva de aprendizaje es un poco mas pronunciada que en otros conjuntos de herramientas, los desarrolladores pueden crear interfaces de usuario complejas en muy poco tiempo, al compartir las mismas herramientas con diseñadores y animadores. 1.7.2 Control El nodo basico para elementos UI es Control (a veces llamados “Widget” o “Caja” en otras herramientas). Cada nodo que provee funcionalidad de interfaz de usuario desciende de el. Cuando los controles son puestos en el arbol de escena como hijos de otro control, sus coordenadas (posicion, tamaño) son siempre relativas a sus padres. Esto aporta la base para editar interfaces de usuario complejas rapidamente y de manera visual. 34 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest 1.7.3 Entrada y dibujado Los controles reciben eventos de entrada a traves de la llamada de retorno Control._input_event(). Solo un control, el que tiene el foco, va a recibir los eventos de teclado/joypad (ve Control.set_focus_mode() y Control.grab_focus().) Los eventos de movimiento de mouse son recibidos por el control que esta directamente debajo del puntero de mouse. Cuando un control recibe el evento de que se presiono un boton de mouse, todas los eventos siguientes de movimiento son recibidos por el control presionado hasta que el boton se suelta, aun si el puntero se mueve fuera de los limites del control. Como cualquier clase que hereda de CanvasItem (Control lo hace), una llamada de retorno CanvasItem._draw() sera re- cibida al principio y cada vez que el control deba ser redibujado (los programadores deben llamar CanvasItem.update() para poner en cola el CanvasItem para redibujar). Si el control no esta visible (otra propiedad CanvasItem), el control no recibe ninguna entrada. En general sin embargo, el programador no necesita lidiar con el dibujado y los eventos de entrada directamente cuando se construyen UIs, (es mas util cuando se crean controles personalizados). En su lugar, los controles emiten diferente tipos de señales con informacion contextual para cuando la accion ocurre. Por ejemplo, una Button emite una señal “pressed”, una :ref:‘Slider ‘emitiraun “value_changed” cuando se arrastra, etc. 1.7.4 Mini tutorial de controles personalizados Antes de ir mas profundo, crear un control personalizado sera una buena forma de entender como funcionan los controles, ya que no son tan complejos como pueden parecer. Adicionalmente, aunque Godot viene con docenas de controles para diferentes propositos, sucede a menudo que es simplemente mas sencillo obtener la funcionalidad especidica creando uno nuevo. Para comenzar, crea una escena con un solo nodo. El nodo es del tipo “Control” y tiene cierta area de la pantalla en el editor 2D, como esto: Agregale un script a ese nodo, con el siguiente codigo: extends Control var pulsado=false func _draw(): var r = Rect2( Vector2(), get_size() ) if (pulsado): draw_rect(r, Color(1,0,0) ) else: 1.7. Tutorial GUI (Interfaz Grafica de Usuario) 35 Godot Engine Documentation, Versión latest draw_rect(r, Color(0,0,1) ) func _input_event(ev): if (ev.type==InputEvent.MOUSE_BUTTON and ev.pressed): pulsado=true update() Luego corre la escena. Cuando el rectangulo es clickeado/pulsado, ira de azul a rojo. Esa sinergia entre los eventos y el dibujo es basicamente como funcionan internamente la mayoria de los controles. 1.7.5 Complejidad de la UI Como mencionamos antes, Godot incluye docenas de controles listos para usarse en una interface. Esos controles estan divididos en dos categorias. La primera es un pequeño grupo de controles que funcionan bien para crear la mayoria de las interfaces de usuario. La segunda (y la mayoria de los controles son de este tipo) estan destinadas a interfases de usuario complejas y el skinning(aplicar un forro) a traves de estilos. Una descripcion es presentada a continuacion para ayudar a entender cual debe ser usada en que caso. 1.7.6 Controles UI simplificados Este conjunto de controles es suficiente para la mayoria de los juegis, donde interacciones complejas o formas de presentar la informacion no son necesarios. Pueden ser “skineados” facilmente con texturas regulares. Label: Nodo usado para mostrar texto TextureFrame: Muestra una sola textura, que puede ser escalada o mantenia fija. TextureButton: Muestra una simple boton con textura para los estados como pressed, hover, disabled, etc. TextureProgress: Muestra una sola barra de progreso con textura. Adicionalmente, el reposicionado de controles es mas eficientemente hecho con anclas en este caso (ve el tutorial Tamaño y anclas para mas informacion) De cualqueir forma, sucedera seguido que aun para juegos simples, comportamientos de UI mas complejos son re- queridos. Un ejemplo de esto una lista de elemenots con scrolling (desplazamiento) (por ejemplo para una tabla de puntuaciones altas), la cual necesita un ScrollContainer y un VBoxContainer. Este tipo de controles mas avanzados puede ser mezclado con los regulares sin problema (son todos controles de todas formas). 36 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest 1.7.7 Controles de UI complejos El resto de los controles (y hay docenas de ellos!) estan destinados para otro tipo de escenario, los mas comunes: Juegos que requieren UIs complejas, como RPGs (juegos de rol), MMOs (juegos online masivos), strategy (estrategia), sims (simulacion), etc. Crear herramientas de desarrollo personalizadas para acelerar la creacion de contenido. Crear Plugins de Editor de Godot, para extender la funcionalidad del motor. Reposicionar controles para este tipo de interfaces es mas comunmente hecho con contenedores (ve el tutorial Tamaño y anclas para mas informacion). 1.8 Pantalla de bienvenida (Splash Screen) 1.8.1 Tutorial Este será un tutorial simple para cementar la idea básica de como el subsistema GUI funciona. El objetivo será crear una pantalla de bienvenida realmente simple y estática. A continuación hay un archivo con los assets que serán usados. Estos pueden ser agregados directamente a tu carpeta de proyecto, no hay necesidad de importarlos. robisplash_assets.zip. 1.8.2 Configurando Fija la resolución de pantalla en 800x450 en la configuración de proyecto, y prepara una nueva escena como esta: 1.8. Pantalla de bienvenida (Splash Screen) 37 Godot Engine Documentation, Versión latest Los nodos “fondo” y “logo” son del tipo TextureFrame. Estos tienen una propiedad especial para configurar la textura a ser mostrada, solo carga el archivo correspondiente. El nodo “start” es un TextureButton, que toma varias imágenes para diferentes estados, pero solo normal y pressed (presionado) serán proporcionados en este ejemplo: 38 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Finalmente, el nodo “copyright” es una Label. Las etiquetas (Labels) pueden ser configuradas con una fuente perso- nalizada editando la siguiente propiedad: Como una nota aparte, la fuente fue importada de un TTF, ve Importing fonts. 1.9 Animaciones 1.9.1 Introducción Este tutorial explicara como todo es animado en Godot. El sistema de animación de Godot es extremadamente pode- roso y flexible. Para empezar, vamos a usar la escena del tutorial previo (Pantalla de bienvenida (Splash Screen)). El objetivo es agregarle una animación simple. Aquí hay una copia del tutorial por las dudas: robisplash.zip. 1.9. Animaciones 39 Godot Engine Documentation, Versión latest 1.9.2 Creando la animación Primero que nada, agrega un nodo AnimationPlayer a la escena como hijo del fondo (en nodo raiz): Cuando un nodo de este tipo es seleccionado, el panel de edición de animaciones aparecerá: Asique, es tiempo de crear una nueva animación! Presiona el botón Nueva Animación y nómbrala “intro”. Luego de que la animación es creada, es tiempo de editarla. 1.9.3 Editando la animación Ahora es cuando la magia sucede! Varias cosas suceden cuando se edita una animación, la primera es la aparicion del panel de edición de animación. 40 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Pero la segunda, y mas importante, es que el Inspector entra en modo “animación”. En este modo, un icono de llave aparece al lado de cada propiedad en el Inspector. Esto significa que, en Godot, cualquier propiedad de cualquier objeto puede ser animada. 1.9.4 Haciendo que el logo aparezca A continuación, haremos aparecer el logo desde la parte superior de la pantalla. Luego de seleccionar el reproductor de animaciones, el panel de edición se mantendrá visible hasta que sea manualmente escondido. Para tomar ventaja de esto, seleccióna el nodo “logo” y ve a la propiedad “pos” en el Inspector, muévela arriba, a la posición: 114, -400. Una vez en esta posición, presiona el botón de llave al lado de la propiedad: 1.9. Animaciones 41 Godot Engine Documentation, Versión latest Como es un nuevo track (pista), un dialogo aparecerá preguntando para crearla. Confirma! Asi el keyframe(fotograma clave) sera agregado en el editor de animación: En segundo lugar, mueve el cursor del editor hasta el final, haciendo click aquí: Cambia la posición del logo a 114,0 en el Inspector y agrega otro keyframe (haciendo click en la llave). Con dos keyframes, la animación sucede. Pulsando Play en el panel de animación hará que el logo descienda. Para probarlo al correr la escena, el botón autoplay puede marcar la animación para que empiece automáticamente cuando la escena comienza: 42 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Y finalmente, cuando corras la escena, la animación debería verse de esta forma: 1.10 Recursos 1.10.1 Nodos y recursos Hasta ahora, los Nodos (Nodes) han sido el tipo de datos mas importante en Godot, ya que la mayoría de los compor- tamientos y características del motor están implementadas a través de estos. Hay, sin embargo, otro tipo de datos que es igual de importante. Son los recursos (Resource). Mientras que los Nodos se enfocan en comportamiento, como dibujar un sprite, dibujar un modelo 3d, física, controles GUI, etc, los Recursos con meros contenedores de datos. Esto implica que no realizan ninguna acción ni procesan información. Los recursos solo contienen datos. Ejemplos de recursos: Texture, Script, Mesh, Animation, Sample, AudioStream, Font, Translation, etc. Cuando Godot guarda o carga (desde disco) una escena (.scn o.xml), una imagen (png, jpg), un script (.gd) o básica- mente cualquier cosa, ese archivo es considerado un recurso. Cuando un recurso es cargado desde disco, siempre es cargado una sola vez. Esto significa, que si hay una copia del recurso ya cargada en memoria, tratar de leer el recurso nuevamente va a devolver la misma copia una y otra vez. Esto debido al hecho de que los recursos son solo contenedores de datos, por lo que no hay necesidad de tenerlos duplicados. Típicamente, cada objeto en Godot (Nodo, Recurso, o cualquier cosa) puede exportar propiedades, las cuales pueden ser de muchos tipos (como un string o cadena, integer o numero entero, Vector2 o vector de 2 dimensiones, etc). y uno de esos tipos puede ser un recurso. Esto implica que ambos nodos y recursos pueden contener recursos como propiedades. Para hacerlo un poco mas visual: 1.10. Recursos 43 Godot Engine Documentation, Versión latest 1.10.2 Externo vs Incorporado (Built-in) Las propiedades de los recursos pueden referenciar recursos de dos maneras, externos (en disco) o incorporados. Para ser mas especifico, aqui hay una Texture en un nodo Sprite: 44 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Presionando el botón “>” a la derecha de la vista previa, permite ver y editar las propiedades del recurso. Una de las propiedades (path) muestra de donde vino. En este caso, desde una imagen png. Cuando el recurso proviene de un archivo, es considerado un recurso externo. Si el la propiedad camino es borrada (o nunca tuvo), es considerado un recurso incorporado. Por ejemplo, si el camino ‘”res://robi.png“‘ es borrado de la propiedad path en el ejemplo superior, y la escena es guardada, el recurso será guardado dentro del archivo de escena.scn, ya no referenciando externamente a “robi.png”. Sin embargo, aun si esta guardado de forma incorporada, y aunque la escena puede ser instanciada muchas veces, el recurso se seguirá leyendo siempre una vez. Eso significa que diferentes escenas del robot Robi que sean instanciadas al mismo tiempo conservaran la misma imagen. 1.10.3 Cargando recursos desde código Cargar recursos desde codigo es fácil, hay dos maneras de hacerlo. La primera es usar load(), así: 1.10. Recursos 45 Godot Engine Documentation, Versión latest func _ready(): var res = load("res://robi.png") # el recurso es cargado cuando esta linea se ˓→ejecuta get_node("sprite").set_texture(res) La segunda forma es mas optima, pero solo funciona con un parámetro de cadena constante, porque carga el recurso en tiempo de compilación. func _ready(): var res = preload("res://robi.png") # el recurso se carga en tiempo de ˓→compilación get_node("sprite").set_texture(res) 1.10.4 Cargar escenas Las escenas son recursos, pero hay una excepción. Las escenas guardadas a disco son del tipo PackedScene, esto implica que la escena esta empacada dentro de un recurso. Para obtener una instancia de la escena, el método PackedScene.instance() debe ser usado. func _on_shoot(): var bullet = preload("res://bullet.scn").instance() add_child(bullet) Este método crea los nodos en jerarquía, los configura (ajusta todas las propiedades) y regresa el nodo raíz de la escena, el que puede ser agregado a cualquier nodo. Este enfoque tiene varia ventajas. Como la función PackedScene.instance() es bastante rapida, agregar contenido extra a la escena puede ser hecho de forma eficiente. Nuevos enemigos, balas, efectos, etc pueden se agregados o quitados rápidamente, sin tener que cargarlos nuevamente de disco cada vez. Es importante recordar que, como siempre, las imágenes, meshes (mallas), etc son todas compartidas entre las instancias de escena. 1.10.5 Liberando recursos Los recursos se extienden de Reference. Como tales, cuando un recurso ya no esta en uso, se liberara a si mismo de forma automática. Debido a que, en la mayoría de los casos, los Recursos están contenidos en Nodos, los scripts y otros recursos, cuando el nodo es quitado o liberado, todos los recursos hijos son liberados también. 1.10.6 Scripting Como muchos objetos en Godot, no solo nodos, los recursos pueden ser scripts también. Sin embargo, no hay mucha ganancia, ya que los recursos son solo contenedores de datos. 1.11 Sistema de archivos (Filesystem) 1.11.1 Introducción Los sistemas de archivos son otro tema importante en el desarrollo de un motor. El sistema de archivos gestiona como los assets son guardados, y como son accedidos. Un sistema de archivos bien diseñado también permite a múltiples desarrolladores editar los mismos archivos de código y assets mientras colaboran juntos. 46 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Las versiones iniciales del motor Godot (y previas iteraciones antes de que se llamase Godot) usaban una base de datos. Los assets eran guardados en ella y se le asignaba un ID. Otros enfoques fuero intentados también, como base de datos local, archivos con metadatos, etc. Al final el enfoque mas simple gano y ahora Godot guarda todos los assets como archivos en el sistema de archivos. 1.11.2 Implementación El sistema de archivos almacena los recursos en disco. Cualquier cosa, desde un script, hasta una escena o una imagen PNG es un recurso para el motor. Si un recurso contiene propiedades que referencian otros recursos en disco, los caminos (paths) a esos recursos con incluidos también. Si un recurso tiene sub-recursos que están incorporados, el recurso es guardado en un solo archivo junto a todos los demás sub-recursos. Por ejemplo, un recurso de fuente es a menudo incluido junto a las texturas de las fuentes. En general el sistema de archivos de Godot evita usar archivos de metadatos. La razón para esto es es simple, los gestores de assets y sistemas de control de versión (VCSs) son simplemente mucho mejores que cualquier cosa que nosotros podamos implementar, entonces Godot hace su mejor esfuerzo para llevarse bien con SVN, Git, Mercurial, Preforce, etc. Ejemplo del contenido de un sistema de archivos: /engine.cfg /enemy/enemy.scn /enemy/enemy.gd /enemy/enemysprite.png /player/player.gd 1.11.3 engine.cfg El archivo engine.cfg es la descripción del proyecto, y siempre se encuentra en la raíz del proyecto, de hecho su locación define donde esta la raiz. Este es el primer archivo que Godot busca cuando se abre un proyecto. Este archivo contiene la configuración del proyecto en texto plano, usando el formato win.ini. Aun un engine.cfg vacío puede funcionar como una definición básica de un proyecto en blanco. 1.11.4 Delimitador de camino (path) Godot solo soporta / como delimitador de ruta o camino. Esto es hecho por razones de portabilidad. Todos los sistemas operativos soportan esto, aun Windows, por lo que un camino como c:\project\engine.cfg debe ser tipiado como c:/project/engine.cfg. 1.11.5 Camino de recursos Cuando se accede a recursos, usar el sistema de archivos del sistema operativo huésped puede ser complejo y no portable. Para resolver este problema, el camino especial res:// fue creado. El camino res:// siempre apuntara a la raíz del proyecto (donde se encuentra engine.cfg, por lo que es un hecho que res://engine.cfg siempre es valido) El sistema de archivos es de lectura-escritura solo cuando se corre el proyecto localmente desde el editor. Cuando se exporta o cuando se ejecuta en diferentes dispositivos (como teléfonos o consolas, o corre desde DVD), el sistema de archivos se vuelve de solo lectura, y la escritura no esta permitida. 1.11. Sistema de archivos (Filesystem) 47 Godot Engine Documentation, Versión latest 1.11.6 Camino de usuario Escribir a disco es de todas formas necesario para varias tareas como guardar el estado del juego o descargar paquetes de contenido. Para este fin existe un camino especial ‘‘user://‘‘que siempre se puede escribir. 1.11.7 Sistema de archivos de huésped De forma alternativa se puede utilizar también caminos del sistema de archivos huésped, pero esto no es recomendado para un producto publicado ya que estos caminos no tienen garantía de funcionar en todas las plataformas. Sin embar- go, usar caminos de sistema de archivos huésped puede ser muy útil cuando se escriben herramientas de desarrollo en Godot! 1.11.8 Inconvenientes Hay algunos inconvenientes con este simple diseño de sistema de archivos. El primer tema es que mover assets (re- nombrarlos o moverlos de un camino a otro dentro del proyecto) va a romper las referencias a estos assets. Estas referencias deberán ser re-definidas para apuntar a la nueva locación del asset. El segundo es que bajo Windows y OSX los nombres de archivos y caminos no toman en cuenta si son mayúsculas o minúsculas. Si un desarrollador trabajando en un sistema de archivos huésped guarda un asset como “myfile.PNG”, pero lo referencia como “myfile.png”, funcionara bien en su plataforma, pero no en otras, como Linux, Android, etc. Esto también puede aplicarse a archivos binarios exportados, que usan un paquete comprimido para guardar todos los archivos. Es recomendado que tu equipo defina con claridad una nomenclatura para archivos que serán trabajados con Godot! Una forma simple y a prueba de errores es solo permitir nombres de archivos y caminos en minúsculas. 1.12 Scene Tree (Árbol de Escena) 1.12.1 Introducción Aquí es donde las cosas se empiezan a poner abstractas, pero no entres en pánico, ya que no hay nada mas profundo que esto. En los tutoriales previos, todo gira al rededor del concepto de Nodos, las escenas están hechas de ellos, y se vuelven activas cuando entran a Scene Tree. Esto merece ir un poco mas profundo. De hecho, el sistema de escenas no es siquiera un componente de núcleo de Godot, ya que es posible ignorarlo y hacer un script (o código C++) que habla directamente con los servidores. Pero hacer un juego de esa forma seria un montón de trabajo y esta reservado para otros usos. 1.12.2 MainLoop (Ciclo Principal) La forma en la que Godot trabaja internamente es la siguiente. Esta la clase OS, la cual es la única instancia que corre al principio. Luego, todos los controladores, servidores, lenguajes de scripting, sistema de escena, etc. son cargados. Cuando la inicialización esta completa, la clase OS necesita el aporte de un MainLoop para correr. Hasta este punto, toda esta maquinaria es interna (puedes chequear el archivo main/main.cpp en el código fuente si alguna vez estas interesado en ver como funciona esto internamente). El programa de usuario, o juego, comienza en el MainLoop. Esta clase tiene algunos métodos, para inicialización, idle (llamadas de retorno sincronizadas con los frames), fija (llamadas de retorno sincronizadas con física), y entrada. 48 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Nuevamente, Esto es realmente de bajo nivel y cuando haces juegos en Godot, escribir tu propio MainLoop ni siquiera tiene sentido. 1.12.3 SceneTree (Árbol de Escena) Una de las formas de explicar como Godot trabaja, es verlo como un motor de juegos de alto nivel sobre una middle- ware (lógica de intercambio de información entre aplicaciones) de bajo nivel. El sistema de escenas es el motor de juegos, mientras que OS y los servidores son la API de bajo nivel. En cualquier caso, el sistema de escenas provee su propio main loop al sistema operativo, SceneTree. Esto es automáticamente instanciado y ajustado cuando se corre la escena, no hay necesidad de trabajo extra. Es importante saber que esta clase existe porque tiene algunos usos importantes: Contiene la raiz Viewport, cuando una escena se abre por primera vez, es agregado como un hijo de ella para volverse parte del Scene Tree (mas sobre esto luego) Contiene información sobre los grupos, y tiene lo necesario para llamar a todos los nodos en un grupo, u obtener una lista de ellos. Contiene algo de funcionalidad sobre estados globales, como son ajustar el modo de pausa, o terminar el proceso. Cuando un nodo es parte de un Árbol de Escena, el singleton SceneTree puede ser obtenido simplemente llamando Node.get_tree(). 1.12.4 Viewport Raíz La raiz Viewport siempre esta en lo mas alto de la escena. Desde un nodo, puede ser obtenía de dos formas diferentes: get_tree().get_root() # acceso vía scenemainloop get_node("/root") # acceso vía camino absoluto Este nodo contiene el viewport principal, cualquier cosa que sea hijo de un Viewport es dibujado dentro de el por defecto, por lo que tiene sentido que por encima de todos los nodos siempre haya un nodo de este tipo, de otra forma no se vería nada! Mientras que otros viewports pueden ser creados en la escena (para efectos de pantalla dividida o similar), este es el único que nunca es creado por el usuario. Es creado automáticamente dentro de SceneTree. 1.12.5 Scene Tree (Arbol de Escena) Cuando un nodo es conectado, directa o indirectamente, a la raíz del viewport, se vuelve parte del Scene Tree. Esto significa que, como se explico en tutoriales previos, obtendrá los llamados de retorno _enter_tree() y _ready() (así como _exit_tree()) 1.12. Scene Tree (Árbol de Escena) 49 Godot Engine Documentation, Versión latest Cuando los nodos entran a Scene Tree, se vuelven activos. Obtienen acceso a todo lo que necesitan para procesar, obtener entradas, mostrar 2D y 3D, notificaciones, reproducir sonidos, grupos, etc. Cuando son removidos de la Scene Tree, lo pierden. 1.12.6 Orden del árbol La mayoría de las operaciones con Nodos en Godot, como dibujar 2D, procesar u obtener notificaciones son hechas en el orden de árbol. Esto significa que los padres y hermanos con menor orden van a ser notificados antes que el nodo actual. 1.12.7 “Volverse activo” por entrar la Scene Tree 1. Una escena es cargada desde disco o creada por scripting. 2. El nodo raíz de dicha escena (solo una raíz, recuerdan?) es agregado como un hijo del Viewport “root” (desde SceneTree), o hacia cualquier hijo o nieto de el. 50 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest 3. Todo nodo de la escena recientemente agregada, recibirá la notificacion “enter_tree” ( llamada de retorno _en- ter_tree() en GDScript ) en orden de arriba hacia abajo. 4. Una notificación extra, “ready” ( llamada de retorno _ready() en GDScript) se provee por conveniencia, cuando un nodo y todos sus hijos están dentro de la escena activa. 5. Cuando una escena (o parte de ella) es removida, reciben la notificación “exit scene” ( llamada de retorno _exit_tree()) en GDScript ) en orden de abajo hacia arriba. 1.12.8 Cambiando la escena actual Luego que una escena es cargada, suele desearse cambiar esta escena por otra. La forma simple de hacer esto es usar la funcion SceneTree.change_scene(): func _mi_nivel_fue_completado(): get_tree().change_scene("res://levels/level2.scn") Esta es una forma fácil y rápida de cambiar de escenas, pero tiene la desventaja de que el juego se detendrá hasta que la nueva escena esta cargada y corriendo. En algún punto de tu juego, puede ser deseable crear una pantalla de carga con barra de progresa adecuada, con indicadores animados o carga por thread (en segundo plano). Esto debe ser hecho manualmente usando autoloads (ve el próximo capitulo!) y Carga en segundo plano. 1.13 Singletons (AutoCarga) 1.13.1 Introducción Los Singletons de escena son muy útiles, ya que representan un caso de uso muy común, pero no es claro al principio de donde viene su valor. El sistema de escenas es muy útil, aunque propiamente tiene algunas desventajas: No hay lugar común donde almacenar información (como núcleo, ítems obtenidos, etc) entre dos escenas. Es posible hacer una escena que carga otras escenas como hijos y las libera, mientras mantiene la información, pero si esto es hecho, no es posible correr una escena sola por si misma y esperar que funcione. También es posible almacenar información persistente a disco en ‘user://‘ y hacer que las escenas siempre lo carguen, pero guardar y cargar eso mientras cambiamos de escenas es incomodo. Por lo tanto, luego de usar Godot por un tiempo, se vuelve claro que es necesario tener partes de una escena que: Están siempre cargadas, no importa que escena es abierta desde el editor. Puede mantener variables globales, como información de jugador, ítems, dinero, etc. Puede manejar cambios de escenas y transiciones. Solo ten algo que actúe como singleton, ya que GDScript no soporta variables globales por diseño. Por eso, la opción para auto-cargar nodos y scripts existe. 1.13.2 AutoLoad (AutoCarga) AutoLoad puede ser una escena, o un script que hereda desde Nodo (un Nodo sera creado y el script ajustado para el). Son agregados a el proyecto en Escena > Configuración de Proyecto > pestaña AutoLoad. 1.13. Singletons (AutoCarga) 51 Godot Engine Documentation, Versión latest Cada autoload necesita un nombre, este nombre sera el nombre del nodo, y el nodo siempre sera agregado al viewport root (raíz) antes de que alguna escena sea cargada. Esto significa, que para un singleton llamado “jugadorvariables”, cualquier nodo puede accederlo al requerirlo: var jugador_vars = get_node("/root/jugadorvariables") 1.13.3 Conmutador(Switcher) personalizado de escena Este corto tutorial explicara como hacer para lograr un conmutador usando autoload. Para conmutar una escena de forma simple, el método SceneTree.change_scene() basta (descrito en Scene Tree (Árbol de Escena)), por lo que este método es para comportamientos mas complejos de conmutación de escenas. Primero descarga la plantilla desde aquí: autoload.zip, y ábrela. Dos escenas están presentes, scene_a.scn y scene_b.scn en un proyecto que salvo por estas escenas esta vació. Cada una es idéntica y contiene un botón conectado a la llamada de retorno para ir a la escena opuesta. Cuando el proyecto corre, comienza en scene_a.scn. Sin embargo, esto no hace nada y tocar el boton no funciona. 1.13.4 global.gd Primero que nada, crea un script global.gd. La forma mas fácil de crear un recurso desde cero es desde la pestaña del Inspector: 52 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest Guarda el script con el nombre global.gd: El script debería estar abierto en el editor de scripts. El siguiente paso sera agregarlo a autoload, para esto, ve a: Escena, Configuración de Proyecto, Autoload y agrega un nuevo autoload con el nombre “global” que apunta a ester archivo: Ahora, cuando la escena corre, el script siempre sera cargado. Así que, yendo un poco atrás, en la función _ready(), la escena actual sera traída. Tanto la escena actual como global.gd son hijos de root, pero los nodos autocargados siempre están primeros. Esto implica que el ultimo hijo de de root es siempre la escena cargada. También, asegúrate que global.gd se extienda desde Nodo, de otra forma no sera cargada. extends Node var escena_actual = null func _ready(): var raiz = get_tree().get_root() escena_actual = raiz.get_child( raiz.get_child_count() - 1 ) 1.13. Singletons (AutoCarga) 53 Godot Engine Documentation, Versión latest Como siguiente paso, es necesaria la función para cambiar de escena. Esta función va a borrar la escena actual y reemplazarla por la que se pidio. func ir_escena(camino): # Esta función usualmente sera llamada de una señal de # llamada de retorno, o alguna otra función de la escena # que esta corriendo borrar la escena actual en este punto # puede ser una mala idea, porque puede estar dentro de una # llamada de retorno o función de ella. El peor caso va a # ser que se cuelgue o comportamiento no esperado. # La forma de evitar esto es difiriendo la carga para mas # tarde, cuando es seguro que ningún código de la escena # actual esta corriendo: call_deferred("_ir_escena_diferida",camino) func _ir_escena_diferida(camino): # Inmediatamente libera la escena actual, # no hay riesgo aquí. escena_actual.free() # Carga la nueva escena var s = ResourceLoader.load(camino) # Instancia la nueva escena escena_actual = s.instance() # Agrégalo a la escena activa, como hijo de root get_tree().get_root().add_child(escena_actual) # Opcional, para hacerlo compatible con la API SceneTree.change_scene() get_tree().set_current_scene( escena_actual ) Como mencionamos en los comentarios de arriba, realmente queremos evitar la situación de tener la escena ac- tual siendo borrada mientras esta siendo usada (el código de sus funciones aun corriendo), por lo que usando Ob- ject.call_deferred() es recomendado en este punto. El resultado es que la ejecución de los comandos en la segunda función van a suceder en un momento inmediatamente posterior inmediato cuando no hay código de la escena actual corriendo. Finalmente, todo lo que queda es llenar las funciones vacías en scene_a.gd y scene_b.gd: #agrega a scene_a.gd func _on_goto_scene_pressed(): get_node("/root/global").ir_escena("res://scene_b.scn") y #agrega a scene_b.gd func _on_goto_scene_pressed(): get_node("/root/global").ir_escena("res://scene_a.scn") Ahora, al correr el proyecto es posible conmutar entre ambas escenas al presionar el botón! 54 Capítulo 1. Aprendiendo paso a paso Godot Engine Documentation, Versión latest (Para cargar escenas con una barra de progreso, chequea el próximo tutorial, Carga en segundo plano) 1.13. Singletons (AutoCarga) 55 Godot Engine Documentation, Versión latest 56 Capítulo 1. Aprendiendo paso a paso CAPÍTULO 2 Motor 2.1 Escena, entrada y viewports 2.1.1 Viewports (Visores) Introducción Godot tiene una característica pequeña pero útil llamada viewports. Los Viewports son, como su nombre implica, rectángulos donde el mundo es dibujado. Tienen 3 usos principales, pero pueden ser flexiblemente adaptados para hacer mucho mas. Todo esto se hace con el nodo Viewport. Los principales usos de los que hablábamos son: Scene Root: Las raiz de la escena activa siempre es un viewport. Esto es lo que muestra las escenas creadas por el usuario. (Deberías saber esto de los tutoriales previos!) Sub-Viewports: Estos pueden ser creados cuando un Viewport es hijo de un Control. Render Targets:: Viewports pueden ser ajustadas en el modo “RenderTarget”. Esto implica que el viewport no es visible directamente, pero sus contenidos pueden ser accedidos con una Texture. Entrada Los viewports también son responsables de entregar eventos de entrada correctamente ajustados y escalados a todos sus nodos hijos. Ambos el root del viewport y sub-viewports hacen esto automáticamente, pero los rendertargets no. Por este motivo, es usuario debe hacerlo manualmente con la funcion Viewport.input() si es necesario. 57 Godot Engine Documentation, Versión latest Listener (Oyente) Godot soporta sonido 3D (tanto en nodos 2D como 3D), mas sobre esto puede ser encontrado en otro tutorial (un día..). Para que este tipo de sonido sea audible, el viewport necesita ser habilitado como un listener (para 2D o 3D). Si estas usando un viewport para mostrar tu mundo, no olvides de activar esto! Cámaras (2D y 3D) Cuando se usa una Camera Camera2D 2D o 3D, las cámaras siempre mostraran en el viewport padre mas cercano (yendo hacia root). Por ejemplo, en la siguiente jerarquía: Viewport Camera Las cámaras se mostraran en el viewport padre, pero en el siguiente orden: Camera Viewport No lo hará (o puede mostrarse en viewport root si es una subescena). Solo puede haber una cámara activa por viewport, por lo que si hay mas de una, asegúrate que la correcta tiene la propiedad “current” ajustada, o hazlo llamando: camera.make_current() Escala y estiramiento Los viewports tienen la propiedad “rect”. X e Y no son muy usados ( solo el viewport root realmente los utiliza), mientras WIDTH y HEIGHT representan el tamaño del viewport en pixels. Para sub-viewports, estos valores son sobrescritos por los del control padre, pero para render targets ajusta su resolución. ) También es posible escalar el contenido 2D y hacerle creer que la resolución del viewport es otra que la especificada en el rect, al llamar: viewport.set_size_override(w,h) #tamaño personalizado para 2D viewport.set_size_override_stretch(true/false) #habilita el estiramiento para tamaño ˓→personalizado El viewport root usa esto para las opciones de estiramiento en la configuración del proyecto. Worlds (Mundos) Para 3D, un viewport contendrá World. Este es básicamente el universo que une la física y la renderización. Los nodos Spatial-base serán registrados usando el World del viewport mas cercano. Por defecto, los viewports recientemente creados no contienen World pero usan el mismo como viewport padre (pero el viewport root no tiene uno, el cual es donde los objetos son renderizados por defecto). World puede ser ajustado en un viewport usando la propiedad “world”, y eso separara todos los nodos hijos de ese viewport de interactuar con el viewport world padre. Esto es especialmente útil en escenarios donde, por ejemplo, puedes querer mostrar un personaje separado en 3D impuesto sobre sobre el juego (como en Starcraft). Como un ayudante para situaciones donde puedes querer crear viewports que muestran objetos únicos y no quieres crear un mundo, viewport tiene la opción de usar su propio World. Esto es muy útil cuando tu quieres instanciar personajes 3D u objetos en el mundo 2D. 58 Capítulo 2. Motor Godot Engine Documentation, Versión latest Para 2D, cada viewport siempre contiene su propio World2D. Esto es suficiente en la mayoría de los casos, pero si se desea compartirlo, es posible hacerlo al llamar la API viewport manualmente. Captura Es posible requerir una captura de los contenidos del viewport. Para el viewport root esto es efectivamente una captura de pantalla. Esto es hecho con la siguiente API: # encola una captura de pantalla, no sucederá inmediatamente viewport.queue_screen_capture() Luego de un frame o dos (check_process()), la captura estará lista, obtenla usando: var capture = viewport.get_screen_capture() Si la imagen retornada esta vacía, la captura aun no sucedió, espera un poco mas, esta API es asincrónica. Sub-viewport Si el viewport es hijo de un control, se volverá activa y mostrara lo que tenga dentro. El diseño es algo como esto: Control Viewport El viewport cubrirá el área de su control padre completamente. 2.1. Escena, entrada y viewports 59 Godot Engine Documentation, Versión latest Render target (objetivo de renderizacion) Para ajustar como un render target, solo cambia la propiedad “render target” de el viewport a habilitado. Ten en cuenta que lo que sea que esta dentro no será visible en el editor de escena. Para mostrar el contenido, la textura de render target debe ser usada. Esto puede ser pedido con código usando (por ejemplo): var rtt = viewport.get_render_target_texture() sprite.set_texture(rtt) Por defecto, la re-renderizacion del render target sucede cuando la textura del render target ha sido dibujada en el frame. Si es visible, será renderizada, de otra contrario no lo será. Este comportamiento puede ser cambiado a renderizado manual (una vez), o siempre renderizar, no importando si es visible o no. Algunas clases son creadas para hacer esto mas sencillo en la mayoría de los casos dentro del editor: ViewportSprite (para 2D). Asegúrate de chequear los demos de viewports! La carpeta viewport en el archivo disponible para descarga en el sitio principal de Godot, o https://github.com/godotengine/godot/tree/master/demos/viewport 2.1.2 Resoluciones múltiples Resolución base Una resolución de pantalla base para el proyecto puede ser especificada en configuración de proyecto. Sin embargo, lo que hace no es completamente obvio. Cuando corre en PC, el motor intentara ajustara esta reso- lución (o usar algo mas chico si falla). En equipos móviles, consolas u otros dispositivos con una resolución fija o renderizacion de pantalla completa, esta resolución será ignorada y la resolución nativa se usara en su lugar. Para com- pensar esto, Godot ofrece muchas formas de controlar como la pantalla va a cambiar de tamaño y estirarse a diferentes tamaños de pantalla. Resizing (Cambiar de tamaño) Hay varios tipos de dispositivos, con varios tipos de pantalla, los cuales a su vez tienen diferente densidad de pixels y resolución. Manejarlos todos puede ser un montón de trabajo, asique Godot trata de hacer la vida del desarrollador un poco mas fácil. El nodo Viewport tiene varias funciones para manejar el cambio de tamaño, y el nodo root de la escena es siempre un viewport (las escenas cargadas son instanciadas como hijos de el, y siempre se pueden acceder llamando get_tree().get_root() o get_node("/root")). En cualquier caso, mientras cambiar los parámetros del viewport root es probablemente la forma mas flexible de atender este problema, puede ser un montón de trabajo, código y adivinanza, por lo que Godot provee un rango de parámetros simple en la configuración de proyecto para manejar múltiples resoluciones. 60 Capítulo 2. Motor Godot Engine Documentation, Versión latest Configuraciones de estiramiento Las configuraciones de estiramiento están localizadas en la configuración de proyecto, es solo un montón de variables de configuración que proveen varias opciones: Modo de estiramiento Disabled: Lo primero es el modo de estiramiento. Por defecto esta deshabilitado, lo que significa que no hay estiramiento (cuanto mas grande la pantalla o ventana, mas grande la resolución, siempre igualando pixeles 1:1). 2D: En este modo, la resolución especificada en display/width y display/height en la configuración del proyecto será estirada para cubrir la pantalla entera. Esto implica que 3D no sera afectado ( solo va a renderizar a una resolución mas alta) y 2D también será renderizado a una resolución mayor, solo que agrandada. Viewport: El escalado de viewport es diferente, el Viewport root se ajusta como un render target, y aun renderiza precisamente a la resolución especificada en la sección display/ de la configuración de proyecto. Finalmente, este viewport es copiado y escalado para entrar a la pantalla. Este modo es útil cuando trabajas con juegos que requieren precisión de pixeles, o solo con el motivo de renderizar a una resolución mas baja para mejorar la performance. Aspecto de estiramiento Ignore: Ignorar la relación de aspecto cuando se estire la pantalla. Esto significa que la resolución original será estirada para entrar en la nueva, aun cuando sea mas ancha o mas angosta. Keep: Mantener la relación de aspecto cuando se estire la pantalla. Esto implica que la resolución original será mantenida cuando se ajuste a una nueva, y barras negras serán agregadas a los costados o borde superior e inferior de la pantalla. 2.1. Escena, entrada y viewports 61 Godot Engine Documentation, Versión latest Keep Width: Mantener la relación de aspecto cuando se estira la pantalla, pero si la resolución de pantalla es mas alta que la resolución especificada, será estirada verticalmente (y una mayor resolución vertical será reportada en el viewport, proporcionalmente) Esta es usualmente la mejor opción para crear GUIs o HUDs que se escalan, asi algunos controles pueden ser anclados hacia abajo (Tamaño y anclas). Keep Height: Mantener la relación de aspecto cuando se estira la pantalla, pero si la pantalla resultante es mas ancha que la resolución especificada, será estirada horizontalmente (y mas resoluciones horizontales serán reportadas en el viewport, proporcionalmente). Esta es usualmente la mejor opción para juegos 2D que tienen scroll(desplazamiento) horizontal (como juegos de plataforma) 2.1.3 InputEvent (Evento de Entrada) Que es? Gestionar entradas es usualmente complejo, no importa el SO o la plataforma. Para facilitarlo un poco, un objeto especial incorporado se provee, InputEvent. Este tipo de datos puede ser configurado para contener varios tipos de eventos de entrada. Input Events viaja a través del motor y puede ser recibido en múltiples lugares, dependiendo del propósito. Como funciona? Cada evento de entrada se origina desde el usuario/jugador (aunque es posible generar un InputEvent y dárselo de vuelta al motor, lo cual es util para gestos). El objeto OS para cada plataforma va a leer eventos desde el dispositivo, luego pasándoselo al MainLoop. Como SceneTree es la implementación por defecto de MainLoop, los eventos se envían allí. Godot provee una función para obtener el objeto SceneTree actual: get_tree() Pero SceneTree no sabe que hacer con este evento, por lo que se lo va a dar a los viewports, empezando desde “root” Viewport (el primer nodo del arbol de escena). Viewport hace una cantidad considerable de cosas con la entrada recibida, en orden: 62 Capítulo 2. Motor Godot Engine Documentation, Versión latest 1. Primero, intentara darle la entrada a la GUI, y ver si algún control lo recibe. De ser asi, Control será llamado por la función virtual Control._input_event() y la señal “input_event” sera emitida (esta función es reimplementable por script al heredarla). Si el control quiere “consumir” el evento, va a llamar Control.accept_event() y el evento no se esparcirá mas. 2. Si la GUI no quiere el evento, la función standard _input sera llamada en cualquier nodo con procesamiento de entrada habilitado (habilítalo con Node.set_process_input() y sobrescribe Node._input()). Si alguna función consume el evento, puede llamar SceneTree.set_input_as_handled(), y el evento no se esparcirá mas. 3. Si aun nadie consumió el evento, la llamada de retorno unhandled será invocada (habilítala con No- de.set_process_unhandled_input() y sobrescribe Node._unhandled_input()). Si alguna funcion consume el even- to, puede llamar a SceneTree.set_input_as_handled()„ y el evento no se esparcirá mas. 4. Si nadie ha querido el evento hasta ahora, y una Camera es asignada al viewport, un rayo al mundo de física (en la dirección de rayo del clic) será emitido. Si este rayo toca un objeto, llamara a la funcion CollisionOb- ject._input_event() en el objeto físico relevante (los cuerpos reciben esta llamada de retorno por defecto, pero las áreas no. Esto puede ser configurado a través de las propiedades Area). 2.1. Escena, entrada y viewports 63 Godot Engine Documentation, Versión latest 5. Finalmente, si el evento no fue utilizado, será pasado al siguiente Viewport en el árbol, de otra forma será ignorado. Anatomía de un InputEvent InputEvent es solo un tipo base incorporado, no representa nada y solo contiene información básica, como el ID de evento (el cual es incrementado para cada evento), índice de dispositivo, etc. InputEvent tiene un miembro “type”. Al asignarlo, se puede volver diferentes tipos de entrada. Todo tipo de InputEvent tiene propiedades diferentes, de acuerdo a su rol. Ejemplo de un tipo de evento cambiante. # crear evento var ev = InputEvent() # ajustar tipo index (índice) ev.type = InputEvent.MOUSE_BUTTON # button_index solo esta disponible para el tipo de arriba ev.button_index = BUTTON_LEFT Hay varios tipo de InputEvent, descritos en la tabla de abajo: Evento Type Index Descripción InputEvent NONE Evento de entrada vacío. InputEventKey KEY Contiene un valor scancode y unicode, además de modificadores. InputEventMou- MOU- Contiene información de clics, como botón, modificadores, etc. seButton SE_BUTTON InputEventMou- MOU- Contiene información de movimiento, como pos. relativas y absolutas, seMotion SE_MOTION velocidad InputEventJoys- JOYS- Contiene información de ejes análogos de Joystick/Joypad tickMotion TICK_MOTION InputEventJoys- JOYS- Contiene información de botones de Joystick/Joypad tickButton TICK_BUTTON InputEventS- SCREEN_TOUCHContiene información multi-touch de presionar/soltar. (solo disponible en creenTouch dispositivos móviles) InputEventS- SCREEN_DRAGContiene información multi-touch de arrastre (solo en disp. móviles) creenDrag InputEventAc- SCREEN_ACTION Contiene una acción genérica. estos eventos suelen generarse por el tion program- ador como feedback. (mas de esto abajo) Acciones Un InputEvent puede o no representar una acción predefinida. Las acciones son útiles porque abstraen el dispositivo de entrada cuando programamos la lógica de juego. Esto permite: Que el mismo código trabaje en diferentes dispositivos con diferentes entradas (por ej. teclado en PC, Joypad en consola). Entrada a ser reconfigurada en tiempo de ejecución. Las acciones pueden ser creadas desde la Configuración de Proyecto en la pestaña Actions. Lee Configuración de acciones de entrada para una explicación de como funciona el editor de acciones. Cualquier evento tiene los metodos InputEvent.is_action(), InputEvent.is_pressed() y InputEvent. 64 Capítulo 2. Motor Godot Engine Documentation, Versión latest De forma alternativa, puede desearse suplir al juego de vuelta con una acción desde el código (un buen ejemplo es detectar gestos). SceneTree (derivado de MainLoop) tiene un método para esto: MainLoop.input_event(). Se usaría normalmente de esta forma: var ev = InputEvent() ev.type = InputEvent.ACTION # ajustar como move_left, presionado ev.set_as_action("move_left", true) # feedback get_tree().input_event(ev) InputMap (Mapa de controles) Personalizar y re mapear entrada desde código es a menudo deseado. Si tu worflow depende de acciones, el singleton InputMap es ideal para reasignar o crear diferentes acciones en tiempo de ejecución. Este singleton no es guardado (debe ser modificado manualmente) y su estado es corrido desde los ajustes de proyecto (engine.cfg). Por lo que cualquier sistema dinámico de este tipo necesita guardar su configuración de la forma que el programador lo crea conveniente. 2.1.4 Coordenadas de mouse y entrada Acerca La razón de este pequeño tutorial es aclarar muchos errores comunes sobre las coordenadas de entrada, obtener la posición del mouse y resolución de pantalla, etc. Coordenadas de pantalla de hardware Usar coordenadas de hardware tiene sentido en el caso de escribir UIs complejas destinada a correr en PC, como editores, MMOs, herramientas, etc. De todas formas, no tiene mucho sentido fuera de ese alcance. Coordenadas de pantalla de viewport Godot usa viewports para mostrar contenido, los cuales puede ser escalados de varias maneras (vee el tutorial Resolu- ciones múltiples). Usa, pues, las funciones de los nodos para obtener las coordenadas de mouse y tamaño del viewport, por ejemplo: func _input(ev): # Mouse en coordenadas viewport if (ev.type==InputEvent.MOUSE_BUTTON): print("El mouse fue Click/Unclick en: ",ev.pos) elif (ev.type==InputEvent.MOUSE_MOTION): print("Movimiento de mouse en: ",ev.pos) # Imprime el tamaño del viewport print("La resolución del viewport es: ",get_viewport_rect().size) func _ready(): set_process_input(true) 2.1. Escena, entrada y viewports 65 Godot Engine Documentation, Versión latest Alternativamente es posible pedir al viewport la posición del mouse: get_viewport().get_mouse_pos() 2.2 Filesystem (Sistema de archivos) 2.2.1 Organización de proyectos Introducción Este tutorial esta dirigido a proponer un workflow simple sobre como organizar proyectos. Debido a que Godot permite que el programador use el sistema de archivos como el o ella quieren, encontrar una forma de organizar los proyectos cuando empiezas a usar el motor puede ser algo difícil. Por esto, un workflow simple sera descrito, el cual puede ser usado o no, pero deberia servir como un punto inicial. Ademas, usar control de versiones puede ser un rato, por lo que este documento también lo incluirá. Organización Otros motores de juegos a menudo trabajan teniendo una base de datos, donde puedes navegar imágenes, modelos, so- nidos, etc. Godot es mas basado en escenas por naturaleza así que la mayor parte del tiempo los assets están empacados dentro de las escenas o simplemente existen como archivos pero no referenciados desde escenas. Importación & directorio del juego Es muy a menudo necesario usar la importación de assets en Godot. Como los assets de origen para importar también son reconocidos como recursos por el motor, esto puede volverse un problema si ambos están dentro de la carpeta de proyecto, porque al momento de exportar el exportador va a reconocerlos y exportar ambos. Para resolver esto, es una buena practica tener tu carpeta de juego dentro de otra carpeta (la verdadera carpeta del proyecto). Esto permite tener los assets del juego separados de los assets de origen, y también permite el uso de control de versiones (como svn o git) para ambos. Aquí hay un ejemplo: myproject/art/models/house.max myproject/art/models/sometexture.png myproject/sound/door_open.wav myproject/sound/door_close.wav myproject/translations/sheet.csv Luego también, el juego en si, en este caso, dentro de la carpeta game/: m

Use Quizgecko on...
Browser
Browser