Interfaz de usuario
Crearemos un nodo llamado "interfaz de usuario" y lo guardaremos en una carpeta de escenas y luego iremos a temas, crearemos una fuente dinámica (en setting ajustamos el amaño de las letras), un font data y añadiremos nuestra fuente .ttf
Luego crearemos un nodo panel, y en las opciones de inspector modificaremos su tamaño en "rect", un estilo personalizado en "custom style" en el cuál modifcaremos el color, la transparencia, el grosor del borde y su color
Ahora para añadir un fondo al panel vamos a agregar un nodo "TextureRect" y debemos ubicarlo antes del panel para que se vea de fondo
Arrastramos la textura, activamos "expand" para que podamos cambiar las dimensiones d el imagen y también activaremos "Keep Aspect"
Variables multidimensionales
Vamos a crear un script tipo visual script en el panel y agregaremos presionando el signo + una nueva variable y la editaremos para que se tipo str. Lo re nombraremos como "Idiomaobjetivo"
Ahora agregaremos una nueva variable con el signo + pero de tipo diccionario. Éste tipo de variables permite almacenar una o varias variables y asociarlas a una clave. La clave es la palabra y el valor la definición. A esta la llamaremos "Menu"
Vamos a presionar sobre diccionario y se nos creara un clave-valor. Luego podemso definir el tipo de las claves y los valor
La clave la seleccionaremos como string y el valor como "PoolStringArray" que nos permite crear una lista de la variable seleccionada.
Luego aumentamos el valor que tenemos a bajo que sirve para introducir variables de tipo string. Usaremos el 3 y a cada uno le pondremos el nombre respectivo de nuestro menú: Nuevo - English - Salir. Luego presionamos en "Agregar Par Clave/Valor". De ésta forma se añade la primera variable a nuestro diccionario
Ahora crearemos un nuevo par clave-valor de la misma forma, para las traducciones al inglés. La clave será tipo string con el nombre de English, el valor será tipo "PoolStringArray" y agregaremos 3 variables: New - Español - Exit
Entonces lo que haremos será cambiar el texto de los botones según el idioma seleccionado. Para ello:
1. Teniendo seleccionado el nodo de botón "Salir" conectaremos la señal "Pressed" al script que estamos editando y crearemos con ello un nodo
2. Ahora debemos obtener el texto contenido en el botón idioma e incluirlo dentro de la variable que creamos al principio. Esa variable llamada "idiomaobjetivo" la arrastraremos a visual script, pero antes de soltarlo presionamos Ctrl para que se agreguen las entradas. Luego lo conectamos con el otro nodo como secuencia
3. Arrastramos la propiedad text del botón idioma nuevamente presionando Ctrl para que se agregue el puerto de datos str, le cuál conectaremos a la entrada str del nodo "idiomaobjetivo".
4. Ahora debemos cambiar el texto del botón "Nuevo", entonces arrastramos al propiedad text del botón "Nuevo" y lo uniremos como secuencia .
5. Ahora debemos especificar el texto que queremos usar para el botón "nuevo". Ese texto varía según los valores del diccionario que hemos creado. Arrastraremos la variable "Diccionario" que nombramos "menu" lo cuál creará un nuevo nodo que permite obtener todos los valores.
6. Recordemos que dentro de esta variable tenemos dos claves, una para cada idioma. Lo que debemos hacer es extraer una a una las cadenas de texto para así añadirlas al nodo "Set text" de los botones. Para ello usaremos la función "Dictionary Get" que se agrega desde el visor. Éste nodo presenta 3 puertos de entrada y un puerto de datos de salida. En el primer puerto debemos especificar la variable "Dictionary" que en nuestro caso es la variable "menu". Los conectamos.
7. El segundo puerto de entrada debemos especificar una clave de nuestro diccionario. Ésta clave viene definida por la variable "idiomaobjetivo" por lo quedemos arrastrarlo y conectara.
8. Ahora necesitamos extraer uno a uno los elementos de la lista. Para ello añadiremos el nodo "Array get index". Dentro de éste nodo debemos indicar cuál es la variable que contiene la lista de elementos. Para ello conectamos la salida del nodo dictionary get a la entrada "base" de "Get index".
9. En segundo lugar debemos especificar el número de elementos que debemos extraer. Para ello agregamos el nodo "constant". Teniendo seleccionado el nodo en inspector debemos cambiar a "int". El valor que tendremos es cero correspondiente al primero de la lista. Éste nodo entonces lo conectamos a la entrada "index" del nodo "Get index". La salida del nodo index la conectamos a la entrada del nodo "set tex" correspondiente al boton "Nuevo"
10. Ahora debemos hacer lo mismo con los otros botones "Idioma" y "Salir" por lo que debemos arrastrar su respectivas propiedades de texto y los conectaremos como secuencia al primer nodo de propiedad de texto llamado "Set text"
11. Duplicaremos dos veces los nodos "Get index" y "Constant" y conectaremos en ambas entradas "Base" la salida del nodo "Dictionary Get" y a cada nodo constant le cambiaremos el valor correspondiente según el listado, 1 y 2 respectivamente
12. Luego conectaremos las salidas de cada nodo "Get indext" con las entradas de los nodos "Set text" correspondientes
Nodo iterador
El problema que tenemos es que para ésta configuración tenemos que repetir. En el caso de que fueran más botones el código sería muy largo. Para ello es necesario usar el nodo iterador. Este nodo permite repetir un conjunto de acciones el numero de veces especificado en el puerto de datos de entrada. En nuestro caso el numero de veces que repetiremos las acciones depende del numero de botones que tengamos.
1. Agregamos el nodo iterador y lo conectamos con la salida del "Set idiomaobjetivo"
2. Para especificar el numero de botones debemos usar el nodo "Get child count" el cuál debemos conectar al puerto de datos de entrada del nodo Set idiomaobjetivo
3. El puerto de datos de salida del nodo Set idiomaobjetivo etiquetado como "each" permite definir el conjunto de acciones que deseamos repetir y como nuestro objetivo es repetir 3 veces la operación Set text de cada botón lo unimos a este nodo
4. El puerto de datos de salida del nodo Set idiomaobjetivo etiquetado como "elem" permite obtener el valor actual del bucle que en nuestro caso es entre 0 y 2. Por lo tanto debemos conectar ésta salida a la entarda "index" del nodo "Get index" que recordemos que éste extraía uno a uno los elementos de la lista
5.Lo que necesitamos ahora es que el nodo "Sext text" se aplique en el orden correspondiente, primero el botón "nuevo", luego el botón "idioma", luego el botón "salir". Para ello debemos seleccionar el nodo "Set text" y en inspector cambiar la propiedad que tenemos en set mode que es "Node path" pues ésta lo que hace es funcionar solo para un nodo concreto, que en éste caso es el botón nuevo (donde se arrastró ésta propiedad). Debemos entonces cambiar ésta opción por "instance". Con ello se agrega un nuevo puerto de datos llamado "obj". Aquí el cambio de texto se aplicará sobre el objeto que indiquemos
6. En el puerto "obj" debemos indicar los 3 botones, uno después del otro y de forma automática. Para ello necesitamos el nodo "Get child (int)". Ésta opción devuelve el nodo hijo atendiendo a un valor numérico. Éste valor corresponde al orden establecido dentro de la jerarquía, el botón nuevo 0, el botón idioma 1 y el botón salir 2. Esa iteración y a vimos que se obtiene de la salida "elem" del nodo iterador. Por lo tanto conectamos esa salida a la entrada de éste nodo. Luego la salida de este nodo a la entrada "obj" del nodo "set text".
Cambio de escena
Teniendo un panel principal como el que tenemos con 3 botones: Nuevo, idioma, y salir. Queremos que al presionar "Nuevo" podamos entrar a una nueva escena ,que sería la escena del juego.
Nuestro objetivo entonces es saltar a la escena 3d al pulsar el botón nuevo, para ello debemos crear un script sobre el botón "Nuevo". Crearemos un de tipo visual script.
1. Conectamos la señal pressed() con el botón Nuevo para que se cree el nodo
2. Para llamar al sistema de escenas y cambiar de pantalla de juego debemos agregar el nodo "Scene tree"
3. Si salimos desde el puerto de salida obj del nodo "Scene tre" se abrirá una nueva ventana con las funciones especificas del sistema de escenas. Vamos a buscar la función "Chaneg scene". Éste nodo función nos permite cambiar a un nuevo nivel guardado dentro del sistema de archivos de nuestro proyecto. En donde dice Null debemos definir la ruta del archivo de la escena. En éste caso es la escena laberinto. En nuestro sistema de archivos copiamos la ruta y la pegamos en Null con Ctrl+V. Finalmente unimos los puertos de secuencia con el nodo "Scene tree"
Salir del juego
Creamos un script en el botón "Salir" y seguimos los mismos pasos anteriores pero en vez de usar el nodo "change scene" usaremos "quick"
Personajes
Godot soporta varios formatos, entre ellos Collada .Dae. Vamos a crear una carpeta de personaje que contendrá el modelo en formato .dae con sus animaciones en 60fps, y sus texturas. Las animaciones las descargaremos en ese formato desde https://www.mixamo.com/
Godot trabaja con materiales PBR por lo que si tenemos una textura difuso (que contiene sombras) no es compatible por lo que debemos pasarla a "albedo". Para ello podemos ir al sitio web https://pixlr.com/x/
Arrastramos la imagen y luego la duplicamos
Luego seleccionamos "Soft-light"
Luego seleccionamos invert y bajamos al saturación
Luego la descargamos con el sufijo albedo
Luego de tener todas las texturas en una carpeta dentro de nuestro sistema de archivos, hacemos clic en "material" y arrastramos las texturas pertinentes
Cada archivo se abre en una nueva escena con tres nodos, entre ellos el nodo "AnimationPlayer" que es la animación misma. En nuestro caso tenemos la animación de reposo (Idle) y la animación de correr (run). Necesitamos tener las animaciones en un solo archivo. Para ello primeramente guardamos la animación con "Guardar como" desde la ventana de animación
Como guardamos la animación run, ahora la cargaremos en donde tenemos la animación Idle
Ahora tenemos las dos animaciones. Recordemos que para que la animación sea constante debemos presionar "loop de aniamción"
Ahora necesitamos guardar la escena con una extensión propia de Godot. Así que la guardaremos con "Guardar Escena como"
Maquina de estado
Para realizar una maquina de estado sobre el personaje debemos agregar el nodo "AnimationTree". Éste tipo de nodo permite controlar las animaciones mediante distintas herramientas.
1. Primero teniendo seleccionado el nodo "AnimationTree" iremos a inspector y en Tree Root seleccionaremos "AnimationNodeStateMachine"
2. Luego en AnimPlayer seleccionaremos "AnimationPlayer"
3. Para indicarle a Godot que el nodo AniamtionTree tiene control sobre las animaciones debemos tiquear la casilla "Activado"
Luego en la ventana inferior del visor 3d crearemos nuestro árbol de animaciones.
1. Haciendo clic con el botón derecho del ratón sobre un área vacía podemos agregar una animación
2. Luego de agregar nuestras animaciones debemos hacer una conexión entre ellas (en este caso Idle con Run) y lo haremos presionando la tecla Shift
3. Si pulsamos dicha conexión podemos establecer ciertas propiedades de la transición en inspector. Por ejemplo tenemos "Advante Condition" que nos permite crear una variable boleana para activar la transición. En nuestro caso escribiremos "mover"
4. Luego la propiedad Xfade tame permite establecer el tiempo de transición entre las animaciones. En nuestro caso colocaremos 0.1
5. Ahora para hacer la transición a la inversa hacemos lo mismo de arrastrar con shift pero en sentido contrario
Programación de estados
Agregaremos un visual script al nodo "AnimationTree" y seguiremos los siguientes pasos:
1. En el icono de la carpeta donde dice funciones añadiremos al función "input".
2. Teniendo seleccionado el nodo "AnimationTree" iremos a isnpector y en la pestaña "Conditions" de la pestaña "parameters" arrastraremos la propiedad "Idle" y la propiedad "Move". Luego los conectamos todos como secuencia comenzando pro function, luego move y fianlmente idle
3. Añadiremos el nodo "action" y en inspector lo configuraremos para detectar la tecla de dirección arriba "ui_up" y lo conectaremos en el puerto de datos de entrada del node "Move" para que así cuando la tecla esté pulsada, la condición run cambié a verdadero y comience la animación
4. Finalmente añadimos el nodo "Logic Not" y lo conectaremos en la entrada de datos con el nodo action y en la salida de datos con la entrada del nodo "Idle". Así establece la variable condicional Idle en el estado inverso en que se encuentra la tecla de dirección arriba (ui_up)
Añadir personaje a la escena del juego
Para añadir nuestro personaje principal a nuestra escena lo primero que debemos hacer es agregar el nodo "KinematicBody" como hijo del nodo spacial e instanciar la escena donde está el persona je usando el icono de cadena
Luego, como hijo del nodo kinematicBody agregamos el nodo "Collisionshape", seleccionamos el tipo capsula y lo ajustamos
Instancias únicas
En nuestro nodo raíz crearemos un visual script. Para así añadir una instancia única, las cuales sirven para modificar propiedades como por ejemplo la calidad gráfica, la resolución, entre otros.
1. Añadiremos el nodo "Engine singleton" que es un nodo con acceso a las instancias únicas y en inspector abriremos las opciones de constant que es donde elegiremos el tipo de propiedad a modificar, tenemos por ejemplo OS que sirve para modificar la resolución de la pantalla, cambiar el titulo de la ventana, entre otros. En nuestro caso usaremos el input que nos servirá para ocultar y bloquear el movimiento del ratón
2. Si salimos del nodo Engine singleton abriremos un listado y elegiremos "Set mouse mode". Éste nodo tiene una entrada de datos int en donde podemos cambiar el valor teniendo cada uno de ellos una función: 0. Mostrar el cursor. 1. Ocultar el cursor. 2. Ocultar y bloquear el cursor. 3. Mostrar y restringir la zona del cursor. vamos a elegir al función 2
3. Ahora dándole clic al icono de la carpeta añadiremos la función ready y la conectaremos en el puerto de secuencia de entrada del nodo "Set mouse mode". De ésta forma cuando se inicie el juego el cursor estará oculto y confinado dentro de la ventana de juego
4. Ahora vamos a añadir una función para volver a mostrar el cursor cuando el usuario pulse la tecla "Esc". Para ello desde el icono de carpeta añadiremos la función "input"
5. Añadiremos el nodo "condition" y lo conectaremos con el puerto de secuencia de salida del nodo input
6. Añadiremos el nodo "Action" y lo conectaremos con el puerto de datos de entrada del nodo condition y en inspector cambiaremos la tecla a "cancel" correspondiente a Esc
7. Duplicaremos los nodos Engine singleton y Set mouse mode. En éste ultimo nodo modificaremos el valor a 0 que corresponde a "Mostrar el cursor" y lo uniremos con el puerto de secuencia de salida True del nodo condition
Control de cámara con el ratón
Para poder controlar la rotación de la cámara en torno al personaje necesitamos crear un nodo spacial. Éste debemos crearlo como hijo del nodo kinematicbody correspondiente al personaje principal . Luego el nodo de cámara debemos arrastrarlo a este nodo y ajustarlo en la posición correcta. Si seleccionamos el nodo spacial y rotamos la cámara sigue al personaje
Ahora vamos a crear un visualscript para que la cámara rote siguiendo los movimientos del ratón. El script debemos añadirlo al nodo spacial del personaje el cuál renombraremos como "referencia de cámara" y seguiremos los siguientes pasos:
1. Añadimos al función "input" desde le icono de carpeta. Ésta función se activa si pulsamos una tecla, movemos el ratón o controles de un joystick
2. Luego agregamos el nodo "TypeCast" para restringir las acciones. Conectaremos cada puerto, el de secuencia y de datos respectivamente con el nodo input. Gracias a este nodo podremos especificar que tipo de entrada estamos esperando. Ésto lo debemos especificar dando clic en el nodo, yendo a la propiedad "base type" de inspector y seleccionar "InputEventMouseMotion" para definir el movimiento del ratón como señal necesaria para ejecutar las acciones
3. Ahora teniendo seleccionado el nodo spacial (referencia de cámara) iremos a inspector y arrastraremos la propiedad de rotación y conectaremos la entrada de secuencia de este nodo con la salida de secuencia del nodo TypeCast. De ésta forma si movemos el ratón el nodo de referencia de cámara rotará una cantidad
4. Ahora necesitamos determinar cuanto será la cantidad de rotación. Lo que dependerá de dos factores: La rotación actual y el movimiento realizado por el ratón. La rotación actual la obtenemos arrastrando la misma propiedad de rotación pero con Ctrl presionado antes de soltar para que éste nodo se convierta en un nodo con salida tipo vector
5. Luego debemos salir del nodo "Get rotación degress" a una zona vacía del visor y nos aparecerá una lista, buscaremos "Deconstruct vector"
6. Para obtener el movimiento del ratón debemos salir del puerto de datos de salida del nodo type cast a una zona vacía del visor y nos aparecerá una lista, buscaremos "Obtener relative"
7. Para descomponer éste vector (que es una variable vectorial de dos dimensiones) debemos salir del puerto de datos de salida de este nodo a una zona vacía del visor y nos aparecerá una lista, buscaremos "Deconstruct vector" (en su versión de dos componentes)
Ahora debemos rotar la cámara con el movimiento del ratón. Para ello debemos conocer los ejes que intervienen en dicha rotación. Por ello es recomendable ir a la vista 3d y probar rotando los ejes X e Y del nodo spacial para ver cuál es el limite que nos servirá. En nuestro caso acotaremos el angulo de X entre -20 y 15, y el ángulo Y entre 90 y -90.
Al valor X de la propiedad rotación debemos añadirle o sustraerle el valor Y del movimiento del ratón y al valor Y de la propiedad rotación debemos añadirle o sustraerle el valor X del movimiento del ratón. Agregaremos los nodos "Math Add" y "Math Subtract". A cada uno le modificaremos la propiedad type de inspector a "flotante". Usaremos la suma para el eje X y la resta para el eje Y.
8. Por lo tanto conectaremos la salida Y del nodo Deconstruct vector (correspondiente al movimiento del ratón) a la entrada A del nodo Subtract y conectaremos la salida X del nodo Deconstruct vector (correspondiente a la rotación actual) a la entrada B de este mismo nodo por lo que estaremos.
9. Ahora, conectaremos la salida X del nodo Deconstruct vector (correspondiente al movimiento del ratón) a la entrada B del nodo Add, y conectaremos la salida Y del nodo Deconstruct vector (correspondiente a la rotación actual) a la entrada A de este mismo nodo por lo que estaremos.
10. Ahora, como es necesario limitar la rotación del eje X de la cámara para evitar giros verticales no deseados. Para ello añadiremos el nodo "Clamp". Éste nodo limita el valor de una variable usando una cota superior e inferior. El valor que usaremos será -20 y 20. Éste lo conectaremos con el puerto de salida del nodo Add
11. Ahora debemos crear un nodo que de-construya el vector de tres dimensiones por lo que usaremos el nodo "Construct vector 3XYZ". Conectaremos la salida del nodo clamp con la entrada X, la salida del nodo resta con la entrada Y, y la salida Z del nodo "Deconstruct vector" a la entrada Z.
12. Finalmente conectamos la salida de este ultimo nodo al puerto de datos de entrada de "Set rotation"
Añadir librería de objetos
Luego de arrastrar nuestros objetos 3d para nuestra librería a un nuevo escenario crearemos los materiales en "Nuevo recurso" y escogeremos "SpacialMaterial". Ésto cada vez que creemos un nuevo material
Luego seleccionando cada objeto arrastraremos los materiales que hemos creado
Ahora debemos añadir los nodos de collision a nuestros objetos. La manera más fácil de hacerlo es mediante el menú malla. Si seleccionamos "Crear StaticBody Triangular" se crean los nodos necesarios para que cualquier objeto dinámico pueda colisionar con las paredes
Ahora vamos a convertir nuestro escenario en una biblioteca de mallas desde el menú "escenas". La guardaremos en nuestra carpetas de objetos con la extensión .meshlib
Ahora iremos al escenario principal y añadiremos el nodo "GridMap"
Luego en inspector podemos arrastrar nuestra librería
Ahora tendremos nuestros objetos en una nueva ventana y podemos arrastrarlos a nuestro espacio 3d. Para rotar la geometría de los muros usamos S, para subir el nivel de la posición del objeto hacía arriba o hacia a bajo tenemos al opción plano. El comando para subir es E y para bajar Q. Para ponerlo en forma vertical es Z y volver a horizontal X. Con Esc se cancela. También podemos configurar la cantidad de celdas en las que se mueve
Matriz de transformación
Cuando aplicamos una fuerza sobre un cuerpo controlado por el motor de física necesitamos indicarle a Godot cuál es la dirección y la magnitud haciendo uso de un vector de dos o tres componentes. Ese vector se define según los ejes del espacio global por lo que no respeta la orientación de nuestro objeto. Por ejemplo, para mover nuestro personaje principal debemos movernos en el eje Z de nuestro espacio global
Pero si giramos nuestro objeto 90 grados en el eje Y, para mover nuestro personaje hacia adelante deberíamos hacerlo ahora en el eje X
Para solventar este problema existe un recurso matemático llamado "Matriz de transformación" . Lo podemos ver en inspector en la ventana "matriz". Está formado por dos componentes:
1. La base: Está formado por tres vectores que nos permiten conocer la orientación de los ejes x, y, z del espacio local de un objeto con respecto a las coordenadas x, y, z del espacio global
2. El origen:
Podemos activar y desactivar la vista local desde el icono del cubo
Control de personaje en tercera persona
Agregaremos un visual script al personaje principal
1. Añadimos la función "physics_process"
2. Luego agregamos el nodo condition y lo conectamos como secuencia
3. Luego el nodo action con la tecla discrecional hacia arriba (ui_up) que lo conectaremos en el puerto de datos de entrada del nodo condition
Las acciones que queremos que el personaje realice son dos: Orientar el personaje hacia la dirección opuesta a la cámara y mover el personaje hacia adelante
4. Para orientar el personaje hacia la dirección opuesta necesitamos la propiedad de rotación. Seleccionamos el nodo del personaje principal y arrastraremos esa propiedad desde inspector. Lo conectaremos como secuencia del nodo "condition" y modificaremos la propiedad index con el eje Y para establecer que solo vamos a usar el valor Y
5. Nuestro objetivo es que la geometría del personaje rote el mismo ángulo que el nodo referencia de cámara. Por lo tanto necesitamos recuperar el vector de rotación de ese nodo y unir su componente Y con éste ultimo nodo que hemos creado. Para ello seleccionamos la propiedad de rotación del nodo "referencia de cámara" y presionamos Ctrl antes de soltar para obtener el valor de dicha propiedad
6. Ahora añadiremos el nodo "Deconstruct vector3" que lo que hace es separarse en los tres ejes. Por lo tantto conectaremos su entrada de vector con la salida de vector del nodo "Get rotation degress" y la salida Y a la entrada flotante del otro nodo "Get rotation degress"
7. Ahora necesitamos mover el personaje y para ello utilizaremos el nodo "Move and collage" y lo conectaremos como secuencia del nodo "Set rotation degrees"
8. Ahora tenemos que definir un movimiento en el espacio global. Ésto lo haremos mediante la matriz de transformación del nodo "personaje principal". Debemos arrastrarla y antes de soltar presionar Ctrl para obtener la información
9. De éste ultimo nodo que hemos creado llamado "Get transform" saldremos desde su puerto único de salida a un espacio vacío y buscaremos "Deconstruct Transform"
10. La salida "basis" del nodo "Deconstruct Transform" presenta tres vectores. Para extraer los tres vectores saldremos desde ese puerto de salida a un espacio vacío y buscaremos "Deconstruct basic"
11. De las tres salidas que tiene éste ultimo nodo que hemos creado nos centraremos en la z que corresponde a la dirección frontal al personaje del espacio local. Esa salida debe ir al puerto de entrada del nodo "Move and collage" pero antes reduciremos al velocidad. Para ello saldremos desde ese puerto de salida a un espacio vacío y buscaremos "Math multiply". Modificaremos los valores (en nuestro caso) a 0.1 en todos lso ejes y finalmente lo conectaremos a la entrada del nodo Move and collage.
Apuntes tomados de el siguiente curso:
https://www.youtube.com/watch?v=imfZg11n8bw&list=PL2FA591jQnK9U3Q-JW8jGWliIQR0iGw7b&index=5
Crearemos un nodo llamado "interfaz de usuario" y lo guardaremos en una carpeta de escenas y luego iremos a temas, crearemos una fuente dinámica (en setting ajustamos el amaño de las letras), un font data y añadiremos nuestra fuente .ttf
Luego crearemos un nodo panel, y en las opciones de inspector modificaremos su tamaño en "rect", un estilo personalizado en "custom style" en el cuál modifcaremos el color, la transparencia, el grosor del borde y su color
Ahora crearemos un nodo button como hijo dle nodo panel, y en inspector cambiaremos el nombre, agregaremos un icono, activaremos "flat" para que se elimine el fondo, activaremos "Expand icon" para darle mayor dinamismo al botón, y ajustaremos la posición y tamaño en "rect"
Ahora para añadir un fondo al panel vamos a agregar un nodo "TextureRect" y debemos ubicarlo antes del panel para que se vea de fondo
Arrastramos la textura, activamos "expand" para que podamos cambiar las dimensiones d el imagen y también activaremos "Keep Aspect"
Variables multidimensionales
Vamos a crear un script tipo visual script en el panel y agregaremos presionando el signo + una nueva variable y la editaremos para que se tipo str. Lo re nombraremos como "Idiomaobjetivo"
Ahora agregaremos una nueva variable con el signo + pero de tipo diccionario. Éste tipo de variables permite almacenar una o varias variables y asociarlas a una clave. La clave es la palabra y el valor la definición. A esta la llamaremos "Menu"
Vamos a presionar sobre diccionario y se nos creara un clave-valor. Luego podemso definir el tipo de las claves y los valor
La clave la seleccionaremos como string y el valor como "PoolStringArray" que nos permite crear una lista de la variable seleccionada.
Luego aumentamos el valor que tenemos a bajo que sirve para introducir variables de tipo string. Usaremos el 3 y a cada uno le pondremos el nombre respectivo de nuestro menú: Nuevo - English - Salir. Luego presionamos en "Agregar Par Clave/Valor". De ésta forma se añade la primera variable a nuestro diccionario
Ahora crearemos un nuevo par clave-valor de la misma forma, para las traducciones al inglés. La clave será tipo string con el nombre de English, el valor será tipo "PoolStringArray" y agregaremos 3 variables: New - Español - Exit
Entonces lo que haremos será cambiar el texto de los botones según el idioma seleccionado. Para ello:
1. Teniendo seleccionado el nodo de botón "Salir" conectaremos la señal "Pressed" al script que estamos editando y crearemos con ello un nodo
2. Ahora debemos obtener el texto contenido en el botón idioma e incluirlo dentro de la variable que creamos al principio. Esa variable llamada "idiomaobjetivo" la arrastraremos a visual script, pero antes de soltarlo presionamos Ctrl para que se agreguen las entradas. Luego lo conectamos con el otro nodo como secuencia
3. Arrastramos la propiedad text del botón idioma nuevamente presionando Ctrl para que se agregue el puerto de datos str, le cuál conectaremos a la entrada str del nodo "idiomaobjetivo".
4. Ahora debemos cambiar el texto del botón "Nuevo", entonces arrastramos al propiedad text del botón "Nuevo" y lo uniremos como secuencia .
5. Ahora debemos especificar el texto que queremos usar para el botón "nuevo". Ese texto varía según los valores del diccionario que hemos creado. Arrastraremos la variable "Diccionario" que nombramos "menu" lo cuál creará un nuevo nodo que permite obtener todos los valores.
6. Recordemos que dentro de esta variable tenemos dos claves, una para cada idioma. Lo que debemos hacer es extraer una a una las cadenas de texto para así añadirlas al nodo "Set text" de los botones. Para ello usaremos la función "Dictionary Get" que se agrega desde el visor. Éste nodo presenta 3 puertos de entrada y un puerto de datos de salida. En el primer puerto debemos especificar la variable "Dictionary" que en nuestro caso es la variable "menu". Los conectamos.
7. El segundo puerto de entrada debemos especificar una clave de nuestro diccionario. Ésta clave viene definida por la variable "idiomaobjetivo" por lo quedemos arrastrarlo y conectara.
8. Ahora necesitamos extraer uno a uno los elementos de la lista. Para ello añadiremos el nodo "Array get index". Dentro de éste nodo debemos indicar cuál es la variable que contiene la lista de elementos. Para ello conectamos la salida del nodo dictionary get a la entrada "base" de "Get index".
9. En segundo lugar debemos especificar el número de elementos que debemos extraer. Para ello agregamos el nodo "constant". Teniendo seleccionado el nodo en inspector debemos cambiar a "int". El valor que tendremos es cero correspondiente al primero de la lista. Éste nodo entonces lo conectamos a la entrada "index" del nodo "Get index". La salida del nodo index la conectamos a la entrada del nodo "set tex" correspondiente al boton "Nuevo"
10. Ahora debemos hacer lo mismo con los otros botones "Idioma" y "Salir" por lo que debemos arrastrar su respectivas propiedades de texto y los conectaremos como secuencia al primer nodo de propiedad de texto llamado "Set text"
11. Duplicaremos dos veces los nodos "Get index" y "Constant" y conectaremos en ambas entradas "Base" la salida del nodo "Dictionary Get" y a cada nodo constant le cambiaremos el valor correspondiente según el listado, 1 y 2 respectivamente
12. Luego conectaremos las salidas de cada nodo "Get indext" con las entradas de los nodos "Set text" correspondientes
Nodo iterador
El problema que tenemos es que para ésta configuración tenemos que repetir. En el caso de que fueran más botones el código sería muy largo. Para ello es necesario usar el nodo iterador. Este nodo permite repetir un conjunto de acciones el numero de veces especificado en el puerto de datos de entrada. En nuestro caso el numero de veces que repetiremos las acciones depende del numero de botones que tengamos.
1. Agregamos el nodo iterador y lo conectamos con la salida del "Set idiomaobjetivo"
2. Para especificar el numero de botones debemos usar el nodo "Get child count" el cuál debemos conectar al puerto de datos de entrada del nodo Set idiomaobjetivo
3. El puerto de datos de salida del nodo Set idiomaobjetivo etiquetado como "each" permite definir el conjunto de acciones que deseamos repetir y como nuestro objetivo es repetir 3 veces la operación Set text de cada botón lo unimos a este nodo
4. El puerto de datos de salida del nodo Set idiomaobjetivo etiquetado como "elem" permite obtener el valor actual del bucle que en nuestro caso es entre 0 y 2. Por lo tanto debemos conectar ésta salida a la entarda "index" del nodo "Get index" que recordemos que éste extraía uno a uno los elementos de la lista
5.Lo que necesitamos ahora es que el nodo "Sext text" se aplique en el orden correspondiente, primero el botón "nuevo", luego el botón "idioma", luego el botón "salir". Para ello debemos seleccionar el nodo "Set text" y en inspector cambiar la propiedad que tenemos en set mode que es "Node path" pues ésta lo que hace es funcionar solo para un nodo concreto, que en éste caso es el botón nuevo (donde se arrastró ésta propiedad). Debemos entonces cambiar ésta opción por "instance". Con ello se agrega un nuevo puerto de datos llamado "obj". Aquí el cambio de texto se aplicará sobre el objeto que indiquemos
6. En el puerto "obj" debemos indicar los 3 botones, uno después del otro y de forma automática. Para ello necesitamos el nodo "Get child (int)". Ésta opción devuelve el nodo hijo atendiendo a un valor numérico. Éste valor corresponde al orden establecido dentro de la jerarquía, el botón nuevo 0, el botón idioma 1 y el botón salir 2. Esa iteración y a vimos que se obtiene de la salida "elem" del nodo iterador. Por lo tanto conectamos esa salida a la entrada de éste nodo. Luego la salida de este nodo a la entrada "obj" del nodo "set text".
Cambio de escena
Teniendo un panel principal como el que tenemos con 3 botones: Nuevo, idioma, y salir. Queremos que al presionar "Nuevo" podamos entrar a una nueva escena ,que sería la escena del juego.
Nuestro objetivo entonces es saltar a la escena 3d al pulsar el botón nuevo, para ello debemos crear un script sobre el botón "Nuevo". Crearemos un de tipo visual script.
1. Conectamos la señal pressed() con el botón Nuevo para que se cree el nodo
2. Para llamar al sistema de escenas y cambiar de pantalla de juego debemos agregar el nodo "Scene tree"
3. Si salimos desde el puerto de salida obj del nodo "Scene tre" se abrirá una nueva ventana con las funciones especificas del sistema de escenas. Vamos a buscar la función "Chaneg scene". Éste nodo función nos permite cambiar a un nuevo nivel guardado dentro del sistema de archivos de nuestro proyecto. En donde dice Null debemos definir la ruta del archivo de la escena. En éste caso es la escena laberinto. En nuestro sistema de archivos copiamos la ruta y la pegamos en Null con Ctrl+V. Finalmente unimos los puertos de secuencia con el nodo "Scene tree"
Salir del juego
Creamos un script en el botón "Salir" y seguimos los mismos pasos anteriores pero en vez de usar el nodo "change scene" usaremos "quick"
Personajes
Godot soporta varios formatos, entre ellos Collada .Dae. Vamos a crear una carpeta de personaje que contendrá el modelo en formato .dae con sus animaciones en 60fps, y sus texturas. Las animaciones las descargaremos en ese formato desde https://www.mixamo.com/
Godot trabaja con materiales PBR por lo que si tenemos una textura difuso (que contiene sombras) no es compatible por lo que debemos pasarla a "albedo". Para ello podemos ir al sitio web https://pixlr.com/x/
Arrastramos la imagen y luego la duplicamos
Luego seleccionamos "Soft-light"
Luego seleccionamos invert y bajamos al saturación
Luego la descargamos con el sufijo albedo
Luego de tener todas las texturas en una carpeta dentro de nuestro sistema de archivos, hacemos clic en "material" y arrastramos las texturas pertinentes
Tenemos dos archivos dae correspondiente a cada animación, vamos a abrir cada una
Cada archivo se abre en una nueva escena con tres nodos, entre ellos el nodo "AnimationPlayer" que es la animación misma. En nuestro caso tenemos la animación de reposo (Idle) y la animación de correr (run). Necesitamos tener las animaciones en un solo archivo. Para ello primeramente guardamos la animación con "Guardar como" desde la ventana de animación
Como guardamos la animación run, ahora la cargaremos en donde tenemos la animación Idle
Ahora tenemos las dos animaciones. Recordemos que para que la animación sea constante debemos presionar "loop de aniamción"
Ahora necesitamos guardar la escena con una extensión propia de Godot. Así que la guardaremos con "Guardar Escena como"
Maquina de estado
Para realizar una maquina de estado sobre el personaje debemos agregar el nodo "AnimationTree". Éste tipo de nodo permite controlar las animaciones mediante distintas herramientas.
1. Primero teniendo seleccionado el nodo "AnimationTree" iremos a inspector y en Tree Root seleccionaremos "AnimationNodeStateMachine"
2. Luego en AnimPlayer seleccionaremos "AnimationPlayer"
3. Para indicarle a Godot que el nodo AniamtionTree tiene control sobre las animaciones debemos tiquear la casilla "Activado"
Luego en la ventana inferior del visor 3d crearemos nuestro árbol de animaciones.
1. Haciendo clic con el botón derecho del ratón sobre un área vacía podemos agregar una animación
3. Si pulsamos dicha conexión podemos establecer ciertas propiedades de la transición en inspector. Por ejemplo tenemos "Advante Condition" que nos permite crear una variable boleana para activar la transición. En nuestro caso escribiremos "mover"
4. Luego la propiedad Xfade tame permite establecer el tiempo de transición entre las animaciones. En nuestro caso colocaremos 0.1
5. Ahora para hacer la transición a la inversa hacemos lo mismo de arrastrar con shift pero en sentido contrario
Programación de estados
Agregaremos un visual script al nodo "AnimationTree" y seguiremos los siguientes pasos:
1. En el icono de la carpeta donde dice funciones añadiremos al función "input".
2. Teniendo seleccionado el nodo "AnimationTree" iremos a isnpector y en la pestaña "Conditions" de la pestaña "parameters" arrastraremos la propiedad "Idle" y la propiedad "Move". Luego los conectamos todos como secuencia comenzando pro function, luego move y fianlmente idle
3. Añadiremos el nodo "action" y en inspector lo configuraremos para detectar la tecla de dirección arriba "ui_up" y lo conectaremos en el puerto de datos de entrada del node "Move" para que así cuando la tecla esté pulsada, la condición run cambié a verdadero y comience la animación
4. Finalmente añadimos el nodo "Logic Not" y lo conectaremos en la entrada de datos con el nodo action y en la salida de datos con la entrada del nodo "Idle". Así establece la variable condicional Idle en el estado inverso en que se encuentra la tecla de dirección arriba (ui_up)
Añadir personaje a la escena del juego
Para añadir nuestro personaje principal a nuestra escena lo primero que debemos hacer es agregar el nodo "KinematicBody" como hijo del nodo spacial e instanciar la escena donde está el persona je usando el icono de cadena
Luego, como hijo del nodo kinematicBody agregamos el nodo "Collisionshape", seleccionamos el tipo capsula y lo ajustamos
Instancias únicas
En nuestro nodo raíz crearemos un visual script. Para así añadir una instancia única, las cuales sirven para modificar propiedades como por ejemplo la calidad gráfica, la resolución, entre otros.
1. Añadiremos el nodo "Engine singleton" que es un nodo con acceso a las instancias únicas y en inspector abriremos las opciones de constant que es donde elegiremos el tipo de propiedad a modificar, tenemos por ejemplo OS que sirve para modificar la resolución de la pantalla, cambiar el titulo de la ventana, entre otros. En nuestro caso usaremos el input que nos servirá para ocultar y bloquear el movimiento del ratón
2. Si salimos del nodo Engine singleton abriremos un listado y elegiremos "Set mouse mode". Éste nodo tiene una entrada de datos int en donde podemos cambiar el valor teniendo cada uno de ellos una función: 0. Mostrar el cursor. 1. Ocultar el cursor. 2. Ocultar y bloquear el cursor. 3. Mostrar y restringir la zona del cursor. vamos a elegir al función 2
3. Ahora dándole clic al icono de la carpeta añadiremos la función ready y la conectaremos en el puerto de secuencia de entrada del nodo "Set mouse mode". De ésta forma cuando se inicie el juego el cursor estará oculto y confinado dentro de la ventana de juego
4. Ahora vamos a añadir una función para volver a mostrar el cursor cuando el usuario pulse la tecla "Esc". Para ello desde el icono de carpeta añadiremos la función "input"
5. Añadiremos el nodo "condition" y lo conectaremos con el puerto de secuencia de salida del nodo input
6. Añadiremos el nodo "Action" y lo conectaremos con el puerto de datos de entrada del nodo condition y en inspector cambiaremos la tecla a "cancel" correspondiente a Esc
7. Duplicaremos los nodos Engine singleton y Set mouse mode. En éste ultimo nodo modificaremos el valor a 0 que corresponde a "Mostrar el cursor" y lo uniremos con el puerto de secuencia de salida True del nodo condition
Control de cámara con el ratón
Para poder controlar la rotación de la cámara en torno al personaje necesitamos crear un nodo spacial. Éste debemos crearlo como hijo del nodo kinematicbody correspondiente al personaje principal . Luego el nodo de cámara debemos arrastrarlo a este nodo y ajustarlo en la posición correcta. Si seleccionamos el nodo spacial y rotamos la cámara sigue al personaje
Ahora vamos a crear un visualscript para que la cámara rote siguiendo los movimientos del ratón. El script debemos añadirlo al nodo spacial del personaje el cuál renombraremos como "referencia de cámara" y seguiremos los siguientes pasos:
1. Añadimos al función "input" desde le icono de carpeta. Ésta función se activa si pulsamos una tecla, movemos el ratón o controles de un joystick
2. Luego agregamos el nodo "TypeCast" para restringir las acciones. Conectaremos cada puerto, el de secuencia y de datos respectivamente con el nodo input. Gracias a este nodo podremos especificar que tipo de entrada estamos esperando. Ésto lo debemos especificar dando clic en el nodo, yendo a la propiedad "base type" de inspector y seleccionar "InputEventMouseMotion" para definir el movimiento del ratón como señal necesaria para ejecutar las acciones
3. Ahora teniendo seleccionado el nodo spacial (referencia de cámara) iremos a inspector y arrastraremos la propiedad de rotación y conectaremos la entrada de secuencia de este nodo con la salida de secuencia del nodo TypeCast. De ésta forma si movemos el ratón el nodo de referencia de cámara rotará una cantidad
4. Ahora necesitamos determinar cuanto será la cantidad de rotación. Lo que dependerá de dos factores: La rotación actual y el movimiento realizado por el ratón. La rotación actual la obtenemos arrastrando la misma propiedad de rotación pero con Ctrl presionado antes de soltar para que éste nodo se convierta en un nodo con salida tipo vector
5. Luego debemos salir del nodo "Get rotación degress" a una zona vacía del visor y nos aparecerá una lista, buscaremos "Deconstruct vector"
6. Para obtener el movimiento del ratón debemos salir del puerto de datos de salida del nodo type cast a una zona vacía del visor y nos aparecerá una lista, buscaremos "Obtener relative"
7. Para descomponer éste vector (que es una variable vectorial de dos dimensiones) debemos salir del puerto de datos de salida de este nodo a una zona vacía del visor y nos aparecerá una lista, buscaremos "Deconstruct vector" (en su versión de dos componentes)
Ahora debemos rotar la cámara con el movimiento del ratón. Para ello debemos conocer los ejes que intervienen en dicha rotación. Por ello es recomendable ir a la vista 3d y probar rotando los ejes X e Y del nodo spacial para ver cuál es el limite que nos servirá. En nuestro caso acotaremos el angulo de X entre -20 y 15, y el ángulo Y entre 90 y -90.
Al valor X de la propiedad rotación debemos añadirle o sustraerle el valor Y del movimiento del ratón y al valor Y de la propiedad rotación debemos añadirle o sustraerle el valor X del movimiento del ratón. Agregaremos los nodos "Math Add" y "Math Subtract". A cada uno le modificaremos la propiedad type de inspector a "flotante". Usaremos la suma para el eje X y la resta para el eje Y.
8. Por lo tanto conectaremos la salida Y del nodo Deconstruct vector (correspondiente al movimiento del ratón) a la entrada A del nodo Subtract y conectaremos la salida X del nodo Deconstruct vector (correspondiente a la rotación actual) a la entrada B de este mismo nodo por lo que estaremos.
9. Ahora, conectaremos la salida X del nodo Deconstruct vector (correspondiente al movimiento del ratón) a la entrada B del nodo Add, y conectaremos la salida Y del nodo Deconstruct vector (correspondiente a la rotación actual) a la entrada A de este mismo nodo por lo que estaremos.
10. Ahora, como es necesario limitar la rotación del eje X de la cámara para evitar giros verticales no deseados. Para ello añadiremos el nodo "Clamp". Éste nodo limita el valor de una variable usando una cota superior e inferior. El valor que usaremos será -20 y 20. Éste lo conectaremos con el puerto de salida del nodo Add
11. Ahora debemos crear un nodo que de-construya el vector de tres dimensiones por lo que usaremos el nodo "Construct vector 3XYZ". Conectaremos la salida del nodo clamp con la entrada X, la salida del nodo resta con la entrada Y, y la salida Z del nodo "Deconstruct vector" a la entrada Z.
12. Finalmente conectamos la salida de este ultimo nodo al puerto de datos de entrada de "Set rotation"
Añadir librería de objetos
Luego de arrastrar nuestros objetos 3d para nuestra librería a un nuevo escenario crearemos los materiales en "Nuevo recurso" y escogeremos "SpacialMaterial". Ésto cada vez que creemos un nuevo material
Luego seleccionando cada objeto arrastraremos los materiales que hemos creado
Ahora debemos añadir los nodos de collision a nuestros objetos. La manera más fácil de hacerlo es mediante el menú malla. Si seleccionamos "Crear StaticBody Triangular" se crean los nodos necesarios para que cualquier objeto dinámico pueda colisionar con las paredes
Ahora vamos a convertir nuestro escenario en una biblioteca de mallas desde el menú "escenas". La guardaremos en nuestra carpetas de objetos con la extensión .meshlib
Ahora iremos al escenario principal y añadiremos el nodo "GridMap"
Luego en inspector podemos arrastrar nuestra librería
Ahora tendremos nuestros objetos en una nueva ventana y podemos arrastrarlos a nuestro espacio 3d. Para rotar la geometría de los muros usamos S, para subir el nivel de la posición del objeto hacía arriba o hacia a bajo tenemos al opción plano. El comando para subir es E y para bajar Q. Para ponerlo en forma vertical es Z y volver a horizontal X. Con Esc se cancela. También podemos configurar la cantidad de celdas en las que se mueve
Matriz de transformación
Cuando aplicamos una fuerza sobre un cuerpo controlado por el motor de física necesitamos indicarle a Godot cuál es la dirección y la magnitud haciendo uso de un vector de dos o tres componentes. Ese vector se define según los ejes del espacio global por lo que no respeta la orientación de nuestro objeto. Por ejemplo, para mover nuestro personaje principal debemos movernos en el eje Z de nuestro espacio global
Pero si giramos nuestro objeto 90 grados en el eje Y, para mover nuestro personaje hacia adelante deberíamos hacerlo ahora en el eje X
Para solventar este problema existe un recurso matemático llamado "Matriz de transformación" . Lo podemos ver en inspector en la ventana "matriz". Está formado por dos componentes:
1. La base: Está formado por tres vectores que nos permiten conocer la orientación de los ejes x, y, z del espacio local de un objeto con respecto a las coordenadas x, y, z del espacio global
2. El origen:
Podemos activar y desactivar la vista local desde el icono del cubo
Control de personaje en tercera persona
Agregaremos un visual script al personaje principal
1. Añadimos la función "physics_process"
2. Luego agregamos el nodo condition y lo conectamos como secuencia
3. Luego el nodo action con la tecla discrecional hacia arriba (ui_up) que lo conectaremos en el puerto de datos de entrada del nodo condition
Las acciones que queremos que el personaje realice son dos: Orientar el personaje hacia la dirección opuesta a la cámara y mover el personaje hacia adelante
4. Para orientar el personaje hacia la dirección opuesta necesitamos la propiedad de rotación. Seleccionamos el nodo del personaje principal y arrastraremos esa propiedad desde inspector. Lo conectaremos como secuencia del nodo "condition" y modificaremos la propiedad index con el eje Y para establecer que solo vamos a usar el valor Y
5. Nuestro objetivo es que la geometría del personaje rote el mismo ángulo que el nodo referencia de cámara. Por lo tanto necesitamos recuperar el vector de rotación de ese nodo y unir su componente Y con éste ultimo nodo que hemos creado. Para ello seleccionamos la propiedad de rotación del nodo "referencia de cámara" y presionamos Ctrl antes de soltar para obtener el valor de dicha propiedad
6. Ahora añadiremos el nodo "Deconstruct vector3" que lo que hace es separarse en los tres ejes. Por lo tantto conectaremos su entrada de vector con la salida de vector del nodo "Get rotation degress" y la salida Y a la entrada flotante del otro nodo "Get rotation degress"
7. Ahora necesitamos mover el personaje y para ello utilizaremos el nodo "Move and collage" y lo conectaremos como secuencia del nodo "Set rotation degrees"
8. Ahora tenemos que definir un movimiento en el espacio global. Ésto lo haremos mediante la matriz de transformación del nodo "personaje principal". Debemos arrastrarla y antes de soltar presionar Ctrl para obtener la información
9. De éste ultimo nodo que hemos creado llamado "Get transform" saldremos desde su puerto único de salida a un espacio vacío y buscaremos "Deconstruct Transform"
10. La salida "basis" del nodo "Deconstruct Transform" presenta tres vectores. Para extraer los tres vectores saldremos desde ese puerto de salida a un espacio vacío y buscaremos "Deconstruct basic"
11. De las tres salidas que tiene éste ultimo nodo que hemos creado nos centraremos en la z que corresponde a la dirección frontal al personaje del espacio local. Esa salida debe ir al puerto de entrada del nodo "Move and collage" pero antes reduciremos al velocidad. Para ello saldremos desde ese puerto de salida a un espacio vacío y buscaremos "Math multiply". Modificaremos los valores (en nuestro caso) a 0.1 en todos lso ejes y finalmente lo conectaremos a la entrada del nodo Move and collage.
Apuntes tomados de el siguiente curso:
https://www.youtube.com/watch?v=imfZg11n8bw&list=PL2FA591jQnK9U3Q-JW8jGWliIQR0iGw7b&index=5