Transcripciones
1. Avance 0-0: Bienvenido a mi curso
sobre cómo construir ametroivnia en el motor de juego
Gadot Mi nombre es Thomas Ionizlo
y seré tu instructor. Tengo una licenciatura
en informática y llevo más de cinco años enseñando el desarrollo de
juegos a través
de múltiples plataformas. He incluido un conjunto
completo de activos, incluyendo sprites, efectos de
sonido y música que
puedes usar para
seguir o puedes usar tus
propios activos si lo prefieres Este curso te ayudará a
familiarizarte con el motor
GdoGame Es un flujo de trabajo muy eficiente para crear juegos y su lenguaje
nativo de scripting script GD Aprenderás a construir
y editar escenas usando los diversos nodos
de Gado y alterar su comportamiento
con scripts. Mientras escribes estos scripts, aprenderás a aplicar principios de
programación orientados
a
objetos para mantener tu código conciso, escalable y reutilizable
para otros proyectos. Lo más importante es que
aprenderás a
estructurar un proyecto complejo de esta magnitud
dividiéndolo en sus componentes
individuales. Comenzaremos construyendo y animando un personaje de
plataformas de dos D. Luego construye un entorno
para que el personaje explore y mueva
la cámara del juego. A continuación, permitiremos que el personaje
haga la transición entre diferentes salas y
dibuje el mundo en un mapa para ayudar al jugador a
explorar tu mundo. Después de guardar y cargar
el progreso del jugador, dibujaremos una pantalla frontal. Luego agrega nuestras habilidades
desbloqueables, incluyendo un doble salto,
un salto de pared, un guión y disparar un Por último, agregaremos
algunos enemigos para el combate, una pelea de jefes y haremos un
seguimiento del
progreso del jugador a lo largo del juego. Ya sea que seas nuevo
en el desarrollo de juegos, nuevo en el motor de juego Gadot o simplemente nuevo en Metroid venias, este curso te enseñará
todo lo que necesitas
saber para construir un
juego completo desde cero Si necesitas ayuda, nuestro servidor de
discordia está lleno de
otros estudiantes y desarrolladores de juegos en
ciernes que pueden responder a cualquiera
de tus Haz clic en el enlace de
mi perfil para unirte. Puedes previsualizar las dos primeras secciones del curso de forma gratuita, y tengo otro curso
que cubre los conceptos básicos
de la programación de GD Script
completamente gratis, también. Una vez que estés listo,
podemos empezar a aprender a construir
una metrovnia en
2. 0-1 Descarga: Hola amigos. Para poder
seguir este curso necesitarás el motor Godot Abre cualquier navegador web
y dirígete a godot.org y descarga
la última versión, que a partir de la grabación
de este video es 4.5 0.1 El motor es de uso gratuito, pero opcionalmente puedes optar donar para apoyar el
desarrollo si quieres. Una vez completada la descarga, deberás extraer los
archivos de la carpeta con cremallera luego almacenarlos en un
lugar seguro de tu computadora Para ejecutar el editor,
todo lo que tienes que hacer es ejecutar el archivo más grande que
no termina en la consola. No hay instaladores ni
lanzadores de los que preocuparse. La primera vez que abras Godot, tu lista de proyectos estará vacía, y te preguntará si
quieres explorar algunos de los proyectos de ejemplo
que están disponibles Vamos a ignorar esto
y crear nuestro primer proyecto, que abre una nueva ventana. Aquí podemos decidir dónde
guardar el proyecto. La ubicación predeterminada está
en la carpeta de documentos, pero es una buena idea crear una subcarpeta separada para
contener tus proyectos de Godot A continuación, podemos darle un nombre a
nuestro proyecto. No te preocupes por esto
demasiado ahora mismo. Siempre puedes cambiarlo después. También se creará una nueva subcarpeta con el mismo nombre para contener todos
los archivos
relacionados con este proyecto pueden seleccionar tres renderizadores diferentes, cada uno optimizado para
diferentes propósitos Te recomiendo comenzar todos tus proyectos usando
el renderizador
de compatibilidad
para comenzar ya que es lo mejor para compilaciones web y solo
cambiar tu renderer más tarde si necesitas un mejor soporte
para efectos visuales de mejor calidad control de versiones con Gi
Hub se
admite automáticamente y recomiendo encarecidamente
aprender a usarlo. Al crear este
proyecto, se
abrirá automáticamente
para que podamos editarlo. Aunque voy a cerrar el
editor y volver a abrirlo. Nuestro proyecto ahora está incluido
en la lista de proyectos, y podemos abrirlo
haciendo doble clic sobre él
o seleccionándolo de la lista y haciendo clic en el botón Editar. Ahora tenemos acceso al Godot y podemos comenzar a
editar nuestro primer proyecto En el siguiente video,
exploraremos el diseño de
la ventana del editor. Te veré en el siguiente video.
3. Editor 0-2: Hola, amigos. Antes de
comenzar a editar nuestro proyecto, tendremos que
familiarizarnos con el diseño de la ventana
Godot Editor La mayor parte de la
ventana se llena con una vista en tres D de
la escena actual. Este proyecto será en dos D, no tres D. Podemos
cambiar la vista entre tres D y dos D usando los botones en
la parte superior de la ventana. En dos D, tenemos el eje
X dibujado en rojo, el eje Y dibujado en verde, y un rectángulo azul
que muestra la ventana gráfica, o lo que realmente se
dibujará en pantalla al
ejecutar el juego Tenga en cuenta que la ventana gráfica
está por debajo del eje X con Y es igual a cero representando
la parte superior de la pantalla El eje Y está invertido, por lo que los valores positivos para Y se moverán hacia abajo en el eje
Y, no hacia arriba. En la parte superior izquierda, tenemos una pestaña para la estructura de la
escena actual, que actualmente está vacía y nos
pide crear un nodo
raíz para esta escena. Ya que nuestro juego será dos D, hagamos una escena de dos D. La pestaña de escenas ahora muestra
nuestro nodo raíz de escenas, un nodo dos D.
Exploraremos más sobre escenas
y nodos en el siguiente video. Este dock también contiene
la pestaña Importar, que nos permitirá cambiar
la configuración de importación para los archivos
importados que usaremos en nuestro proyecto como
gráficos y audio. Estos archivos se almacenarán y organizarán dentro del sistema de archivos del
proyecto, que podemos ver
en la parte inferior izquierda. Actualmente, nuestro proyecto solo
tiene un archivo en él, que es el ícono de Gadot En la pestaña del sistema de archivos, podemos mantener nuestros
archivos de proyecto organizados creando carpetas y buscando a través de
ellas usando el filtro. Volviendo a la pestaña de escena, si tenemos una nota seleccionada, entonces sus propiedades se
presentarán en la
pestaña Inspector de la derecha. Podemos ampliar las categorías de estas propiedades y
editar sus valores aquí. Este dock también
contiene la pestaña nodo, que proporciona una lista de
señales que este nodo puede emitir, así
como de
qué grupos forma parte. La pestaña de historial contiene una
lista de todos los cambios que hemos realizado dentro de la escena actual
o para todo el proyecto. Puedes ver todos
los cambios que hicimos, además también edité
el Editor Fontie El muelle inferior está
actualmente colapsado, pero podemos hacer clic en el botón
de salida para expandirlo. La salida también
nos mostrará los cambios que hagamos el proyecto y también mostrará la salida de
texto de nuestro juego, lo cual es muy útil
para depurar Podemos
generar mensajes manualmente aquí, pero el editor también emitirá advertencias y errores aquí también. El depurador tiene una variedad
de herramientas útiles para
ayudarnos a descubrir qué es lo que está ralentizando o
estrellando También hay pestañas
específicamente para audio,
animación, shaders y aquí se
agregarán más pestañas a
medida que sean necesarias Podemos contraer este muelle haciendo clic en la pestaña seleccionada
actualmente. Al hacer clic en los tres puntos, estos muelles se pueden reorganizar
para adaptarse a sus necesidades,
sin embargo, cree que funcionará mejor
para adaptarse a su flujo de trabajo para adaptarse a su Las pestañas individuales también
se pueden arrastrar entre documentos. Cuando encuentre un diseño
que funcione bien para
usted, puede guardarlo desde
el menú del editor. También puede cambiar una variedad de configuraciones del editor para personalizar el editor para que se ajuste a sus necesidades. Cuando finalmente tenemos
un juego que ejecutar, podemos hacerlo desde los botones de
la esquina superior derecha. Ya sea jugando el juego desde el principio o solo
corriendo la escena actual, pausa o deteniendo el juego En el siguiente video,
aprenderemos a construir una escena. Te veré en el siguiente video.
4. 0-3 escenas: Hola, amigos. Ahora que estamos familiarizados con el
layout del editor, comencemos a editar
nuestra primera escena. Comenzaremos haciendo
clic en dos escenas D, haciendo del nodo raíz
de nuestra escena un nodo dos D. Un nodo dos D en realidad no
representa nada en nuestro juego. Es sólo una transformación
bidimensional. Una transformación es una combinación de una posición, rotación y escala. Godot también incluye un
componente sesgado en dos transformaciones D. Si realmente queremos
dibujar algo, necesitaremos agregar otro
nodo a nuestra escena. Ya sea haciendo clic derecho en
el nodo raíz y seleccionando Agregar hijo o haciendo
clic en el botón Más, podemos agregar un
nodo hijo a nuestra escena. Hay muchos tipos
diferentes de nodos que sirven para
diferentes propósitos. La forma más común
de dibujar algo en dos juegos D es
usar un sprite Entonces agregaremos un nodo Sprite
dos D a nuestra escena. Los tipos de nodo heredan
de otros tipos de nodos. Entonces un nodo sprite dos D también es un nodo dos D y un elemento canvas, y un nodo básico, y tiene todas las mismas propiedades
heredadas de estos tipos, además de algunas más propias El nodo D de Sprite dos se agrega como hijo
del nodo raíz, indicado por la sangría Las escenas se organizan
en una jerarquía, comenzando con un nodo raíz
singular luego ramificándose en cualquier
número de nodos secundarios Estos nodos secundarios también pueden tener sus propios nodos secundarios
que forman el árbol de escenas. Podemos colapsar
ramas del árbol o todo
el árbol haciendo clic
en la flecha al lado de ellas, y nuevamente para expandirlas. El nodo sprite
todavía no está dibujando nada porque no
se le ha dicho qué dibujar Seleccionándolo, para que podamos ver sus propiedades
en el inspector, donde efectivamente tiene propiedades
heredadas del nodo, elemento
Canvas, y nodo D. Bajo la sección Sprite two D, también tiene una propiedad texture, que actualmente está vacía Podemos cargar un archivo de
textura o arrastrar el icono GAD desde la pestaña del sistema de archivos
al campo de textura
para poblarlo Y ahora el nodo Sprite
dos D está dibujando la textura del icono de GADO como
un sprite en nuestro juego Duplicemos este nodo
Sprite dos D en el árbol de escenas haciendo clic derecho y seleccionando duplicar o seleccionando el nodo y
presionando Control o Comando D. El duplicado tiene todas las mismas propiedades que el nodo original y se renombra agregando un número
creciente a su hermanos en el árbol de escena no
se les permite
tener el mismo nombre. Podemos mover cualquiera
de nuestros sprites en la vista
de escena simplemente arrastrándolos. Esto actualizará automáticamente su
propiedad transformada de dos posiciones D en el inspector. También podemos rotar el sprite, escalarlo y
sesgarlo si queremos A continuación, arrastremos este nodo
Sprite Tu Di
al otro, asignándolo para que sea un nodo hijo
del otro nodo Sprite Tu Di, indicado por otro
nivel Ahora, si seleccionamos el nodo padre Sprite tu Di y editamos
sus propiedades de transformación, estos cambios son
heredados por el hijo Las propiedades de
transformación propias del hijo se definen en
relación con la del padre. Esta estructura jerárquica
de escenas y herencia de propiedades nos permite construir escenas
complejas con múltiples componentes
diferentes Podemos agregar cualquier número de nodos
diferentes a la
escena de diferentes tipos, como un
reproductor de flujo de audio dos nodos D, y una partícula GPU dos nodos D. Ahora bien, esta escena de dos D puede
dibujar algo, emitir sonidos y partículas, y todos
estos componentes
heredarán a su
posición de transformación desde el nodo raíz Para facilitar las cosas, la transformación de un
nodo raíz siempre debe tener todos los valores predeterminados y tener solo nodos hijos con
sus transformaciones editadas. Podemos renombrar nodos, lo que resulta particularmente útil para el nodo raíz de una escena
describa lo que es. Vamos a llamarlo
algo así como robot. Entonces podremos guardar esta escena como un archivo de escena en nuestro proyecto, y automáticamente se
llamará igual que el nodo raíz. Entonces crea una nueva escena de
dos D e imagina esto para representar una
habitación que contiene al robot. Nuestra escena de robot se puede agregar a la escena
como un solo nodo. Incluso podemos tener múltiples
robots si queremos. Desde el contexto de
esta escena más grande, ahora
podemos editar las propiedades
de
transformación de un robot para moverlo, rotar, escalar, sesgar, etcétera Cambiemos el nombre de esta escena
Room y guárdala. Si volvemos a la escena del robot y editamos los nodos
hijos del robot, estos cambios se aplicarán a todas las instancias del
robot en otras escenas. La escena de la habitación
no necesita preocuparse por cómo se construye el
robot, solo donde está
dentro de la habitación. Construir escenas a partir de componentes
individuales nos
permite mantener los detalles de objetos
individuales contenidos y ocultos
lejos de alcances más grandes También nos permite
producir fácilmente múltiples copias
de la misma cosa, pero con una sola fuente para ese objeto que
necesita ser editado. Construir un juego completo
consistirá en construir muchas escenas más pequeñas que representen objetos individuales del
juego, personajes y ubicaciones, y
luego combinar múltiples de estas escenas
para crear una escena más grande mientras
el juego se ejecuta. En el siguiente video,
exploraremos cómo el motor proporciona útiles tipos de
nodos integrados para
simular la física Te veré en el siguiente video.
5. 0-4 Física: Hola, amigos. Ahora que entendemos cómo se construyen las
escenas,
repasaremos cómo
los motores de juego proporcionan una funcionalidad integrada para facilitar mucho
el desarrollo de juegos. Podemos deshacernos de los robots y eliminar esa escena
del proyecto. Empecemos por agregar un cuerpo
rígido a nuestra escena. En el contexto de la física, un cuerpo es cualquier objeto que pueda chocar con otros
objetos y que tenga masa Un cuerpo rígido representa
un objeto sólido. Se verá afectada por fuerzas
externas como la gravedad, colisionará con otros objetos
sólidos, pero no se deformará ni se Mantendrá su forma. Este cuerpo rígido necesita una forma, que es otro
nodo que debe
agregarse como hijo directo
del cuerpo rígido. Este nodo de forma no
sabe qué forma es hasta que le damos un
recurso de forma en el inspector. Desde el menú desplegable, podemos seleccionar algunas opciones diferentes. Voy a hacer una forma de rectángulo. Ahora este cuerpo rígido tiene forma, pero en
realidad no se está dibujando nada. Entonces le agregaremos un nodo
Sprite two D y haremos
que dibuje la textura del icono de
Godot El sprite y la
forma de colisión no coinciden. Entonces seleccionando el nodo de forma de
colisión, podemos ajustarlo para que se ajuste mejor
al sprite haciendo clic y arrastrando los puntos rojos o editando sus propiedades
en el inspector Al mantener presionada la tecla Alt con el
nodo de cuerpo rígido seleccionado, colocémoslo
para que esté en algún lugar alrededor de la mitad superior
de la pantalla. Luego presione el botón Ejecutar escena
actual o presione F six como atajo. El motor del juego
aplica automáticamente fuerzas
al cuerpo rígido para simular física del mundo
real como la gravedad. La escala de masa y gravedad se
puede ajustar rápidamente en el inspector para ajustar el
comportamiento del cuerpo rígido Incluso podemos darle
un material físico para agregar fricción o rebote, ajustarlo al centro de masa y muchas otras opciones. Por ahora, hagamos que esta sencilla
caja choque con un piso. Los objetos muy robustos que no
queremos mover
generalmente se construyen a partir de un cuerpo estático en lugar de un cuerpo rígido. Un cuerpo estático aún puede
chocar con otros cuerpos, pero no se moverá como resultado de esa colisión y no se verá afectado por fuerzas como la gravedad Un cuerpo estático también necesita
una forma de colisión. Desde el menú desplegable,
seleccionaré el límite mundial. A diferencia de otras formas, un límite mundial
se extiende hasta el infinito. En dos D, esto se
representa como una línea. La flecha en las dos vistas D apunta lejos del límite. Por defecto,
creará un piso. Mover la posición
del nodo de cuerpo estático
hacia abajo hasta la parte inferior de la ventana gráfica impedirá que el cuerpo rígido caiga
más allá de este límite mundial Duplicemos el cuerpo
rígido y veamos cómo se comporta al chocar
con otro Podemos hacer click en un nodo
y cambiar su tipo. Entonces cambiemos este
cuerpo rígido en un cuerpo estático. Después,
colóquelo y gírelo para que el cuerpo rígido
choque con él en el aire. Recuerda cambiar el nombre de los nodos después cambiar su tipo para que
sepas de qué tipo son. Pero también se puede decir por el
icono al lado de su nombre, también. Si tuviéramos que programar manualmente
todo esto nosotros mismos, tomaría mucho trabajo
dibujar estos sprites, calcular cómo se ven
afectados por las fuerzas, averiguar cuándo
chocan entre sí y determinar cómo eso
afecta su comportamiento Junto con la física, los motores de juego nos
ayudan automatizando gran parte de la funcionalidad
común en la mayoría de los juegos para acelerar drásticamente
y simplificar En el siguiente video,
aprenderemos a adjuntar scripts a los nodos
para editar su comportamiento. Te veré en el siguiente video.
6. De 0 a 5 guiones: Hola, amigos. Si bien
el motor del juego nos
brinda mucha funcionalidad incorporada
, también
podemos agregar la nuestra propia
adjuntando scripts a los nodos. Seleccionando cualquier nodo
en el árbol de escenas, usaré el cuerpo estático
que es una caja flotante. Podemos
hacer clic con el botón derecho y seleccionar script
adjunto o presionar
el botón del script adjunto. Esto abre una nueva ventana. El script heredará
automáticamente del tipo de nodo al que
se está adjuntando, y podremos iniciar nuestro script
desde una plantilla si queremos También especificaremos un
nombre para el guión, que debe reflejar
su propósito. Voy a nombrar mi script spin, así
como la carpeta en la
que está guardado. Al hacer clic en el botón Crear
se cambiará automáticamente la
vista a la vista de script, para que podamos comenzar a
editar el script. La plantilla nos inicia con dos funciones,
listo y proceso. Cualquier texto que siga al símbolo de
Octothorp es un comentario. No es utilizado por el
motor y sólo existe para nuestro beneficio para ayudarnos a entender
mejor el guión. Como describen estos comentarios, la función ready se llamará
automáticamente cuando este nodo ingrese al árbol de
escenas por primera vez, lo que es un
poco engañoso. Pero por ahora, significará
cuando empiece el juego por primera vez. Proceso, por otro lado, se
llamará a cada fotograma
mientras se esté ejecutando el juego, que con la configuración predeterminada
del proyecto será de 60 veces por segundo. Una declaración de función comienza
con la palabra clave funk, seguida del nombre
de la función Estos nombres de funciones
comienzan con un guión bajo, que es la forma en que Gudo marca las funciones como privadas, lo que significa que
solo están destinadas a ser utilizadas dentro del contexto
de este script El nombre de la función va
seguido de paréntesis, cuales contendrán parámetros para la función
si los hay La función de proceso
tiene un parámetro, Delta, que es el número de segundos que han pasado
desde el fotograma anterior. Por lo que esta mayoría de las
veces será una 60ª, pero a veces aumentará si procesar un fotograma lleva
más tiempo de lo esperado los parámetros le sigue un guión mayor que una flecha, luego el tipo
de retorno de la función, que en ambos casos son nulos, lo que significa que
no devuelven ningún valor Declarar los
tipos de devolución es opcional, y estos se pueden
eliminar si lo prefiere El contenido de una función tiene sangría en una pestaña,
sin necesidad de llaves Ambas funciones
contienen solo la palabra clave pass, lo que básicamente
significa no hacer nada. Pero podemos sustituir esta instrucción por
algo diferente. Para ver cómo
funciona esto, cambiemos el cuerpo de la
función ready para hacer algo. La función print
emitirá todo lo que
queramos al panel de salida
cuando se ejecute el juego. Podemos llamar a funciones
especificando su nombre
seguido de paréntesis Luego dentro de los paréntesis, podemos proporcionar argumentos coincidan con las funciones
declaradas parámetros Dentro de comillas,
podemos escribir lo que queramos, como listo para girar. Todo lo que ponemos entre comillas se
conoce como cadena, abreviatura de cadena de caracteres. En la función de proceso, hagamos
lo mismo, pero esta vez, imprima el valor de Delta. También hagamos lo que se pretendía hacer este
script y modifiquemos el valor de
esta rotación de nodos, aumentándola por Delta usando
el operador más iguales. El operador plus equals
tomará el valor de Delta y lo sumará
al valor de rotación. Después asigne también el
resultado a la rotación. Corriendo la escena, podemos ver
que la caja está dando vueltas. Deteniendo el juego, podemos ver en la salida que el
mensaje listo se imprimió primero, solo una vez,
seguido de muchos números, la
mayoría de los cuales son uno 60. ¿Cómo funciona esto? Tanto ready como process son
funciones de nodo,
es decir, cada nodo nuestro árbol de escenas ya
tiene estas funciones, pero no están haciendo nada. Nuestro script está anulando
las definiciones de estas funciones para
un nodo en particular al
que se adjunta este script Podemos ver en nuestro script cuando
una función está anulando una definición de función
cuando tiene una flecha azul
delante de ella Cuando ejecutemos el juego,
el motor
reconstruirá el
árbol de escenas para esta escena, comenzando desde la raíz, agregando un nodo a la vez
de arriba a abajo La función ready
para cada nodo se
llamará después de que se agregue
al árbol de escenas, pero también después
de que
se hayan agregado todos sus hijos y sus funciones
ready hayan
sido llamadas primero. Esto significa que los padres pueden confiar
en que sus hijos sean agregados al árbol de escena antes de
que se los considere listos. Después de que todo el árbol de
escenas esté listo, entonces comenzarán los
fotogramas del proceso. El proceso se llamará
en cada nodo del árbol de escena de arriba a
abajo en orden secuencial. A diferencia de ready, los padres
no dejarán que sus hijos
procesen primero. Ahora que tenemos una comprensión básica
de cómo funciona Godot, en el siguiente video, comenzaremos configurar el proyecto
para hacer nuestro juego Te veré en el siguiente video.
7. Juego 0-6: Hola, amigos. Antes de
comenzar nuestro proyecto de juego, tendremos que preparar
algunas cosas. Primero, podemos
eliminar todo o iniciar un nuevo proyecto para que
tengamos un borrón y cuenta nueva. Voy a quitar todo
excepto la colisión de piso. Después renombrar esta escena y
su nodo raíz a juego. La escena del juego será una escena centralizada donde se lleva a cabo
toda la
jugabilidad principal. El nodo raíz del juego tendrá
dos ramas hijas principales, un nodo de entorno mundial
y un nodo de capa de lienzo. Estos representan una
clara distinción entre lo que existe
en el mundo del juego, como el nivel en el que el jugador
está jugando actualmente, todos los
elementos de los personajes, etcétera, y lo que existe fuera de ese mundo puramente para beneficio
del jugador, información que se muestra en una pantalla frontal o interfaz de usuario El nodo de Medio Ambiente mundial
tendrá varios hijos. Uno o más nodos para los niveles
actuales que se cargan, por ahora solo vamos a representar
eso como un tutti de cuerpo estático Un nodo tutti de cuerpo de personaje
se usa con mayor frecuencia para el personaje del jugador y un nodo Tutti de cámara que
suele seguir al jugador Voy a restablecer
la posición de
la colisión de piso de nuevo
al origen de la escena. Con un nodo de cámara en la escena, el rectángulo azul ya no representa qué parte del
mundo se dibuja en pantalla, en cambio, el
puerto de visión de la cámara se muestra en Magenta, actualmente centrado
en el origen. Por lo que el piso estará en el
centro de la vista de esta cámara. La capa de lienzo tendrá hijos para cosas
como mostrar la información del jugador en
pantalla, menús, etcétera Todos estos estarán representados
con nodos de control. Los
nodos Canvas y control seguirán utilizando el rectángulo azul
como ventana gráfica para organizar
sus posiciones en
la pantalla Cómo funciona esto mientras el jugador está jugando el juego es que la cámara verá el
mundo y dibujará lo que ve, todos los hijos del
mundo Environment Node. Después de que la cámara haya renderizado una
imagen rectangular de Toti del mundo, la capa Canvas dibujará a sus
hijos por encima de eso, creando la típica
pantalla de juego que estamos
acostumbrados a ver Estas dos ramas también comparten
otra clara distinción. Habrá
que pausar al mundo, pero la capa del lienzo no lo hará Por lo que seleccionar el nodo de juego
en el inspector bajo nodo, proceso de
expansión, cambiará su
modo de proceso a siempre. El
nodo de entorno mundial se establecerá pausble y la capa Canvas permanecerá como la herencia
predeterminada Heredará el
modo de proceso de su padre, que es el nodo de juego, por lo que también lo será siempre Dado que el modo de
proceso predeterminado es heredar, todos los hijos del
entorno mundial heredarán siendo pasibles mientras que los hijos de la capa Canvas
heredarán siempre el La primera vez que presionemos el botón Ejecutar proyecto
en cualquier proyecto nuevo, nos pedirá que
fijemos la escena principal. Podemos seleccionar la escena actual o seleccionar otra
del proyecto. Con la escena del juego
actualmente abierta, podemos configurarla como
la escena principal por ahora y cambiarla después
cuando tengamos una escena de título. Esto se puede cambiar
en la
configuración del proyecto bajo la configuración de ejecución. También es una buena idea establecer la configuración de
su pantalla
antes de comenzar. Así que selecciona ventana. Aquí podemos establecer
el ancho
y alto de la ventana gráfica medidos en píxeles Encuentro 12 80 por 720 para ser de
buen tamaño para la mayoría de los juegos, y es compatible
con la mayoría de las plataformas. Bajo stretch, cambiar el modo de
estiramiento de elementos desactivados a Canvas asegurará que dos nodos D se estiren
o encojan para que se ajusten a
la ventana del juego. Como voy a estar usando pixel art, voy a cambiar el modo de escala
de fraccionario a entero Por lo que los píxeles solo
duplicarán o la mitad de tamaño, evitando píxeles de tamaño mixto. Bajo
texturas de renderizado, también
cambiaré el
filtro de textura predeterminado de lineal a más cercano. Esto dibujará mis
activos de pixel art exactamente como están, evitando que sean borrosos Después de cerrar la configuración del
proyecto, es posible que deba activar una actualización simplemente haciendo
zoom o panoramizando la ventana gráfica para forzar que el rectángulo azul de la ventana gráfica o
la cámara se redimensionen o
la cámara Ahora estamos listos para comenzar a
dividir el proyecto en sus componentes individuales y abordarlos uno a la vez. En la siguiente sección, crearemos un personaje básico de
plataformas Tutti que el jugador pueda controlar Te veré en el siguiente video.
8. 1-1 Cuerpo del personaje: Hola, amigos. En esta sección, vamos a construir un personaje de plataformas de dos
D que el jugador pueda controlar Si tu escena de juego
no tiene ya un cuerpo de personaje dos Dnode,
deberías agregar uno ahora El cuerpo del personaje dos D no es un cuerpo en el
sentido de una persona, sino un cuerpo físico, como el cuerpo
rígido o el cuerpo estático. A diferencia de los cuerpos rígidos, un cuerpo de
personaje no tiene
automáticamente
la gravedad aplicada a él sino que reaccionará ante colisiones, a diferencia de un cuerpo estático Entonces el nodo del cuerpo del personaje también necesita una forma de colisión como hijo de él con un recurso de forma para decirle
qué forma es. La mayoría de los juegos usan una cápsula
para representar a un personaje, pero también se usan rectángulos y
círculos Por ahora, usaré
un rectángulo con dimensiones de 128 por 128. Siempre podemos cambiar o
cambiar el tamaño a la forma de colisión después de tener un dibujo
del personaje para
basarlo más tarde Además de una forma de
colisión, también
necesitaremos un
nodo de sprite para dibujar el personaje Es importante no usar un nodo Sprite Animado ya que este no es su propósito
previsto Los nodos Sprite animados son solo para dibujar sprites
animados simples Tan pronto como tengas que
sincronizar cualquier otro nodo con tus
animaciones como sonidos,
partículas o
funciones, necesitarás más flexibilidad de
la que el
nodo Animated Sprite puede proporcionar Por ahora, solo usaré el icono de Godot como textura del
personaje, que es de 128 por
128 Pixel cuadrado que coincide con
la forma de colisión Cambiemos el nombre del nodo
Toti del cuerpo del personaje al nombre
del personaje Si bien es posible
que no tengamos ninguna intención de tener múltiples copias
de este personaje, sigue siendo una buena idea componer su estructura
en una escena separada, aislada de la escena del juego. Podemos lograr esto haciendo clic
derecho en el nodo, luego seleccionando guardar
rama como escena. Vamos a crear una nueva
subcarpeta para escenas, otra dentro de esa
para personajes, luego guardarla como
nombre de este personaje En la escena del juego,
este personaje ahora se representa como un
solo nodo con un icono de tablilla, diciéndonos que se trata Todos sus
nodos hijos están ocultos, ahora contenidos dentro de
la escena del personaje. Podemos abrir la escena del personaje haciendo clic en el icono de la
tablilla. En la escena del personaje, es una buena práctica considerar el origen del
personaje está en el punto central entre el punto central entre
sus pies como si el eje
X fuera el piso. Esto asegura que todos los
caracteres tendrán su punto de origen en común
independientemente de su tamaño. Así que vamos a mover los nodos Sprite y la forma de
colisión
hacia arriba a lo largo del eje Y. Además de la
forma de colisión y los nodos Sprite, nuestro personaje necesitará
un jugador de animación para reproducir las animaciones de Sprite También un
Árbol de Animación para controlar qué animación se está reproduciendo
en un momento dado. Un
reproductor de flujo de audio dos nodos D nos
permitirá reproducir efectos de
sonido también. También podemos querer un emisor de
partículas GPU para crear efectos de partículas para cosas como pasos y saltos Cada uno de estos nodos
será cubierto en su propio video para
explicarlos con más detalle. Por ahora, es importante
entender cómo una escena
puede representar cualquier cosa en el juego con su propia escena teniendo muchos nodos hijos
que se utilizan para construirla. El nodo raíz de esta escena suele tener un script
adjunto al mismo. Dependiendo de cómo prefiera
organizar sus archivos, posible
que desee
mantener este script en la misma carpeta que
la escena a la que se adjunta o en una carpeta separada
específicamente para los scripts. Debe nombrar
sus guiones después de su propósito previsto en un nombre lo más
vago posible Este guión no será específico
para mi personaje infantil, sino que debería escribirse de
tal manera que pueda aplicarse a cualquier personaje, al
menos por ahora El propósito del
script será no solo controlar el propio nodo del
cuerpo del personaje, sino también realizar las
operaciones de todos los
nodos hijos para operar en armonía según sea necesario para crear
nuestro personaje. Este guión adjunto
al nodo raíz de nuestra escena de
personajes
también es accesible
desde la escena del juego y servirá para dos propósitos
adicionales. Se ofuscará el procesamiento
de los componentes individuales de la escena del personaje a
la vez que proporciona una interfaz limpia
y concisa para interacción con otros guiones y objetos en la escena del juego Esto se explorará con
mayor detalle a lo largo
del resto de esta sección. Ahora que tenemos lista una estructura básica de
personajes, necesitaremos recibir aportes del jugador para controlarlos. Te veré en el siguiente video.
9. Mapa de entrada 1-2: Hola, amigos. En este video, vamos a
recibir entrada
del jugador y
enviársela al personaje. Desde que creé el script para mi cuerpo de personaje Tu Di
node a partir de una plantilla, ya tiene algún
código que
recibirá entrada y moverá el
carácter hacia la izquierda o hacia la derecha. Si ejecutamos la escena del juego, al
presionar las teclas de
flecha izquierda y derecha se
moverá al personaje, pero no se siente muy bien y no se implementa muy bien. El comentario proporcionado incluso nos
dice que al
menos deberíamos reemplazar acciones izquierda y derecha de
la interfaz con nuestras propias acciones de
juego personalizadas. Para ello, abriremos la configuración
del proyecto, luego cambiaremos a la pestaña Mapa de
entrada. En el campo que
dice agregar nueva acción, vamos a escribir el nombre
de nuestra acción, empezando por mover a la izquierda. Esto no debe contener ningún espacio y generalmente se escribe
en minúsculas serpiente, todas minúsculas separadas
con Presiona la tecla Enter o haz clic en el botón Agregar para agregar
la acción de entrada, luego haz
otra para moverte a la derecha. Y también necesitaremos
uno para Jump más adelante. A la derecha de cada una
de estas acciones, haga clic en el botón más para agregar un evento a
esta acción de entrada. Este será el botón que
se presiona para activarlo. El campo de escucha detectará
automáticamente los eventos de entrada, o puede buscar a través de
los eventos de entrada disponibles. Para moverme a la izquierda, usaré
la tecla de flecha izquierda, moviéndome a
la derecha con la tecla de flecha derecha, y saltar será la tecla z. Podemos agregar múltiples
eventos diferentes a cada acción, lo que significa que podemos agregar soporte de
controlador fácilmente agregando
eventos adicionales para el controlador. Usaré pad direccional izquierda y derecha para
mover al personaje, así
como stick izquierdo a
izquierda y derecha, y también el
botón de la cara inferior para saltar. Cuando hayas terminado, cierra
la configuración del proyecto. En este video,
solo vamos a cambiar esta única línea donde
estamos recuperando entrada, y lo más importante,
moverla a un script separado Es una buena práctica que todos tus guiones tengan un
solo propósito. Este guión solo se
utilizará para controlar a un personaje, no para recibir entrada
del jugador. Añadiendo un nuevo nodo
al árbol de escenas, éste puede ser simplemente un nodo
normal ya que no va a estar haciendo otra cosa
que ejecutar nuestro script. Vamos a llamarlo Jugador. Después adjuntarle un nuevo guión. Hay múltiples
formas de recibir entrada. El más común es
anular la función de entrada. Las anulaciones de función deben coincidir exactamente con la
función que se está anulando Entonces el nombre debe tener exactamente
la misma ortografía, los mismos tipos de parámetros
y el mismo tipo de retorno. La función de entrada
tiene un parámetro, un evento de entrada, al que
podemos nombrar lo que queramos. Pero prefiero usar
sus nombres predeterminados, y no devuelve nada. La función de entrada se
llamará durante cualquier fotograma cuando ocurra algún evento de
acción de entrada, ya sea
presionar un botón, inclinar un stick analógico
o mover el mouse Dentro de esta función de entrada, podemos acceder al evento input por su nombre y acceder a su
contenido con un punto. Queremos llamar a una función
del evento de entrada llamada
Is action pressed. Al llamar a una función, el nombre de la función debe
ir seguido de paréntesis Dentro de los paréntesis,
proporcionamos argumentos a la función
que coinciden con sus parámetros En este caso, una cadena, el nombre de la
acción de entrada que estamos comprobando. Entonces escribiremos salto
entre comillas, teniendo cuidado de hacer coincidir
el caso exacto y ortografía de la acción de entrada que creamos en la configuración del
proyecto. Esta función devuelve un booleano, ya sea true si
se presionó el botón o
false si no lo fue Al poner esta función
después de la palabra clave if, luego seguida de dos puntos, podemos crear un nuevo
nivel de sangría para nuestro script Cualquier cosa que pongamos aquí
dentro solo se ejecutará si el resultado de la declaración
I es verdadero, así que solo si se presionó el
botón. Por ahora, solo
imprimiremos la palabra salto. Ejecutando el juego,
si presionamos alguno de los eventos de entrada que especificamos
como la acción de entrada de salto, veremos que jump está
impreso en el panel de salida. No necesitamos la
función ready, así que vamos a eliminar eso. Para cosas como el movimiento, especialmente cuando se usan
controladores con sticks analógicos, puede ser útil verificar esta entrada dentro de la función de
proceso. Al igual que estaba haciendo el
script de caracteres, necesitaremos usar
el singleton de entrada Esta clase singleton tiene una
función llamada get axis. La función del eje G
requiere dos parámetros, una acción negativa y
una acción positiva. La izquierda siempre se considera la negativa y la derecha positiva, coincidiendo con el eje X
en nuestro mundo dos D. Entonces escribiremos los nombres
de nuestras acciones de entrada que creamos en la
configuración del proyecto entre comillas, moveremos a la izquierda y moveremos a la derecha. Esta función devolverá un número decimal entre uno
negativo y uno positivo, representando
hasta qué punto
se inclina el stick izquierdo en cualquier dirección, o simplemente uno negativo o uno positivo si usa
teclas o botones Dado que un valor de cero, lo que significa que no se está
dando ninguna entrada, sigue siendo una entrada válida siempre
vamos a querer enviar esta información al
jugador cada cuadro. Entonces no hay necesidad de
una declaración if aquí. Vamos a imprimir el valor que se devuelve aquí
para que podamos verlo. ejecutar el juego, el número cero se está
imprimiendo repetidamente. Presionando las teclas de flecha izquierda o
derecha, las teclas del pad de dirección en
mi controlador o inclinando el stick analógico izquierdo cambia el valor entre
uno negativo y uno positivo Si alguna vez deseas
más información sobre alguna de estas
clases o funciones, puedes acceder a su
documentación
manteniendo pulsada la
tecla de control o comando y haciendo clic en ellas. abrir el
script de caracteres desde antes, tenemos una variable
llamada direction que se declara dentro de
la función de proceso. Comentemos esto y
movamos esta variable
al alcance global
de nuestro script
declarándolo en la parte superior
del guión en su lugar Volviendo al
guión del jugador donde recibimos entrada de
movimiento para pasar esta información de
un guión a otro, necesitaremos una referencia
al otro guión. En el script del jugador, vamos a crear una
variable que contiene una referencia a un cuerpo de
personaje para dende Al agregar una etiqueta de exportación al frente de la
declaración de
la variable, la variable será
accesible desde el inspector, y podemos asignar su
valor como nuestro carácter. Entonces, en lugar de imprimir el valor del punto de entrada get axis, lo
enviaremos
al personaje
asignándolo a la variable de
dirección del personaje Cuando ejecutemos el juego, el nodo
jugador estará comprobando cada fotograma para ver el estado de
nuestras entradas de movimiento a la izquierda y
a la derecha. Después asigne eso a la variable de dirección del
personaje. La función de
proceso de scripts de caracteres verificará la variable de
dirección, cada fotograma y la usará para mover el
carácter hacia la izquierda y hacia la derecha. Ahora tenemos a nuestro jugador dando entrada para mover a nuestro personaje. Te veré en el siguiente video.
10. Movimientos 1-3: Hola, amigos. En este video, vamos a
mejorar el
movimiento de los personajes aplicando la física. En el script de caracteres, podemos ver que la plantilla
por defecto está comprobando si el valor
de direction es cero. Cero se trata como falso y
cualquier otro valor es verdadero. Entonces, si se le da algún valor de
dirección que no sea cero, la
velocidad X del personaje se establece en dirección
multiplicada por la velocidad. O si la dirección es cero, entonces está moviendo el valor de la velocidad X del personaje
hacia cero por velocidad. El resultado de esto es que la velocidad del personaje
es cero o velocidad, excepto en el caso de
inclinar el stick analógico Esto no es muy realista
y no se siente muy bien. Estos valores
de velocidad y
velocidad de salto también se definen como constantes,
que, a diferencia de las variables,
nunca se les permite cambiar Esto es problemático, y
deberíamos cambiarlo si alguna vez
queremos que los personajes se muevan a diferentes velocidades en nuestro juego. Nos ocuparemos de saltar más tarde. Otra cosa a tener en cuenta es que estos valores
se miden en píxeles, por lo que variarán en función
del tamaño de tu personaje. Por ahora, reemplacemos
nuestra constante
de velocidad una
variable de velocidad de movimiento de tipo flotador. Pondré el mío a 256
píxeles por segundo. Es una buena idea separar variables y funciones
en lo que se pretende que sea público versus privado
precediendo nombres privados
con un guión bajo Cualquier cosa privada
está pensada para que solo se pueda acceder desde dentro de
este script en sí, a diferencia de la variable direction, que se está
accediendo y cambiando desde el script del reproductor,
por lo que es pública. En el proceso de física, reemplazaremos la
constante de velocidad con nuestra variable de velocidad de
movimiento. Y ahora todo funciona
exactamente como lo hacía antes, excepto que la velocidad
es un poco más lenta. Si agregamos una etiqueta de exportación al frente de esta declaración de
variable, podremos cambiar el
valor de la misma en el inspector. Esta es una excelente
manera de probar y ajustar el valor para
que se sienta bien Ya que podemos ejecutar nuestro juego, ver si se siente bien, luego
cambiarlo y volver a probar. Otro beneficio es que si tenemos múltiples caracteres
usando este mismo script, cada uno puede tener su propio
valor para esta variable. Pero los personajes no suelen
pasar de quedarse quietos a moverse a su máxima
velocidad instantáneamente En cambio, tienen cierta
cantidad de aceleración aplicada a lo largo del tiempo antes de
alcanzar su velocidad máxima. Esto se puede lograr
declarando otra variable
llamada aceleración, también a flote y se
medirá en píxeles
por segundo al cuadrado Si lo hace más fácil, puedes considerar que su valor un múltiplo de tu velocidad. Si mi aceleración
es el doble de mi velocidad, entonces alcanzaré la
velocidad máxima en medio segundo. O si es la mitad de mi velocidad, entonces tardará 2 segundos en
alcanzar la velocidad máxima. Para aplicar la aceleración
en el proceso físico, todo lo que tenemos que hacer es mover el valor de nuestra velocidad X
actual hacia la velocidad multiplicada por la dirección a una velocidad
de aceleración. Pero esto sucederá de una vez
en un solo fotograma. Para ajustar la velocidad a lo largo del tiempo, tenemos que hacer lo que la
plantilla está haciendo aquí donde aplica gravedad
y multiplicar por Delta. Dado que Delta es la
cantidad de segundos que han pasado desde
el fotograma anterior, generalmente uno 60 de segundo, esto provocará que la tasa
de aceleración se
aplique a lo largo del tiempo en
lugar de todas a la vez El movimiento hacia la función toma lo que está en el
primer parámetro, lo
mueve hacia
el valor del segundo parámetro por la cantidad del
tercer parámetro y devuelve el resultado. No modifica el valor
del primer parámetro, así que tenemos que
asignarlo para sobrescribir el valor anterior
de nuestra velocidad X. La función de movimiento y deslizamiento se define en el cuerpo del personaje dos clases D y
realizará todos los
cálculos difíciles para nosotros, considerando la velocidad del
personaje, fuerzas
externas como la gravedad, colisiones con otros cuerpos
físicos, y luego decidir dónde debe estar el
personaje cada fotograma Ejecutando el juego ahora, tenemos una aceleración
gradual
que se está aplicando antes de alcanzar
nuestra velocidad máxima, y también podemos
ajustar el valor de nuestra aceleración
en el inspector para que se sienta de
la manera que queremos. Podemos eliminar estos comentarios. La misma lógica se puede aplicar a la desaceleración simplemente
agregando otra variable Este valor suele ser mucho
mayor que la aceleración. El código en el proceso de física ya
está utilizando mover hacia. Sólo tenemos que sustituir la velocidad por tiempos
de desaceleración Delta Sin embargo, hay otro momento
en el que es posible que queramos aplicar desaceleración que no sea cuando el jugador no está
dando ninguna entrada, que es cuando quiere dar la
vuelta e ir por el otro lado Podemos ampliar nuestra declaración I
para considerar este caso. Después de verificar si
la dirección no es cero, si nuestra velocidad X es cero, el personaje está parado, entonces todavía
queremos acelerar. Pero también, si el
pecado de dirección es el mismo que el
seno de la velocidad X, entonces el jugador está tratando de
seguir moviéndose en la
misma dirección en la que ya
se están moviendo y
queremos seguir
acelerando a la velocidad. La función seno convertirá
cualquier número en uno negativo, cero o uno positivo, haciendo más simple comparar si
estos dos valores son ambos positivos o
ambos negativos. Podemos combinar condiciones
junto con o. Entonces, si alguno de estos
valores es verdadero, entonces toda la
afirmación es verdadera. Si ambos son falsos, entonces queremos dar la vuelta, lo que significa aplicar
desaceleración lugar de aceleración, resultando en un
cambio mucho más rápido que lo haría
aplicando aceleración
si el valor de desaceleración Probando esto, mover
nuestro personaje hacia la izquierda
y hacia la derecha debería parecer
mucho más realista ahora, y podemos ajustar fácilmente
los valores de nuestra velocidad, aceleración y desaceleración
en el inspector Te veré en el siguiente video.
11. 1-4 Saltos: Hola, amigos. En este video, vamos a mejorar cómo se implementa
el salto. Antes de comenzar a
saltar, moveré la cámara hacia
arriba a lo largo del eje Y para que el piso esté en la parte inferior de la pantalla, no en la mitad. El script de plantilla
para nuestro personaje ya tiene un
botón de salto usando UI excepto, que es la barra espaciadora, configurando la
velocidad Y del personaje para saltar velocidad. Pero ya agregamos nuestro propio botón de salto
en un video anterior. A diferencia de la gravedad o la aceleración, que se multiplican
por Delta y se aplican al personaje
sobre múltiples fotogramas, esta velocidad de salto se aplica
al personaje de
una vez inmediatamente. Ejecutando el juego, podemos
presionar la barra espaciadora para saltar, pero hay múltiples problemas. El salto es siempre de
la misma altura, y tenemos el
script de caracteres comprobando la entrada. Primero eliminemos esto
del proceso de física
del personaje y en su lugar lo
pongamos en una función pública. Lo llamaremos salto. Después en el guión del jugador, al presionar el botón de salto, en lugar de imprimir salto, podemos decirle
al personaje que salte en su lugar. Accediendo al
contenido del personaje con un punto seguido del
nombre de la función, y la función no
tiene parámetros, por lo que no hay nada
entre paréntesis Pero ahora estamos
permitiendo que el personaje salte cada vez que se presiona el
botón, aunque no estén
en el suelo. Tenemos que verificar si
el personaje está en el piso primero antes de
permitirle saltar. Esto es en la función de piso se define en el
cuerpo de carácter dos clase D. Ahora el personaje sólo puede
saltar si está en el suelo, pero el salto es siempre de
la misma altura. En la mayoría de los juegos, el
personaje saltará más alto manteniendo presionado el botón
que si solo se presiona. A veces podemos
medir cuánto tiempo se mantiene
el botón de salto
antes de soltarlo, luego pasar esa
información a través de la llamada a la función de salto para
ajustar la fuerza de salto. Pero sobre todo en dos juegos de plataformas
D, generalmente
esperamos que los saltos ocurran de inmediato cuando
presionamos el botón, lo que significa que no podemos esperar a que
el botón se mantenga
presionado o se suelte Entonces, en cambio, es más común asumir que
el salto será la altura completa del salto
y luego
cortarlo si el jugador
suelta el botón antes de tiempo. la misma manera que reaccionamos ante un botón que se presionaba
en el guión del jugador, podemos reaccionar a que
se libere también. Usando la palabra clave if, esto solo se verificará si las condiciones
anteriores si
eran falsas, eliminando la redundancia
de verificar si el botón fue presionado y liberado al mismo tiempo Si se suelta el botón de salto, podemos llamar a una función
diferente para cancelar el salto
cortándolo corto. De vuelta en el script de caracteres, necesitamos declarar la función de salto
cancelada, que no requiere parámetros
y no devuelve ningún valor. Una forma sencilla de hacer
esto sería
establecer la velocidad
Y del personaje en cero, pero esto puede parecer bastante antinatural llegando a una parada
completa en el aire Entonces, en cambio, dividiré
la velocidad Y por dos. Pero solo queremos que
esto suceda si la velocidad del personaje es
actualmente menor que cero, es
decir, se están
moviendo hacia arriba y solo si su velocidad es menor que
cero porque saltaron. Si hubiera alguna otra
razón por la que el personaje se movía hacia arriba, pero no saltaron, no
querríamos que
cancelaran un salto y
redujeran su velocidad. Podemos controlar esto
declarando una nueva variable. Lo llamaremos Is jumping
de tipo Boolean, que naturalmente
por defecto será Si establecemos esta variable en
true cuando el personaje salta, entonces podemos verificar
si el personaje está saltando antes de
permitirle cancelar el salto. En el caso de que
no cancelen el salto, necesitamos establecer la
variable is jumping de nuevo a
false automáticamente. Entonces en el proceso de física, comprobando si el personaje
está saltando y si su velocidad y es
mayor o igual a cero, es
decir, el personaje está cayendo o al menos
no se mueve hacia arriba, entonces podemos establecer está saltando de
nuevo a falso porque es demasiado tarde para que el personaje suelte el botón
para cancelar este salto. Esto funciona muy bien, pero
ahora tal vez queramos
ajustar qué tan alto puede saltar el
personaje. El script de la plantilla declara la velocidad de
salto como una constante. Al igual que hicimos con
la velocidad de movimiento, podemos cambiar esto
para que sea una variable. Pero saber cuánta
velocidad se requiere para alcanzar una altura específica
no es muy intuitivo, y desde una perspectiva de diseño, a menudo
es mejor poder controlar exactamente qué tan alto puede saltar
un personaje. Así que vamos a declarar
otra variable llamada altura de salto
como un entero. Esto se medirá en píxeles. Voy a poner el mío en 256, que es el doble de la
altura del personaje. Usando la etiqueta on ready, podemos usar algunas
matemáticas para calcular la fuerza de salto requerida para
alcanzar esta altura exacta. La etiqueta on ready
ejecutará esta línea del script cuando el nodo esté listo antes de la función ready. No soy físico,
así que no
podría explicar por qué funciona esta
ecuación, pero sí Simplemente tome la raíz cuadrada de la gravedad multiplicada por la fuerza de
salto por dos. Entonces también multiplique todo
esto por
uno negativo ya que negativo
a lo largo del eje y es hacia arriba. Para ello, necesitamos
conocer la fuerza de gravedad se
está aplicando
al carácter como un número decimal, a flote Entonces declarando otra variable
usando la etiqueta on ready, esta debe estar por encima de
la variable de fuerza de salto, por lo que se establecerá primero Podemos obtener la fuerza de gravedad desde la configuración
del proyecto. Sólo tenemos que especificar la ruta a la configuración
que queremos en una cadena. Finalmente, cuando el
personaje salta, estableceremos su velocidad Y a
esta fuerza de salto calculada. Ahora el jugador puede controlar
qué tan alto quiere saltar. Y podemos editar fácilmente altura máxima de salto de
un personaje desde el inspector. Te veré en el siguiente video.
12. 1-5 Caída: Hola, amigos. En este video, ajustaremos cómo
se siente y controla el personaje en el aire. Nuestro personaje puede
saltar más alto ahora, pero se siente muy flotante, y el personaje puede
controlar su movimiento en el aire tan fácilmente como
podría hacerlo en el suelo Quizás quieras esto para tu juego, pero muchas veces el jugador tiene menos control sobre el
personaje mientras está en el aire. En el script de caracteres, podemos eliminar estas constantes
antiguas ya que ya no
se utilizan en ningún Ya que nuestro guión está
haciendo múltiples cosas, moviendo el personaje a izquierda
y derecha y saltando, sería una buena idea
mantenerlo organizado. Mantendré mis
variables de
velocidad de movimiento,
aceleración, desaceleración y dirección
agrupadas y haré lo
mismo con variables
relacionadas con el salto Incluso podemos crear categorías
para nuestras variables usando la etiqueta de categoría de exportación y especificar el nombre de
la categoría como una cadena. Tengamos una
categoría separada para las variables relacionadas con la locomoción
y otra para el salto Esto agrega encabezados
al inspector, por lo que nuestras variables exportadas se
organizarán en
estas categorías. Nuestra categoría de salto solo
tiene una variable, pero agregaremos algunas
más, comenzando con un multiplicador de gravedad. Esto va a ser un flotador y le
voy a dar un valor
por defecto de uno. Luego multiplique nuestra
gravedad por el
multiplicador de gravedad después de
recuperarla de la configuración del proyecto Dado que este número se
utiliza para calcular la fuerza de salto requerida para
alcanzar nuestra altura de salto deseada, la
altura de salto del personaje no cambiará, y la fuerza
se incrementará automáticamente para compensar. Al abrir los ajustes del proyecto, mirando debajo de Física dos D, la gravedad
predeterminada se establece
en 980 píxeles por segundo al cuadrado Podemos modificar la fuerza
de gravedad aquí para todo
el proyecto y
afectaremos a todos nuestros cuerpos
físicos. Es posible que queramos que algunas cosas se sientan más pesadas o
ligeras que otras, y una manera fácil de
hacerlo es multiplicar su propia gravedad individual
por un número diferente. Aumentar el multiplicador de
gravedad de nuestro personaje hará que su salto sea más rápido y hará que
el personaje se sienta más pesado. Bajar el multiplicador de gravedad los
hará sentir
más ligeros y flotantes A continuación, podemos reducir
la cantidad de control el jugador tiene sobre el personaje
usando más multiplicadores, comúnmente conocidos como
control de aire y frenos de aire control de aire se usa cuando el jugador está dando entrada de
movimiento
en el aire y frenos de aire cuando no están dando
entrada en el aire medio Pondré ambos en 0.5,
lo que significa que la
aceleración
y desaceleración del personaje se reducirán a la mitad Abajo en el proceso de física, podemos organizar mejor
todo lo que está sucediendo dividiéndolo
en diferentes funciones, una que se llama solo cuando el personaje está en el piso
y otra cuando no lo están. Pasaremos el valor
de Delta a ambas funciones. Al definir una función de física
terrestre separada, ahora
podemos
enfocarnos en aplicar solo la física adecuada para cuando el personaje
está en el suelo. Entonces crea otra función
para la física del aire y usa esta función para
controlar al personaje manera diferente a cuando
están en el suelo. Aquí es donde aplicaremos
la fuerza de la gravedad. Luego copia también los
controles para el personaje que se mueve y no se mueve
de la física del suelo. vuelta es menos
importante en el aire ya que no hay terreno
para proporcionar fricción, por lo que no tendría sentido
dar la vuelta Todo lo que tenemos que hacer es multiplicar la
aceleración natural del personaje por el multiplicador de control de aire y su desaceleración por el multiplicador de frenos de
aire Otro método es que se podría considerar el control de aire
y los frenos de aire como valores
alternativos que
sustituyan a la aceleración y desaceleración en lugar de
utilizarlos como multiplicadores También es posible que desee considerar
agregar una velocidad terminal, dependiendo de la cantidad de caídas que esté haciendo
el personaje para largas distancias y
si el jugador necesita tener un mejor
control en tales situaciones. Una velocidad terminal es la velocidad máxima que un objeto podrá
recorrer por el aire, ya que la fuerza de resistencia del
aire
eventualmente igualará la fuerza
de la gravedad y se cancelará
entre sí. Como todavía no tenemos un entorno adecuado
para probar esto, todo lo que realmente podemos hacer es establecer la altura
del salto del personaje en algo muy alto, tal vez incluso
alejar la cámara para que podamos ver más arriba. Pero podemos ver que
el personaje se
moverá muy rápido al
seguir largas distancias, y es muy difícil para el jugador controlar
con alguna precisión. Así que vamos a exportar otra variable para nuestra velocidad terminal. En la atmósfera terrestre,
un humano paracaidista
alcanzará una velocidad terminal a
unos 54 metros/segundo Si 100 píxeles es de 1 metro, entonces eso es 5,400
píxeles por segundo Para aplicar este límite en
la función de física del aire, simplemente
podemos usar la función
Min para devolver ya sea la velocidad Y
actual del personaje o la velocidad terminal, la
que sea menor Luego asigne el valor devuelto a la velocidad Y del personaje. Ahora podemos limitar fácilmente qué tan rápido se
permite que el personaje caiga en el inspector, dándole al jugador más control cuando está siguiendo
largas distancias. Voy a poner el mío en 4,096 por ahora. Te veré en el siguiente video.
13. 1-6 Running: Hola, amigos. En este video, agregaremos un botón de ejecución
que el jugador puede mantener pulsado para cambiar
su velocidad de movimiento. Primero, restableceré
el Zoom de la cámara y la colocaré
donde estaba antes. La velocidad de
movimiento del personaje al jugar con el teclado
es siempre la misma, pero podemos ajustar
la velocidad de movimiento inclinando solo parcialmente
el stick analógico En algunos juegos, esto es suficiente para permitir que el jugador camine
o corra. Pero en otros, hay
un botón de carrera designado para que el jugador mantenga
pulsado para moverse más rápido. Al abrir la configuración del proyecto, podemos agregar un botón Ejecutar
a nuestro Mapa de entrada. Usaré la tecla Mayús o el botón de la cara derecha
en mi controlador. En el script del reproductor,
usaremos las mismas funciones que hicimos con el salto para verificar si se está
presionando o soltando
el botón de ejecución. Cuando se presiona el botón de correr, podemos decirle al
personaje que corra, y cuando se suelta,
decirle que caminen. Mientras estamos aquí, podemos
lidiar con esta advertencia de que la función de proceso
en realidad no está usando el
valor de Delta. Para anular
una función existente, los parámetros deben
coincidir exactamente, por lo que no podemos eliminar
Delta por completo. En cambio, el motor Godot
preferiría que marquemos este parámetro como no utilizado precediendo su nombre
con un guión bajo Alternativamente, podemos abrir
el panel de advertencias y hacer clic en Ignorar para decirle al motor que ignore
esta advertencia. Ahora el
guión del personaje necesitará estas funciones públicas,
correr y caminar. Comenzaremos agregando dos variables exportadas más
en la categoría de locomoción, una velocidad de caminata y una velocidad de carrera Entonces la velocidad de movimiento puede tener
su etiqueta cambiada de exportación a on ready y su valor asignado a la velocidad de
caminata por defecto. Dando
una declaración a las funciones de caminar
y correr ,
no aceptar parámetros y no devolver valores, solo
necesitamos establecer el valor de velocidad de movimiento para velocidad de carrera o
velocidad de caminata. Entonces el proceso de física
manejará el resto usando el
valor actual de la velocidad de movimiento. Eso es todo lo que se necesita para cambiar la velocidad de movimiento de
nuestro personaje mientras mantienes pulsado un botón. Podríamos revertir esto fácilmente para que el personaje se
ejecute por defecto, pero mantén presionado un botón para caminar simplemente
cambiando el valor
predeterminado de velocidad de movimiento a velocidad de carrera y haciendo que el script del jugador
llame a las funciones opuestas. Como esta lección fue tan corta, también
me prepararé para el siguiente video agregando un bloque para que
el personaje salte
usando un nodo de cuerpo estático. A Te veré en el siguiente video.
14. 1-7 Coyote: Hola, amigos. En este video, vamos a ayudar al
jugador agregando funciones de accesibilidad
que harán que nuestro personaje se sienta más
indulgente para controlar Comenzaré restableciendo la altura
del salto del personaje a un número razonable En la mayoría de los dos juegos de plataformas D, el juego permitirá
al jugador presionar el botón de salto por
un corto tiempo después su personaje haya
salido de una repisa y también cuando está cayendo
y casi aterrizando En ambos casos, la función is on floor
devolverá false, pero haría que el
juego se sintiera mejor para el jugador si aún se
le permite realizar un salto. Para agregar estas características, comencemos cambiando
el tipo de retorno de
la función de salto de
nada a un booleano Entonces volveremos verdadero si el salto fue exitoso
o falso si no lo fue. De esa manera, el guión del jugador puede reaccionar ante el
botón de salto que se presiona demasiado pronto y volver a intentar el salto después de que el personaje
aterrice en el suelo Cambiando al guión del jugador, en lugar de simplemente llamar a la función de salto de punto de
carácter, podemos reaccionar a su valor de retorno poniéndolo dentro
de una declaración if. Si jump devuelve true, no
necesitamos hacer nada, pero si devuelve false, podemos suponer que el
jugador quiere saltar cuando
sea posible si eso
sucede relativamente pronto. Entonces si no salta, si jump devolvió false, entonces almacenaremos en búfer
esta entrada de salto por una breve ventana de tiempo. La forma más fácil
de realizar un seguimiento del tiempo es usar un nodo temporizador. Podemos agregar esto como un
hijo del nodo jugador, o como el nodo jugador no tiene un tipo específico para el
que lo estemos usando,
podemos cambiar su tipo
para que sea el propio temporizador. Al observar sus propiedades
en el inspector, podemos establecer la
duración del temporizador, que será la ventana de tiempo
durante la cual la entrada se
almacenará en búfer y establecer su propiedad one
shot en true. Esto significa que una vez iniciado, el temporizador solo
contará atrás hasta 01 tiempo. El comportamiento predeterminado sería
contar hasta cero repetidamente. A continuación, declaremos
una nueva variable. Le nombraremos
entrada en búfer de tipo callable. Callable es una clase que contiene una llamada a función completa
con argumentos Entonces, si nuestro salto falla, queremos establecer nuestra entrada en
búfer para que sea salto de punto de
carácter
sin paréntesis, ya que no estamos llamando a
la función ahora, sino almacenándola en una variable Y también arranca el temporizador. Desde que cambiamos el tipo
de este nodo a un temporizador, tendremos que cambiar el tipo de nodo que este script extiende en la parte superior del
script para poder
acceder a funciones de
la clase timer. Entonces en la función de proceso, si este temporizador se está ejecutando, si no se detiene, entonces llame a la entrada búfer. Si la
entrada en búfer devuelve true, entonces tuvo éxito, y
podemos detener el tiempo. Si la entrada en búfer
devolvió false, entonces no puede suceder
todavía este fotograma, y querremos volver a
intentarlo el siguiente fotograma hasta que se
acabe el temporizador o tenga éxito Para fines de prueba, también
usemos algunas declaraciones de impresión para imprimir cuando el
salto está en búfer, cuando falla la entrada en búfer y cuando tiene éxito Ejecutando el juego, si
presionamos el botón de salto temprano, la entrada de salto se almacena en búfer. Falla algunas veces luego tiene éxito cuando el
personaje golpea el suelo Si presionamos el botón de salto cuando el personaje está
muy arriba en el aire, entonces la entrada se almacena en búfer, pero falla hasta que
se agota el temporizador y nunca tiene éxito Una vez que estemos satisfechos con el rendimiento de
nuestro almacenamiento en búfer de entrada, podemos eliminar o comentar
estas declaraciones impresas A continuación, queremos permitir que
el personaje salte si recientemente han
salido de una repisa, comúnmente conocida como tiempo de coyote,
refiriéndose
al coyote Wiley En la
escena del personaje, podemos agregar un nodo temporizador y
cambiarle el nombre coyote Al igual
que el temporizador de búfer de entrada, será un temporizador de un disparo, y podemos ajustar la
duración del temporizador. Con la escena del personaje abierta
en el guión del personaje, podemos tomar una referencia
a cualquier nodo hijo manteniendo presionada la tecla de
control o comando, luego haciendo clic y arrastrando
el nodo al script Esto
crea automáticamente una variable con el mismo nombre y usa la etiqueta on ready
para establecer su valor usando la notación de ruta de nodo
que comienza con el signo $1. El uso de esta notación de ruta de
nodo de signo de dólar requiere que este nodo debe existir con la ruta de nodo exacta relativa al nodo al que está adjunto
este script. De lo contrario,
provocará un error. Sin embargo, este
tiempo de coyote es una característica que generalmente solo
es aplicable
al personaje del jugador Puede que no queramos
tener este nodo en cada escena de personajes. Entonces podemos usar la
función get node o null pasando la misma
ruta de nodo como un argumento de cadena. Esta función devolverá una referencia
al nodo que sigue esta ruta de nodo o nulo si no existe sin
causar ningún error. En la función de salto, nuestra verificación para ver si es posible
un salto ahora
será si
el personaje está en el piso o si
el personaje tiene un temporizador coyote y el temporizador
coyote no está parado En operaciones lógicas, y se
evaluará antes o a menos
que incluya corchetes. En lo que respecta a la declaración A, se verificará
el lado izquierdo
antes que el lado derecho. Entonces, si el
temporizador coyote no existe, la declaración A
se considerará falsa Por lo que no se
verificará
el lado derecho
de si el temporizador coyote está funcionando o no Ahora todo lo que tenemos que hacer es
iniciar el temporizador coyote. Para ello, necesitamos saber cuándo el personaje
sale de una repisa Consideraré que esto está incluido en la categoría de
salto, y declararemos
dos nuevas variables. Está en piso para almacenar el valor devuelto de la función I on floor
para este marco. Esto nos permitirá
realizar esta comprobación una vez por cuadro y almacenar los resultados para que podamos usarlo varias veces, ahorrando la necesidad de llamar a la
función varias veces por cuadro y estaba en piso, lo que mantendrá el valor de is en piso
del cuadro anterior. Durante el proceso de física, estableceremos el valor de was
on floor a is on floor, luego está en floor
al valor devuelto de
la función is on floor. Cualquier otra llamada a la función
is on floor puede usar nuestra variable en su lugar
para ser más eficientes. Entonces si el personaje
estaba en el suelo en el
cuadro anterior y no está en el piso de este cuadro y su velocidad y es
mayor o igual a cero, es
decir, no saltaron, la única conclusión lógica es que este
personaje ha
salido de una repisa o el piso
en el que estaban parados ha desaparecido, y este es el momento exacto cuando debería comenzar el
temporizador coyote. Para fines de prueba,
agreguemos declaraciones impresas para
que sepamos cuándo comienza
el temporizador de coyote y cuándo se realiza con éxito
un salto de coyote Esto requerirá una sentencia if
redundante, pero la eliminaremos más tarde. Bien. Ejecutando el juego para probarlo. Podemos bajarnos de una repisa y ver que arranca el
temporizador de coyote Si presionamos el botón de salto mientras el
temporizador coyote está funcionando, entonces el personaje aún
puede realizar un salto Ahora tenemos una
plataforma Toti sólida y controlador de
personajes En la siguiente sección,
dibujaremos y animaremos al personaje Te veré en la
siguiente sección.
15. Sprite 2-1: Hola, amigos. En esta sección, vamos a tomar
nuestro sencillo icono de Gadot y pulirlo para convertirlo en un personaje
completamente animado Para eso, vamos
a necesitar activos, imágenes y archivos de audio. Los que estoy usando se
incluirán si
quieres usarlos,
pero recomiendo a los estudiantes
intermedios usen tus propios activos u
otros activos gratuitos. Antes de comenzar a
importar activos, es una buena idea crear una carpeta separada para mantenerlos. También podemos crear
diferentes subcarpetas para diferentes tipos de activos como hojas de sprites y efectos de sonido Haga clic en la carpeta en la que desea que estén
sus activos importados, luego simplemente haga clic y arrastre los activos a
la ventana de Gadot El proceso de importación
ocurrirá automáticamente, y se ordenarán
en la carpeta enfocada. Si no están en
la carpeta correcta, siempre
puedes arrastrarlos pestaña
del sistema de archivos para
reorganizarlos también. Pero esto
desencadenará una reimportación, por lo que es mejor importarlos
a la
carpeta correcta para empezar, especialmente para archivos más grandes Abre tu escena de personaje
si no está abierta ya. Usar estos activos para dibujar el personaje podría ser
tan simple como reemplazar el icono de Gadot con tu archivo de imagen
importado si tus activos tienen solo
un sprite por Los activos que estoy usando están
organizados en una hoja de sprites, por lo que hay múltiples
sprites en una sola textura, que no es lo que quiero dibujar Usando el menú desplegable, podemos seleccionar otros tipos de texturas, y la que se
usa para usar una hoja de sprites se llama textura de atlas Al hacer clic en la
textura del atlas para expandirla, podemos editarla
aquí mismo desde el inspector. Asignar la
hoja de sprites como atlas. Luego podremos editar la
región del atlas, que será dibujada
por la textura del atlas. Al seleccionar una región de
la hoja de sprites para usar, podemos usar la función de
corte automático para seleccionar un solo sprite o
ajuste de píxeles para hacer clic y
arrastrar una Dado que estos sprites son todos de tamaño
uniforme y espaciados, usaré esta región de 32 por
36 píxeles Al cambiar el sprite, el ancho y la altura no
cambiarán Sólo las posiciones X e Y se incrementarán por valores
uniformes Esto hace que sea mucho más
fácil animar al personaje. Antes de comprometerse a usar un conjunto de activos para
animar un personaje, podría valer la pena
editar su hoja de sprites para tener este espaciado uniforme para
ahorrar tiempo y esfuerzo Voy a mover el sprite hacia abajo
para que descanse sobre el eje X. Su posición Y es ahora la mitad de
la altura de la región de sprites. Ahora que tenemos una representación
visual precisa de nuestro personaje, podemos adaptarnos mejor a
la forma de colisión. Podemos reordenar los nodos
secundarios para dibujar la forma de colisión sobre el sprite del personaje para
facilitar las cosas Usaré forma de cápsula
y la haré lo suficientemente grande como para incluir la cabeza pero
no las orejas y el cuerpo, pero no necesariamente
los brazos, la cola o el arma. Esto se utilizará para colisionar
con el entorno, por lo que cualquier cosa fuera de
la forma de colisión se superpondrá con
las paredes, el techo o el suelo Asegúrate de que tu forma de
colisión y sprite permanezcan centrados alrededor del eje Y y se
asienten cómodamente en el eje X
como si fuera el piso Si el tamaño de tu personaje
cambia significativamente, probablemente
querrás
cambiar los valores de sus variables para cosas como velocidad de
movimiento y la altura del salto. También podemos escribir
ecuaciones matemáticas en estos campos, y el motor
determinará el resultado por nosotros. Pero voy a reordenar la forma de colisión a estar detrás del sprite Con el carácter
centrado a lo largo del eje Y, para hacer que el
personaje quede a la izquierda o a la derecha, todo lo que necesitamos hacer es
cambiar el valor de la variable flip horizontal
en el nodo Sprite two D. Cambiando al script de
caracteres, tomaremos una referencia
al nodo Sprite two D y lo almacenaremos en una variable manteniendo
presionada la tecla control o comando y
arrastrándolo al Después declararemos una
función pública llamada cara izquierda, aceptando sin parámetros
y no devolviendo ningún valor. Si bien la
intención actual es
usar solo esta función de forma privada
dentro de este guión, probablemente
puedas imaginar
que decirle a un personaje que se
enfrente a una dirección podría ser
útil en un contexto público. Para mirar a la izquierda, todo lo
que tenemos que hacer es establecer el valor de la propiedad sprites
flip H en true También podríamos escribir otra
función llamada face right, pero la función solo
estaría estableciendo el valor de esta
variable de nuevo en false. A veces es más fácil escribir nuestras funciones para
ser más flexibles. En lugar de tener tanto una función face left como face right, podemos darle a la
función face left un parámetro
que le permita hacer ambas cosas. Simplemente lo nombraré a la izquierda y le daré un valor predeterminado de true. Darle un
valor predeterminado a un parámetro lo convierte en opcional. Entonces esta función
llamada cara izquierda, se
puede llamar sin
aportar ningún argumento, y vamos a suponer que
quieren enfrentar a la izquierda. Entonces podemos establecer el valor de
flip H al valor de left. Para que el personaje se
vea bien, todo lo que tenemos que hacer es llamar a
la cara izquierda pero proporcionar falso como argumento en
lugar de llamar a una función completamente
diferente. En el proceso de física, si la
dirección de un personaje es negativa, entonces quieren enfrentar a la izquierda. Y si es positivo, entonces quieren enfrentar
no a la izquierda, que es la derecha. Si la dirección es cero, entonces permanecerán mirando la misma dirección en la que
estaban en el cuadro anterior. Para obtener una mejor visión
de mi personaje pequeño, acercaré la cámara
por un factor de cuatro y reposicionaré para que el piso
quede en la parte inferior de la pantalla O. Cuando golpeamos play, el personaje está siendo dibujado y su sprite volteado para
mirar en la dirección correcta, pero aún no están
siendo animados Me gustaría que mi
personaje fuera más rápido, así que voy a incrementar sus valores en la escena del personaje. Te veré en el siguiente video.
16. 2-2 Reproductor de animación: Hola, amigos. En este video, vamos a agregar
animaciones a nuestro personaje. Si tu personaje no tiene un nodo de reproductor de animación,
deberías agregar uno ahora. Con el nodo
del reproductor de animación seleccionado, la pestaña de animación debería
expandirse automáticamente. Si no está abierto, puede
abrirlo haciendo clic en el botón
Animación. El panel de animación está actualmente vacío ya que aún
no hay animaciones. Al hacer clic en el botón
Animación, seleccionaremos Nuevo para crear una nueva animación
y ponerle el nombre inactivo. Con una animación seleccionada, ahora
hay una línea de tiempo
medida en segundos. Si lo prefieres, puedes cambiar los segundos a
fotogramas por segundo, y la línea de tiempo
se mostrará en fotogramas en su lugar. Los fotogramas están muy
juntos, así que acercaré el zoom para mostrar fotogramas más
separados entre sí. También podemos cambiar la velocidad de
fotogramas. Pondré el mío a 12
cuadros por segundo. También ayuda a aplicar el ajuste al
cursor de la línea de tiempo con esta palanca Ahora, cuando recorremos
la línea de tiempo de animación, se ajusta automáticamente
al fotograma más cercano Desde este panel,
podemos agregar pistas a la animación haciendo clic
en el botón más. El más común es
una pista de propiedad, que nos permite editar cualquier propiedad de cualquier nodo en
el árbol de escenas a lo largo del tiempo. El nodo que queremos animar
es el nodo Sprite Ti,
específicamente, es propiedad de
textura Esto agrega una pista a la línea de tiempo de animación,
y en esta pista, podemos agregar fotogramas clave para editar la propiedad a un nuevo
valor en ese momento Al hacer clic derecho sobre la pista, podemos seleccionar Insertar clave para
agregar un fotograma clave a esta pista Por defecto, el valor de este fotograma clave será
su valor actual, que es la misma textura lo
configuramos en el video
anterior Esto es lo suficientemente bueno para archivos sprite
individuales, ya que aquí solo podemos cambiar
la textura Pero como estoy usando
una hoja de sprites, en realidad no
quiero
cambiar la textura Solo quiero cambiar la región de la textura que
se está utilizando. Hay un par
de formas de hacer esto. Una es hacer clic en la pista de propiedad y
editar su nombre de propiedad, agregando dos puntos y la
palabra región después de la textura. Esto le dice a la animación
que quiero editar la propiedad region
de la textura, no la textura misma. Volveré a restablecer la animación
para que esté vacía por ahora. Asegúrate de tener
seleccionado el nodo del reproductor de
animación en el árbol de escenas y, a
continuación, selecciona el nodo
Sprite two D. Ampliando la propiedad de
textura del atlas, podemos ver sus propiedades
en un panel anidado Al pasar el mouse sobre el nombre de la propiedad de la
región, la ventana emergente nos mostrará
el nombre de la propiedad Esto es útil para
garantizar que tienes el caso exacto y la ortografía cuando intentas acceder a
él a través del código o a través del
nombre de la pista de animación como acabamos de hacer. Pero el segundo método para agregar pistas de propiedad a una animación, que es mucho más fácil es usar el botón clave a la
derecha de la propiedad. Este botón solo estará aquí si el nodo reproductor de animación fue seleccionado
previamente
en el árbol de escenas. Una animación está abierta actualmente y luego se selecciona otro nodo en
el árbol de escenas. Al hacer clic en este botón de tecla,
se agregará un fotograma clave a la animación actual en la posición del cursor de la
línea de La primera vez que
agregamos un fotograma clave para una propiedad que
actualmente no tiene pista
en la animación, Godot nos preguntará si queremos
hacer una pista para ello Y también, si queremos agregar esta pista a la animación de
reinicio, diremos que sí a ambos. Esto agrega la pista
a la animación, además de que también agrega el primer
fotograma clave al mismo tiempo Al hacer clic en el nombre de la animación
inactiva para expandir el menú desplegable, también creó la animación de
reinicio, que es como GoDo
almacenará los valores predeterminados
de las propiedades Esto ayuda a evitar problemas con la ejecución de animaciones
en el editor y cambiar permanentemente los valores de las propiedades
sin querer Godot restablecerá todas
las propiedades a los valores predeterminados especificados
en esta animación de reinicio Para que esto sea más suave,
intente agregar siempre pistas de
propiedad a las animaciones cuando estén en
su estado predeterminado. Ahora estamos listos para iniciar el proceso de animación
real. Debe tener una pista de
textura para cambiar sprites
individuales o
una pista de región de textura para cambiar sprites
dentro de una hoja de sprites Sus activos también pueden usar diferentes hojas de sprites
para diferentes animaciones Si este es el caso, también
necesitará una pista
tanto para la textura
del atlas como para la región de textura. Todo lo que tenemos que hacer es fregar hacia adelante en la
línea de tiempo un fotograma, luego editar el valor de
la textura o la región de textura y hacer clic en el botón de tecla para agregar
otro fotograma clave y repetir Como sé que todos mis sprites son
del mismo tamaño y están espaciados uniformemente, puedo hacerlo aún más fácil
simplemente insertando nuevos fotogramas clave que
editando manualmente la propiedad X, aumentándola en 32 cada Si probamos esta animación, el motor asumirá
que queremos interponer
los valores de estas
propiedades entre fotogramas clave Dado que la velocidad de fotogramas del juego general es de
60 fotogramas por segundo, pero esta animación es de
12 fotogramas por segundo. El motor crea
cuatro fotogramas adicionales entre cada fotograma clave para
crear una transición más suave Obviamente, esto no es lo que queremos con una animación de sprites, por lo que tendremos que cambiar
el modo de actualización de esta pista de
continuo a discreto Ahora la propiedad solo
cambiará cuando la animación llegue a un fotograma clave y
cambiará el valor inmediatamente La animación es demasiado larga, por lo que tendremos que establecer
el número de fotogramas de la animación para que termine
después del último fotograma clave Esta animación
también tendrá que hacer un bucle, así que haga clic en el
botón de bucle de animación para que el icono de
bucle sea azul Si haces clic en él una vez más, se establecerá en Ping Pong, que es un
tipo diferente de bucle Para las animaciones de personajes,
generalmente queremos un bucle hacia adelante Es una buena idea
establecer también las pistas de
animación de reinicio en
discretas en caso de
que decidas
usarlo para restablecer un personaje a
través de un guión. Esta animación ociosa ya
está completa, y podemos
seguir haciendo el resto de las animaciones que necesitamos para
nuestra plataforma y personaje. Al hacer clic en el botón de
animación, podemos agregar una nueva animación
y comenzar desde cero, o podemos duplicar esta animación inactiva y
usarla como plantilla. Como sé que mis
sprites están espaciados uniformemente, solo
necesito editar
las propiedades Y de
mis fotogramas clave para cambiar de fotogramas inactivos
a fotogramas caminados Podemos copiar y pegar claves
para facilitar las cosas. Una línea que conecta dos claves significa que los valores no están
cambiando entre ellas. Al hacer la animación de
ejecución, simplemente
duplicaré
la velocidad de fotogramas. Podemos hacer clic y arrastrar las teclas para moverlas a
lo largo de la línea de tiempo. También voy a necesitar hacer animaciones de saltos
y caídas. Dependiendo de los
activos que estés usando, es posible que necesites hacer
diferentes animaciones. Por ejemplo, es posible que
necesite un arranque en
salto, salto inactivo, inactivo
o animaciones de aterrizaje. Asegúrate de saber
qué animaciones necesitan bucle y cuáles no. Ahora el personaje tiene
todas las animaciones, pero están atrapadas en
la animación ociosa. Así que tendremos que
decirle al personaje cuándo cambiar a
otras animaciones. Te veré en el siguiente video.
17. Árbol de animación 2-3: Hola, amigos. En este video, controlaremos qué
animación se está reproduciendo en el reproductor de animación
usando un árbol de animación. Si la
escena de tu personaje no tiene un nodo de árbol de animación,
deberías agregar uno ahora. El propósito del árbol de
animación es controlar al jugador de
animación, decidiendo qué animación debe
reproducirse en un momento dado. Entonces, con el nodo del árbol de animación seleccionado en el árbol de escenas
buscando en el inspector, estableceremos su propiedad
de
reproductor de animación nuestro nodo reproductor de animación. La propiedad raíz del árbol es un
recurso que se utilizará para determinar qué
animación será reproducida por el nodo del reproductor de
animación. Al hacer clic en el menú desplegable, tenemos algunas
opciones diferentes para esto, mayoría de las cuales son
más aplicables al usar tres animaciones D
o óseas, que a menudo combinan múltiples
animaciones juntas. Dado que este es un
simple sprite de dos D, usaremos una máquina de estado Al hacer clic en nuestra nueva máquina de
estado, abriremos el
panel del árbol de animación en la parte inferior de la ventana del editor con una
máquina de estado abierta para su edición. Nuestra máquina de estado actualmente tiene un nodo de inicio y un nodo final. Estos no son los mismos que
los nodos en el árbol de escenas, sino que son nodos en el
contexto de una gráfica de nodos. Podemos hacer click en el
espacio vacío para agregar más nodos. Agreguemos la
animación inactiva como nodo. Podemos hacer clic y
arrastrar estos nodos alrededor para
organizarlos como queramos. Sus posiciones dentro de
este espacio son irrelevantes. Cambiando nuestro modo de edición de seleccionar y mover nodos
para conectar nodos, podemos hacer clic y arrastrar
de un nodo a otro, creando una flecha que los
conecta en una dirección. Esta es una transición
del nodo de inicio al nodo inactivo. Entonces, cuando se inicia la
máquina de estado, pasará inmediatamente al nodo inactivo, que le dice
al reproductor de animación que reproduzca la animación inactiva. Cambiando de nuevo el modo de edición
para seleccionar y mover nodos, agreguemos las animaciones walk and
run, también. Y volviendo a
conectar nodos una vez más, crear una transición de inactivo
a caminar y caminar a correr. Cuando se inicia esta máquina de estado, pasará
inmediatamente desde el nodo de inicio al
nodo de ejecución. Por lo que queremos agregar condiciones a estas transiciones para restringir cuándo
se permite que ocurra esta transición. Seleccionando la transición
de inactivo a caminar, expanda la sección de avance. Bajo la
expresión de avance se encuentra un área de texto. Aquí podemos especificar cualquier expresión
lógica que
queramos controlar cuando se permita que se produzca esta
transición, siempre y cuando el resultado
sea un booleano, verdadero o falso En este caso, queremos
reproducir la animación de caminata si la velocidad X del personaje
es otra cosa que no sea cero. Por lo que esto acomodará
caminar tanto a la izquierda como a la derecha. Esta expresión se
verificará en el nodo que
especificamos en las propiedades
del nodo del árbol de animación,
el nodo base de
expresión avanzada. Configurando esto para que sea el nodo
raíz de la escena, el cuerpo del personaje dos nodo D, podemos hacer que la máquina de
estado de animación reaccione automáticamente a la velocidad del
personaje para cambiar la animación. Volviendo a la máquina de estados, pasando de caminar a correr, vamos a querer verificar si
el valor absoluto de la velocidad X del personaje
es mayor que la velocidad de caminata del
personaje Es posible que desee especificar
un umbral diferente, como requerir que
el valor absoluto de la velocidad X sea igual a velocidad de
carrera o mayor que el promedio de la velocidad de caminata y
carrera, etcétera Ahora necesitamos agregar una transición de
regreso a inactivo de caminar. Al crear bucles de transición entre dos o más nodos en
una máquina de estado como esta, las condiciones de
todas las transiciones no
deben ser todas ciertas
al mismo tiempo. Esto haría
imposible que la máquina estatal decida
qué estado debería
estar activo actualmente, ya que simplemente circulará entre
los estados indefinidamente Dado que la condición para
pasar de ralentí a caminar es que la velocidad X sea
cualquier otra cosa que no sea cero, entonces la transición
de caminar a ralentí debería ser si la
velocidad X es igual a cero Estas dos condiciones no pueden
ser ciertas al mismo tiempo, por lo que la máquina de estado no puede quedar atascada en bucle entre
estos dos estados Aplicando la misma lógica para la
transición de carrera a caminata, las condiciones para esta
transición deben ser lógicamente incompatibles con la transición de caminar a correr Entonces, si el valor absoluto de la velocidad X del personaje es menor o igual que la velocidad de caminar del
personaje, esto nunca será cierto al
mismo tiempo como mayor que. Cuando ejecutemos el juego, la máquina de
estado comenzará desde el nodo de inicio y se moverá a lo largo de transiciones entre
diferentes estados, representando
cada estado
una o más animaciones. En algunos casos, la máquina de estado puede hacer la transición al nodo final. En cuyo caso
dejará de funcionar. Al animar nuestro personaje, nunca
queremos que esta
máquina de estado llegue al nodo final, por lo que no hay transición que
conduzca a él Esto funciona para animar al personaje
al ralentí, caminando y corriendo a la
izquierda o a la derecha, pero también necesitamos agregar
animaciones para saltar Si tuviéramos que agregar la animación de
salto aquí, necesitaríamos agregar
transiciones de todos nuestros estados existentes a
la animación de salto, ya que el personaje puede saltar
desde cualquiera de estos estados. Esto se enredará y
desordenado y difícil de manejar, sobre todo si tu personaje tiene múltiples animaciones de
salto diferentes Lo que podemos hacer en cambio es
crear una máquina de estado anidada. Empezaremos por guardar nuestra máquina de estado actual
como recurso de proyecto. Llámalo locomoción. Después reemplace esta
máquina de estado por una nueva. En nuestra nueva máquina de estado en blanco, derecha, haga clic en el
espacio vacío y seleccione Cargar. Encuentre la máquina de
estado Locomotion y agréguela a la nueva
máquina de estado como un solo nodo, y cámbiele el nombre para que sepa que es la máquina de
estado Locomotion Después agrega una transición
de inicio a locomoción. Toda la
máquina de estado Locomotion ahora existe como un solo nodo que
podemos abrir haciendo clic en su
botón Editar con un icono de lápiz Todavía tenemos las animaciones de marcha y
ejecución inactivas en
transición como antes, pero ahora está anidada dentro de
una máquina de estado más grande Podemos regresar a la
otra máquina estatal haciendo clic en el pan rallado. En esta máquina de estado, agregaremos cualquier
animación relacionada con el salto y
las conectaremos con transiciones. Así es como se ve un bucle infinito en una máquina de estado. Queremos que el personaje cambie
de cualquier estado de locomoción para saltar si su velocidad Y
es menor que cero, es
decir, se están moviendo hacia arriba. Si su velocidad Y es
mayor o igual a cero, han alcanzado el
ápice de su salto, y voy a cambiar a
la animación de caída. Después la transición
de la caída de nuevo a la locomoción si el
personaje está en el piso Podemos llamar a la función o usar nuestra variable privada
que creamos anteriormente. Es posible que queramos saltarnos los
saltos e ir directo a caer si el personaje se
sale de una repisa Entonces agreguemos eso como
otra transición bajo la condición de
que el personaje ya no
esté en el suelo. Esto crea un conflicto en nuestra máquina estatal cuando el personaje se encuentra en estado de
locomoción y salta Su velocidad es a la vez menor que cero y no
están en el piso. Entonces, ¿qué transición debería
usar la máquina estatal? En casos como este,
podemos dar
prioridad a nuestras transiciones sobre otras bajando
su propiedad prioritaria. Si el personaje salta, su velocidad Y
es menor que cero, y no están en el suelo. Pero se le da prioridad a la transición al
salto. Entonces esa es la transición la
que se utilizará. Si el personaje
sale de una repisa, su velocidad es
mayor a cero, y no están en el suelo, por lo que no hay conflicto Nuestro
personaje de plataformas en dos D ahora está animado, pero podemos hacerlo sentir
mucho mejor
agregando más pulido Te veré en el siguiente video.
18. 2-4 efectos de sonido: Hola, amigos. En este video, vamos a agregar efectos de sonido a nuestro personaje animado. Para ello, tendremos que importar
algunos archivos de sonido
a nuestro proyecto, ordenados en una carpeta
apropiada. Incluiré algunos efectos de
sonido que puedes usar para seguir junto
con esta lección, pero recomiendo que los estudiantes
intermedios usen sus propios activos o gratuitos. Primero, me desharé
del nodo de cuerpo estático que es este rectángulo blanco ya que ya no lo
estoy usando. Comienza agregando un nodo de transmisión de audio Player two D a tu escena de personaje si aún
no tienes uno. El
reproductor de flujo de audio dos nodos D difiere de un nodo reproductor de
flujo de audio en que el volumen
del efecto de sonido variará en función de su
proximidad al oyente El
oyente predeterminado es la cámara. Podemos poblar la propiedad de
flujo de
nuestro reproductor de flujo de audio con un efecto de sonido y hacer clic en el
botón de reproducción para escucharlo Si echamos un vistazo a las animaciones de nuestro
personaje, particularmente la animación de salto, podemos agregar una
pista de reproducción de audio a la animación y seleccionar el reproductor de
flujo de audio para denodar para ser el
reproductor de esta pista Podemos entonces los efectos de
sonido de fotogramas clave para jugar como
parte de esta animación, pero esto viene con
muchas limitaciones Si el efecto de sonido
es más largo que la animación, se
acortará. Si la animación está en un ciclo,
se repetirá, y con efectos de sonido,
el jugador escuchará muchas veces mientras juega
el juego como este Es una buena idea
agregarle algo de variedad y aleatorización para que el jugador no se
canse de escucharlo Entonces, eliminemos esta pista de la animación y probemos
un método diferente. Ya que conocemos el
momento exacto en que el personaje
salta del guión, sería más fácil
reproducir el sonido de esa manera. Cambiemos el nombre del reproductor de
flujo de audio a dNodet jump y tomemos una referencia para almacenarlo en una variable
privada Cuando el personaje salta, lo
único que tenemos que hacer
es decirle que juegue. Manteniendo el efecto de sonido
fuera de la animación, se reproducirá en su
totalidad y sólo una vez. Podemos duplicar este reproductor de
flujo de audio dos nodos D para agregar más efectos de sonido, también, como uno para
un sonido de aterrizaje. Entonces en el guión, podemos tocarlo de la
misma manera que el sonido del salto, pero no tenemos una función
conveniente para cuando el personaje
aterriza en el suelo todavía. En el proceso de física, tenemos una declaración if verifica si el personaje
se ha salido de una repisa Revirtiendo esta lógica, podemos comprobar si el personaje
ha aterrizado este fotograma, si no estaban
en el piso último marco y están en el
piso este marco. Entonces llamaremos a una nueva función
privada. Vamos a llamarlo en aterrizado. Por ahora, esta función solo necesita reproducir el efecto de sonido de
aterrizaje. Estos efectos de sonido se reproducirán cuando el personaje
salte y aterrice, pero
siempre serán los mismos, lo que se volverá molesto para
el jugador después de algún tiempo. Podemos mejorar esto aleatorizando
ligeramente la escala de tono del sonido
cada vez que se reproduce Así que vamos a adjuntar un script a nuestro reproductor de flujo de audio dos dende y
nombrarlo algo así como aleatorizador de efectos de
sonido sin usar una plantilla y guardarlo
en la carpeta correspondiente Este guión necesitará
una función pública le diga que reproduzca un efecto de sonido
aleatorio, no
aceptando parámetros
y no devolviendo ningún valor El resultado final de
esto será llamar a la función de reproducción definida en el reproductor de flujo de audio
para denodar clase Pero antes de reproducir
el efecto de sonido, queremos editar el valor de
la propiedad de escala de tono. Usando la
función incorporada rand F range, podemos generar un float
aleatorio entre un
valor mínimo y máximo que especificamos. Siendo una la escala de tono
predeterminada, aleatorizaré para que esté
entre 0.5 y 1.5, que debería producir una amplia
gama de sonidos similares Podemos adjuntar este mismo script al otro reproductor de
flujo de audio a Dnode haciendo clic
y arrastrando desde la pestaña del sistema de archivos al nodo en
el árbol de escenas De vuelta en el guión del personaje, en lugar de llamar a
la función de
reproducción de audio Stream Player to D classes, llamaremos a nuestra función
aleatoria de reproducción en su lugar. Esto podría ser
suficiente para reducir la monotonía de nuestros sonidos de salto
y aterrizaje, pero los pasos se
escucharán constantemente mientras
jugamos el juego Por lo tanto, es posible que desee tener múltiples efectos de sonido
diferentes
para algo así y
que el
reproductor de audiostream elija uno al azar Duplicemos un reproductor
AudioStream dos nodos D para hacer otro
para sonidos de paso, también con el mismo
script aleatorizador aún adjunto En el script, exportaremos
una variable para contener todos
los diferentes efectos de sonido de pasos como una matriz de flujos de audio Esto se puede poblar rápidamente por grupo seleccionando todos los sonidos de
paso en la carpeta assets
y
arrastrándolos a la matriz exportada
en el inspector Entonces, al reproducir un efecto de sonido
aleatorio, comprobaremos si el tamaño de
esta matriz no es cero Si la matriz no está vacía, eso significa que debemos
establecer el valor de stream para que sea un
elemento aleatorio de esta matriz. Acceder a un miembro
de la matriz con un número de índice entero como un entero aleatorio entre cero y el tamaño de la
matriz menos uno. Esto simplemente elegirá
un sonido aleatorio de nuestra variedad de sonidos. En el caso de nuestros otros sonidos
aleatorios, ya que no están especificando
ningún valor para la matriz, su tamaño es cero, y no intentará
aleatorizar el efecto de sonido, solo ajustará su Ahora solo necesitamos
tener el efecto de sonido desencadenado por las animaciones de caminar
y correr. Al cambiar de la
vista de guión a dos vistas D, primero seleccione el nodo Árbol de
animación y
luego el
nodo Reproductor de animación para
previsualizar temporalmente las animaciones sin el árbol de animación interfiera. Ya sea con las animaciones walk o
run abiertas, podemos agregar una
pista de método de llamada a la animación y llamar a un método en los pasos reproductor de
flujo de audio para denodar Insertando una clave en la
animación en esta pista, llamaremos
al método play random. Un método en este contexto es
sinónimo de una función. Podemos pasar por
la animación para encontrar los fotogramas cuando los pies del
personaje realmente hacen contacto con el suelo y establecer los fotogramas clave para que estén
en estos fotogramas exactos. Después repite este proceso
con la otra animación. Ahora tenemos un montón de pasos
aleatorios, efectos de
sonido de
salto y aterrizaje, pero también podemos
querer nubes de polvo Te veré en el siguiente video.
19. 2-5 Animated Sprite: Hola, amigos. En este video, vamos a crear partículas de
polvo para nuestro personaje de plataformas Para eso, necesitaremos
importar más hojas de sprites. Comenzando en la escena del personaje, agregaremos un Sprite Animado a de node y le daremos el nombre de
algo así como Saltar polvo El Sprite Animated
to dende difiere de un Sprite regular a de node en que no tiene una
sola Cuenta con un recurso de marcos Sprite. Al hacer clic en el menú desplegable, podemos crear un
nuevo
recurso de marcos de Sprite para este nodo animado de dos D de
Sprite Después haz click en el
recurso para abrirlo. Esto abrirá una nueva pestaña en el panel inferior
etiquetada como marcos Sprite En esta ventana, podemos crear una o más animaciones de
fotogramas Sprite que este nodo
podrá reproducir Estas animaciones solo pueden
cambiar el Sprite mismo. No se pueden
sincronizar con audio, llamadas de
función u
otras propiedades la manera que un nodo de Animation
Player puede hacerlo. Dependiendo de los
activos que estés usando, puedes agregar sprites desde archivos
individuales o desde una sola hoja de Sprite Estoy usando Sprite Sheets, así que voy a hacer clic en los marcos del anuncio
desde el botón Sprite Sheet Navegue por el sistema de archivos para encontrar sus activos deseados. Si usa una hoja de sprites, se
le pedirá
que seleccione qué marcos de la
hoja de sprite desea usar A diferencia de una textura de atlas, estos marcos de sprites
deben estar espaciados uniformemente Selecciona el número de fotogramas en cada fila y columna
de la hoja de sprites, y se cortarán por ti A continuación, puede seleccionar cada uno de los marcos que desee
utilizar haciendo clic en ellos. El número en la esquina
de cada fotograma de sprite es el orden en el que
se agregará a la animación Si no están en
el orden correcto, puede anular la selección y
volver a seleccionar los marcos de Sprite o importarlos fuera de orden
y reordenarlos Al igual que con las animaciones de
personajes siendo un fotograma
más largo que el último fotograma, es una buena idea las animaciones de
sprites como esta tengan un
fotograma vacío al final Por lo que el último fotograma
permanecerá dibujado en pantalla durante toda
la duración de un fotograma antes de que la animación se
considere terminada. Podemos establecer la velocidad de
fotogramas de la animación. Voy a usar 12 fotogramas por segundo y si
esta animación debe o no bucle, que voy a apagar. También hay una opción para
reproducir esta animación de forma automática. Cada nodo Sprite
Toti animado puede tener solo una animación de
reproducción automática, y el nodo
reproducirá esta animación cuando el nodo se agregue
al árbol Cuando una nube de polvo es creada
por el jugador saltando, queríamos reproducir
esta animación. Así que hagamos esta
animación de reproducción automática. Podemos previsualizar
cómo
se verá la animación haciendo clic
en el botón de reproducción. Para ver mejor la animación, podemos ocultar
temporalmente el
sprite del personaje y la forma de colisión haciendo clic en el icono del ojo junto a
ellos en el árbol de escenas Al igual que el personaje,
esta animación
necesita descansar limpiamente en el
suelo del eje X. Entonces, en la sección offset
en el inspector, podemos establecer su desplazamiento Y para que sea
la mitad de su tamaño vertical. Con los activos que estoy usando, eso es 16 pixeles arriba. Esto mantiene los orígenes de los nodos a las 00 mientras se sigue dibujando
el desplazamiento de Sprite Si el color de los
sprites no es del todo correcto o quieres
ajustar su transparencia, puedes hacerlo desde la sección de elemento de
lienzo las propiedades
de nodos
en el inspector La propiedad modulate es un color con un
valor predeterminado de blanco, que tiene valores de un rojo, uno verde, uno azul
y uno Alpha Cada píxel en el sprite
tendrá su propio color
multiplicado por este
color modular antes de ser Así podemos ajustar sus valores de rojo, verde, azul o Alfa. Voy a darle a mi nube de polvo la mitad de transparencia estableciendo
su Modulate Alpha en 0.5 Podemos reordenar los sprites haciendo clic y arrastrándolos
usando los botones de flecha, eliminar marcos, agregar marcos vacíos o importar más marcos
si es necesario Una vez que estés contento con el aspecto de la animación,
recuerda mostrar el sprite del
personaje y la
forma recuerda mostrar el sprite del
personaje y la de
colusión Encenderé el bucle para fines de
demostración. Cuando ejecutamos el juego,
el polvo sigue al personaje por ahí
ya que es hijo de él. Pero lo que normalmente queremos para
algo como esto es la nube de polvo genere en una ubicación específica
y no se mueva Esta nube de polvo tendrá que ser un hermano del
personaje, no un niño Al hacer clic derecho sobre el nodo
Animated Sprite two D, podemos guardarlo como su propia escena Ponlo en una carpeta nueva
para nubes de polvo. Eliminarlo de la escena del
personaje. Entonces ábrelo para que podamos
editarlo de forma aislada. Apaguemos el bucle
de esta animación. Todavía queremos que se reproduzca de forma automática cuando se cree la nube de polvo, pero trataremos de
eso en el siguiente video Por ahora, tenemos dos nubes de
polvo más que crear. Uno para cuando el personaje aterriza y otro para
cuando camina o corre. Así podemos duplicar nuestra escena de salto de polvo existente
para facilitar las cosas. No va a marcar la diferencia, pero me gusta
asegurarme de que el nombre
del nodo raíz de mis escenas
coincida con el nombre del archivo de la escena. Entonces solo cambia los sprites por
los correctos en cada caso A Asegúrese de que todos estén correctamente desfasados para descansar limpiamente en el
piso del eje X. Ahora tenemos tres nubes de polvo
diferentes que
queremos usar con
nuestro personaje. Sólo tenemos que
instanciarlos. Te veré en el
siguiente video.
20. 2-6 Instantiar: Hola, amigos. En este video, instanciaremos
las nubes de polvo en reacción a los movimientos
de nuestro personaje animado Partiendo de la escena del juego, queremos que nuestras
nubes de polvo existan en el mundo como hermanos de
nuestro personaje, no como niños Adjuntemos un nuevo script al Nodo
de Medio Ambiente mundial. Le pondré el nombre mundo y
lo pondré en la carpeta de scripts. propósito principal de este guión por ahora
será generar nuevas escenas
como sus hijos Así que vamos a escribir una nueva
función pública llamada spawn, que acepta una escena empaquetada
como primer parámetro Yo solo lo llamaré
algo vago como SN y también una posición
donde se debe generar,
que es un vector dos Entonces esta función devolverá el nodo que crea en
caso de que queramos usarlo. Podemos convertir una escena empaquetada en un nodo llamando a su función
Instanciate. Tendremos que almacenar este nodo en una variable para
poder usarlo. Voy a llamarlo instancia. La creación de un nodo no lo
agrega al árbol de escenas. Nosotros también tenemos que hacer eso. Pero para agregar cualquier nodo
al árbol de escenas, el nodo necesitará un padre. Este
nodo de entorno mundial será el padre, por lo que lo llamaremos
add child function, dándole la instancia
como argumento. Esto agregará el nodo
al árbol de escenas, pero su posición será en el origen de la escena,
coordenadas 00. Así que queremos establecer
la posición
del nodo recién instanciado
para que sea la posición de generación Sin embargo, esto supone que el nodo recién instanciado
tiene una propiedad position, lo que no es cierto para todos los Si bien esto no
causaría un error todavía, podría ser que en el futuro, si usamos la función spawn para crear diferentes
tipos de nodos Por lo que sería una buena idea
verificar si esta instancia es un elemento canvas antes intentar acceder a su propiedad
position. Podemos hacer que el parámetro de
posición de generación sea opcional dándole un valor predeterminado
de vector dos punto cero Finalmente, podemos devolver
el nodo de instancia. Ahora necesitamos llamar a
esta función como una reacción al personaje
realizando ciertas acciones. La forma más fácil de
hacerlo es usando señales. En el
guión del personaje, podemos declarar señales en la parte superior
del guión para cada una de las tres veces que queremos generar una nube de polvo cuando el personaje ha pisado,
saltado o aterrizado Las señales se
nombran convencionalmente en tiempo pasado, para decir que el suceso
en cuestión ha ocurrido. Al igual que las funciones, las señales
pueden tener parámetros. Para generar
las nubes de polvo, necesitaremos saber la posición del
personaje y en qué dirección
están mirando, indicando si el
sprite debe voltearse En la función de salto, podemos emitir la señal saltada, pasando la posición
actual del personaje y si
el
sprite de caracteres es volteado
horizontalmente como argumentos que coinciden con los parámetros de la
señal Lo mismo se puede hacer cuando
el personaje aterriza. Para los pasos, podemos
declarar una nueva función privada. Nombrémoslo en el paso
y emitamos la señal. Si quieres, también puedes decirle
al sonido de paso que reproduzca dentro de esta función en
lugar de
incluirlo en las animaciones
como una pista separada Pero para hacer eso,
voy a necesitar una referencia
al reproductor de audio paso para denotar en la parte superior de mi guión Seleccionar el nodo
Animation Player y la animación de paseo. Podemos agregar una
pista de método de llamada a la animación, llamando a un método en
el nodo raíz de escenas. Luego inserte fotogramas clave para
llamar a la función on step durante los fotogramas cuando
los pies del personaje hacen contacto con el suelo Si activamos los
efectos de sonido a través del script, ya no
necesitamos
hacer esto desde la animación y podemos
eliminar esta pista Entonces también necesitaré repetir este proceso para
mi animación de ejecución. Cambiando a la escena del juego, podemos conectar señales a scripts para reaccionar a
ellos automáticamente. Seleccionando el carácter, cambiando la
pestaña inspector a la pestaña de nodo, podemos ver nuestra lista de señales. Ya sea
haciendo doble clic en una señal o haciendo clic derecho y
eligiendo Conectar, se abre
una nueva ventana. Desde esta ventana, podemos seleccionar el nodo al que queremos
conectar la señal. En este caso, el nodo del
entorno mundial. Después o bien ingresa el nombre
de una función a llamar como reacción a la señal o
escogiendo una de una lista. Ingresaré manualmente el nombre de una nueva función y la
nombraré spawn Jump dust Al hacer clic en Conectar se
cerrará la ventana y se mostrará el script World Environment
Node con esta función
agregada automáticamente. Esta función también
tiene un icono verde que
indica que está siendo llamado por una conexión de señal, y el nodo de caracteres en el árbol de escenas tiene un icono de señal para mostrarnos que está emitiendo una señal
con una conexión. Esta conexión de señal
también aparece en la pestaña nodo. Podemos exportar variables para contener nuestras tres escenas de nubes de
polvo diferentes, que son de tipo escena llena. Después, rellena cada una
de estas variables
con las escenas apropiadas
desde la pestaña del sistema de archivos Por ahora, vamos a llamar a
la función spawn pasando Jump dust como argumento y también a la posición
actual del personaje Godot no le gusta
cuando nombramos los parámetros de
nuestra función de la misma manera que las propiedades ya
existentes de
un nodo Pero podemos cambiar el nombre de
este parámetro a algo más específico
como la posición del personaje. Esto creará
una instancia de una nube de polvo de salto automáticamente cada vez que
el personaje El nodo Animated Sprite
two D reproducirá de forma
automática la
animación Sprite que creamos, pero no queremos que este nodo de nube de
polvo
continúe existiendo después de que termine
la animación Después de que el personaje haya
estado saltando muchas veces, el árbol de escenas
tendría un montón de Sprite
Animado dos nodos D
que no están haciendo nada Entonces tendremos
que limpiarlos. La forma de eliminar nodos
del árbol de escenas es llamar a
su función libre. Pero no queremos hacer eso
hasta después de que su
animación haya terminado, que es una señal del nodo
animado Sprite dos D. Como sabemos que el tipo de nodo de nuestras escenas de nubes de polvo es
un Sprite Animado dos D, podemos almacenarlos en
una variable privada de ese tipo y llamarlo polvo Podemos conectar señales a través del código tal
como lo hicimos a través del inspector y conectar su
señal de animación terminada a su función libre. Recuerda que al hacer referencia a una función en lugar de
llamar a una función, no
usamos paréntesis También podemos voltear la
nube de polvo horizontalmente si el sprite del personaje se
volteó cuando se omitió esta
señal Repitiendo este proceso para
las otras dos señales, podemos cambiar el tipo de nube de
polvo que se genera. A ejecutar el juego, volveremos a
la ventana Editor
y daremos clic en el
botón remoto en la pestaña de escena. Podemos ver el árbol de escenas
del juego que
actualmente se está ejecutando. Ampliando el árbol para que podamos ver los hijos del Nodo
Mundial del Medio Ambiente. Podemos ver que los
dos nodos D de Sprite
Animado están siendo creados
y destruidos a medida que saltamos, aterrizamos y caminamos El árbol de escena remoto
no actualiza todos los fotogramas, por lo que algunas nubes de polvo
pueden ser creadas y destruidas sin
que se muestren en el árbol de escena remoto. Te veré en
el siguiente video.
21. Bus de audio 2-7: Hola, amigos. En este video, agregaremos un
efecto de sonido separado para la voz del
personaje. Voy a necesitar importar
algunos archivos de audio más para los esfuerzos del personaje. Los efectos de sonido de voz difieren de otros efectos de sonido en que
solo queremos tocar uno a la vez, ya que nuestras cajas de voz solo
pueden producir un
sonido a la vez. Así que solo necesitaremos tener un nodo TD del reproductor de flujo de audio para todas las vocalizaciones
de un personaje En la escena del personaje, vamos a duplicar cualquiera de
los nodos TD del reproductor de
flujo de audio existentes para crear uno nuevo para
la voz del personaje. También es posible que desee
colocar este nodo en algún lugar alrededor del cuello
o la cabeza del personaje en lugar
de a sus pies. Aunque esto no hará
mucha diferencia notable
en mi pequeño personaje. El aleatorizador de efectos de sonido ya
no es aplicable
a este nodo, lo que podemos eliminar el script haciendo clic en el botón de script
separado Reemplazaremos esto
por un nuevo guión. Vamos a llamarlo voz.
En este script, podemos exportar cualquier número de efectos de sonido de voz
estándar, comúnmente conocidos como
esfuerzos o esfuerzos. Exportemos una variable para el sonido de esfuerzo de
salto
como un flujo de audio, que podemos poblar
en el inspector Podemos previsualizar cómo
sonará esto haciendo clic
en el recurso. Luego agregaremos una función que tocará un sonido de esfuerzo de
salto. Sin embargo, esta función
no necesitará hacer nada si el reproductor de flujo de audio de voz para denotar está actualmente ocupado
reproduciendo cualquier otro sonido Sólo si no está jugando, entonces configuraremos el stream
para Saltar esfuerzo y jugarlo. Esto evitará que
cualquier nueva solicitud de
reproducir otro sonido
de esfuerzo interrumpa
el anterior También podemos usar las
mismas técnicas que hicimos con nuestros efectos de
sonido aquí, como aleatorizar la escala de tono o tener una matriz
de flujos de audio y elegir uno al
azar cada vez Y a diferencia de los efectos de
sonido regulares, que siempre se espera
que se reproduzcan cada vez, los esfuerzos no siempre son necesarios. Por lo que también podemos agregar en una oportunidad aleatoria de que el
esfuerzo no juegue, aunque sea posible. Usando la función rand F, esto devolverá un número
aleatorio 0-1 Podemos verificar si esto es
menor que un porcentaje de probabilidad, digamos, 25%,
expresado como 0.25. Añadiendo esto a la declaración
condicional con un operador y, voz de
este personaje no debe estar ocupada tocando ningún
otro sonido y además debe pasar una probabilidad aleatoria del 25% antes de que se le
permita tocar este esfuerzo Todo lo que tenemos que hacer para
activar esto es conectar la señal de salto del personaje a las voces que tocan
la función de
esfuerzo de salto. Pero la
señal de salto del personaje proporciona dos argumentos y las voces tocan función de esfuerzo de
salto no
acepta ningún parámetro, por lo que no
se consideran compatibles. Si hacemos clic en los
métodos compatibles solo toggle, todas las funciones se mostrarán
aunque no coincidan, y podremos seleccionar la función play
Jump effort. Para evitar que esto
cause un error, ampliaremos la sección
avanzada haciendo clic en el Toggle
Avanzado. Aquí podemos enlazar nuevos argumentos o desvincular los argumentos
existentes Simplemente desvincula los dos argumentos
existentes de la señal
saltada del personaje, y ahora la señal es compatible
con la llamada a la función probarlo, escucharemos el sonido de esfuerzo
reproducido aleatoriamente con un 25% de probabilidad, y nunca se
interrumpirá. B. Otra cosa que podemos hacer
para separar las voces de otros efectos de sonido
es darles un Bus de Audio separado en
el diseño del Bus de Audio. Haga clic en el
botón Audio en la parte inferior
del editor para abrir
el diseño del Bus de Audio, que actualmente solo tiene un
solo bus, el Bus Maestro. Pero si hacemos clic en Agregar bus, podemos agregar más buses
al diseño de Audio Bus, uno para efectos de sonido y otro para voces. También es una buena idea
tener otro para la música. Esto nos permite ordenar nuestro audio en diferentes
categorías y controlar
fácilmente
toda la categoría a la vez en todo
el juego. Podemos ajustar el volumen de
todos los efectos de sonido, voces y música de forma independiente, y el volumen maestro
afectará a todos ellos. También hay muchos efectos de audio
diferentes que se pueden agregar a
cada bus si queremos. En nuestra escena de personajes, tenemos múltiples reproductores de flujo de
audio diferentes dos nodos D, y cada uno de estos necesita ser dicho a
qué Bus de Audio pertenecen, siendo el predeterminado Bus Maestro. cada uno de los efectos de sonido se
le puede decir que se reproduzca en el Bus de efectos de
sonido, mientras que el
reproductor de voz AudioStream de dos nodos D se puede decir
que reproduzca en el Bus de voz Ahora podemos ajustar el volumen de nuestros efectos de sonido
independientemente de las voces. M. M. Ahora
tenemos un carácter de plataformas de dos
D muy pulido A continuación, comenzaremos a construir entornos para movernos. Te veré en
la siguiente sección.
22. Mapa de mosaicos 3-1: Hola, amigos. En esta sección, construiremos un entorno para que
nuestro personaje se mueva
y salte. Para ello, necesitaré
importar activos para mi terreno, ordenados en una nueva carpeta
para activos de sprites de terreno Al hacer doble clic sobre el activo, podemos previsualizarlo
en el inspector. Podemos ver que este activo es una hoja de sprites al
igual que el personaje Excepto en lugar de marcos de
animación, esta hoja de sprites contiene
diferentes sprites para dibujar el terreno en función de
sus mosaicos circundantes Comenzando en la escena del juego, haremos que el
nivel actual sea un cuerpo estático para denodar su propia escena Haré una nueva carpeta
para escenas de sala. Y dependiendo del
tamaño de tu juego, es posible que también quieras
clasificar las habitaciones en regiones. Entonces haré otra
carpeta para habitaciones en la región forestal y guardaré esta habitación como algo así
como sala de inicio. Entonces abre esta nueva escena de sala. Ya no quiero que el nodo D del cuerpo estático dos sea el nodo raíz, ya que esta sala contendrá
más que solo un piso. Entonces agregaré un nodo regular dos D a esta escena cuando era niño. Después haciendo clic derecho
sobre este nodo, podemos seleccionar make scene root para reorganizar el árbol de escenas para que este nodo sea
ahora el nodo raíz Ahora el piso es
hijo del nodo raíz, y podríamos agregar
más cuerpos estáticos a este nodo para las paredes, el
techo, las plataformas y
los obstáculos para construir nuestra habitación. Voy a cambiar el nombre del nodo raíz para que sea el mismo que
el nombre de la escena. Al usar mosaicos de una hoja de sprites que tienen el
mismo tamaño y espaciados, podemos usar otro nodo
que proporciona Gadot llamado capa de mapa de teselas
para dibujarlos Agregar un
nodo de capa de mapa de teselas a la escena abre el panel de mapa de teselas en
la parte inferior del editor, pero aún no podemos hacer
nada aquí. Primero, necesitamos echar un vistazo a propiedades de nodos
de capa de mapa de teselas en el inspector. El nodo de capa de mapa de teselas no puede dibujar nada hasta
que tenga un conjunto de teselas. Al hacer clic en el menú desplegable, crearemos un nuevo conjunto de mosaicos. Luego haga clic en el conjunto de mosaicos
para expandir sus propiedades. La primera opción es la forma de las baldosas en este conjunto de azulejos. Los mosaicos que estoy usando son cuadrados, pero también hay
opciones para mosaicos isométricos, cuadrados de
medio desplazamiento y
hexágono. Estos suelen usarse para perspectivas de
arriba hacia abajo, y este juego es
un desplazador lateral, así que voy a estar usando fichas de forma
cuadrada A continuación, tenemos que establecer
el tamaño de las baldosas. Mi hoja de sprites importada tiene
el tamaño de mosaico en su nombre, 32 por 32 píxeles Ignoraremos el resto de los ajustes por ahora y cambiaremos el panel inferior del editor
de Tilemap a conjunto de mosaicos Ahora podemos agregar mosaicos al conjunto de
mosaicos que acabamos de crear. Ya sea haciendo clic en el botón
Más en la parte inferior, luego navegando por
el sistema de archivos para encontrar sus activos o haciendo clic y arrastrando los activos desde la pestaña del sistema de archivos
al área de fuentes de teselas Esto nos dará un
aviso para que el motor divida
automáticamente la
hoja de sprites en mosaicos para nosotros. Si seleccionamos yes, y si
establecemos el tamaño de mosaico correctamente, entonces los mosaicos en la
hoja de sprites se cortarán automáticamente a
ese tamaño para nosotros
y se agregarán al conjunto de mosaicos Al hacer clic en el botón de borrador, podemos hacer clic en los mosaicos para
eliminarlos del conjunto de mosaicos Al hacer clic y arrastrar, se borrarán todos los mosaicos que arrastramos Manteniendo el control o comando, luego haciendo clic y arrastrando, podremos eliminar todas las teselas
del área seleccionada alternar la goma de borrar, podemos usar los mismos controles para agregar mosaicos al conjunto de mosaicos Si desea crear
mosaicos sobredimensionados, puede hacerlo manteniendo presionada la
tecla Mayús y, a
continuación, haga clic y arrastre
sobre varias teselas. Esto tratará múltiples
mosaicos como si
siempre estuvieran destinados a ser dibujados como
un grupo más grande de mosaicos. Pero esta hoja de sprites no
tiene fichas de gran tamaño, así que borraré esto
y agregaré cada una de estas fichas al juego de
mosaicos individualmente Ahora que nuestro
conjunto de mosaicos contiene teselas, nuestra capa de mapa de teselas puede usar este conjunto de mosaicos para dibujar las teselas. Entonces cambiaremos del panel de conjunto
de teselas
al panel de mapa de teselas. Con la herramienta de pintura seleccionada, podemos seleccionar una
fuente de mosaico del conjunto de mosaicos, luego una baldosa de
la fuente de mosaico. En la vista de dos escenas D, el editor proporciona pautas
naranjas de cómo se
colocarán los mosaicos y ahora podemos pintar este azulejo donde
queramos haciendo clic. Si desea cambiar
el desplazamiento de las teselas,
puede ajustar la posición de transformación de los nodos de la
capa de tilemap posición de transformación de los nodos de la
capa Al igual que en el conjunto de mosaicos, podemos usar la palanca de borrado para borrar mosaicos
en lugar de pintarlos. La herramienta de selección
se puede utilizar para seleccionar un mosaico de la vista T D en
lugar del panel de conjunto de mosaicos Podemos dibujar mosaicos
volteados horizontalmente, verticalmente o ambos
y girarlos sentido horario o
antihorario según sea necesario También podemos agrupar varias baldosas
seleccionadas y pintarlas todas a la vez. alternar el lugar del mosaico aleatorio, esto elegirá de
los mosaicos seleccionados al azar El aumento de la dispersión dejará algunas baldosas sin pintar
mientras se arrastran También puedes dibujar líneas. Con múltiples mosaicos seleccionados, se repetirán
a lo largo de la línea. Y la herramienta rectángulo puede llenar un área completa de la capa de
mapa de teselas muy rápidamente. La herramienta de cubeta
se puede utilizar para rellenar un área cerrada vacía
de la capa de mapa de teselas. Las opciones aleatorias y de
dispersión también se aplican a las herramientas de línea destrozada
y cucharón La herramienta bucket también tiene
un conmutador contiguo, que cuando está
desactivado se puede usar para efectuar todas las teselas coincidentes en toda la capa del mapa de
teselas. Con el
nodo de capa de mapa de teselas dibujando nuestro terreno, ya no
necesitamos
el nodo
tutti de cuerpo estático y podemos
eliminarlo de la escena De vuelta a la escena del juego,
podemos ver nuestra sala de inicio. El nodo no se renombra. Todavía dice nivel actual. Si ejecutamos el juego,
el personaje no choca con el terreno
y simplemente cae por él. Ahora tenemos una capa de mapa de teselas usando un conjunto de teselas para dibujar mosaicos, pero necesitamos hacer más trabajo
para configurar nuestro conjunto de teselas. Te veré en el siguiente video.
23. 3-2 terrenos: Hola, amigos. En este video, usaremos más opciones de
conjuntos de teselas para hacer que pintar mosaicos en una capa de
mapa de teselas sea más rápido y fácil. Comenzando en la escena de la habitación, seleccione el nodo de capa de mapa de teselas y luego expanda el
conjunto de mosaicos en el inspector. Al expandir la sección de la
capa de física, actualmente está vacía, por lo que agregaremos una nueva capa de
física. No necesitamos editar ninguna de las propiedades de la capa física. Solo necesita existir. Repasaremos las capas de colisión y el enmascaramiento de colisiones
más adelante en el curso. Pero si quisieras, también
podrías agregar un material físico para
ajustar su fricción,
rugosidad, rebote o absorbencia No quiero un material de física, así que lo borraré
del menú desplegable. Con la capa física
agregada a nuestro conjunto de mosaicos, podemos abrir la
pestaña de conjunto de mosaicos en la parte inferior
del editor para aplicar esta capa de
física a nuestras teselas. Cambie de la configuración del atlas a las propiedades de
pintura haciendo
clic en este botón. Aquí podemos pintar muchas propiedades
diferentes
sobre nuestras baldosas, pero la que queremos
pintar
ahora mismo es la capa física cero. Debajo de la pintura, toda la
loseta debe
rellenarse con cuatro nodos blancos
en todas las esquinas por defecto. Si no lo es, haga clic en
los tres puntos y seleccione restablecer a la
forma predeterminada o presione la tecla Fkey Ahora podemos pintar esta forma de
colisión física en nuestras baldosas. Todos estos azulejos están diseñados para tener la
misma forma cuadrada. Pero si estás usando
diferentes activos, posible
que necesites ajustar la forma de colisión
para diferentes mosaicos. Podemos hacer clic y arrastrar
estos puntos blancos para ajustar la forma de colisión, eliminarlos o agregar más según sea necesario para crear
cualquier forma que queramos. Si necesitas una mejor
vista para ser más precisos, puedes expandir este editor
para llenar todo el panel. También hay opciones de
ajuste de rejilla disponibles. Establecer el ajuste de cuadrícula
al tamaño de píxel
le permitirá crear una colisión
perfecta de píxeles si lo desea A después de pintar
formas de colisión en las fichas, ejecutar el juego de
nuevo, tendremos al personaje colisionando
con nuestras fichas Ahora tenemos colisión,
pero dibujar terreno una baldosa a la
vez es muy tedioso Podemos usar herramientas integradas en
el editor para hacerlo más fácil. Ampliando la sección del terreno, podemos agregar un
conjunto de terrenos a este conjunto de baldosas. El conjunto de terrenos necesita un
terreno agregado a él también. Así que vamos a crear un
elemento aquí, también. Podemos nombrar el terreno como
queramos. Voy a nombrar mi bosque
y darle un color. Este color no se
dibujará en el juego solo en el editor como una
forma de configurarlo. Ayuda a elegir un
color que contrastará con los colores utilizados en la hoja de
sprites para que destaque. Usaré el rosa para
contrastar con mis baldosas verdes y
marrones del terreno. A continuación, abra el panel de conjunto de mosaicos en la parte inferior del editor. Los terrenos son una forma de
dibujar azulejos que están diseñados para conectarse entre sí como lo es esta hoja de
sprites Cambiar a propiedades de pintura, y la propiedad que queremos
pintar es la propiedad del terreno. Luego podemos seleccionar nuestro
conjunto de terrenos que acabamos de crear el
conjunto de terreno cero y el terreno en ese conjunto de terrenos,
el terreno forestal. Para pintar la
propiedad del terreno, primero, tenemos que seleccionar cada una
de las baldosas que forman parte del terreno para
que ya no estén oscuras. En esta hoja de sprites,
eso son todas ellas. Al pasar el ratón sobre una baldosa que se ha agregado
a este terreno, la baldosa se
divide en nueve cuadrados cuadrado medio
necesita ser rellenado para dibujar este azulejo como
parte de nuestro terreno. Los otros cuadrados le dicen al editor que dibuje
esta baldosa si
hay otra baldosa de terreno adyacente a ésta
en esa dirección. Comenzando con esta baldosa, esta está destinada a
ser dibujada si
no tiene otras
baldosas de terreno adyacentes a ella. Entonces solo se pinta el
cuadrado medio. El azulejo sobre el
extremo izquierdo está destinado a ser dibujado si hay otra teja de
terreno a la derecha de la misma, por lo que tendrá el cuadrado
derecho pintado. El mosaico opuesto a la derecha sigue la
misma lógica hacia la izquierda, y el mosaico medio
se dibuja si hay terreno
adyacente tanto a
la izquierda como a la derecha. Las baldosas verticales son
iguales, solo arriba y abajo. El bloque grande en la esquina superior izquierda combina estos dos, agrega esquinas, y además tiene el azulejo sólido en el medio
con todos los cuadrados pintados. Esto será suficiente para dibujar bloques de terreno de forma
convexa. abrir el panel de mapa de teselas, cambiar de mosaicos a terrenos, luego seleccionar el terreno
que acabamos de crear Con la herramienta de pintura seleccionada, podemos pintar las teselas del terreno libremente en la
capa del mapa de teselas, igual que antes. Pero ahora, si nuestras
baldosas de terreno son adyacentes a otras baldosas de terreno y
forman formas rectangulares, entonces se
actualizarán automáticamente a la
baldosa correcta del terreno. Borrar mosaicos también
actualizará los mosaicos circundantes. Esto también funciona con las herramientas de naufragio de
línea y cucharón. Si queremos crear esquinas
cóncavas, tendremos que volver
a la pintura del terreno. Al agregar cada una de las
fichas restantes al terreno, rellenaremos los cuadrados que coincidan con si debería
haber otra baldosa de terreno adyacente a esta
en esa dirección. Si estás siguiendo junto
con estos activos y no
estás seguro de qué patrón se
debe dibujar en cada mosaico, puedes pausar el
video y copiar el mío Algunos activos de teselas
proporcionarán una guía o referencia para ayudarlo con las reglas de
adyacencia para mosaicos, o simplemente puede experimentar
y ver qué se ve bien Intente dibujar algún terreno en una variedad de
formas diferentes para ver si se tiene en
cuenta cada combinación posible y
dibujar apropiadamente. Las baldosas en la parte inferior también
están pensadas para ser dibujadas con
terreno adyacente en todas las direcciones. Cada mosaico en un mapa de teselas
suele estar diseñado para
tener un patrón único. Pero si tienes varias
teselas con el mismo patrón, la herramienta terreno
elegirá una al azar con el mismo
patrón al dibujar. Podemos ajustar la probabilidad
de esta aleatoriedad
pintando otra propiedad de la lista desplegable probabilidad Simplemente ingrese una probabilidad. Usaré 0.01, que es 1% y pintaré esto sobre
las baldosas en la parte inferior. Cada vez que la herramienta de terreno dibuja una baldosa con adyacencia
en todas las direcciones, tendrá un 1%
de probabilidad de dibujar cada una de estas teselas en la parte inferior o usar la
baldosa en blanco por defecto Al pintar terreno
desde el mapa de teselas, si la distribución aleatoria de estas teselas no
se ve muy bien, puedes seguir
dibujando fácilmente sobre él. El editor de terreno
recalculará la distribución aleatoria
cada vez Ahora podemos dibujar fácilmente salas para nuestro juego usando un nodo de capa de mapa de
teselas, pero la cámara no se mueve, así que no podemos mover a nuestro
personaje muy lejos. Te veré en el siguiente video.
24. 3-3 cámaras: Hola, amigos. En este video, haremos que la cámara siga al personaje para que puedan moverse más por el entorno. En la escena del juego,
tenemos al personaje y cámara dos
nodos D como hermanos. Obviamente, si asignamos la cámara como hijo
del personaje, entonces seguirá
al jugador alrededor. Sin embargo, esta no es una
muy buena manera de
hacerlo porque la mayoría de los juegos
tendrán transiciones, escenas de corte u otras
áreas del juego que se ajusten a la vista de la cámara independientemente del personaje del
jugador En algunos juegos, el jugador tiene opción de elegir a
qué personaje quiere jugar, y ese personaje
debe estar cargado, por lo que no se puede determinar en la escena del juego que la cámara debe seguir a este personaje. Es mejor dejar la
cámara como hermano y hacer que la cámara siga al personaje
del jugador a través de un guión. Adjuntemos un guión a
nuestra cámara para denodar. Podríamos llamarlo cámara o
nombrarlo después del comportamiento, seguir al jugador o combinar
los dos, seguimiento de cámara. Podríamos exportar el personaje
del jugador como una variable como lo hicimos
con el controlador de entrada, pero
supongamos que a esta cámara se le
dirá que siga a
más de un personaje lo largo del juego y en su lugar defina una
función pública llamada follow, que acepta un sujeto
como parámetro Teóricamente, este tema
podría ser cualquier cosa siempre cuando exista en el
mundo dos D y tenga una posición Entonces le daremos un tipo
de nodo dos D en lugar del tipo más específico de cuerpo de
personaje dos D. De esa manera, se podría decir a
esta cámara que siga un cuerpo rígido o
cualquier otra cosa que queramos. Esta función no
necesita devolver ningún valor. Todo lo que realmente necesita
hacer es almacenar este tema en una variable
privada. Después anulando la función de
proceso, si esta cámara tiene un sujeto, entonces establecerá
su posición para que sea la misma que la posición
global del sujeto Dado que el sujeto puede ser
parte de una escena más grande, no
queremos usar
su posición local relativa a su padre, sino su posición global dentro del alcance de toda
la escena del juego. No estamos usando el parámetro
Delta, así que procederé
con un guión bajo Ahora necesitamos otro script
para llamar a esta función desde un nodo que tenga acceso tanto
a la cámara
como a nuestro personaje, que será el nodo del juego. Adjuntando un script
al nodo de juego, le
pondremos a este
el administrador del juego, y lo pondré en una
nueva carpeta de scripts para scripts de manager. Será responsabilidad del manager del juego gestionar cuando
el jugador esté jugando
el juego o en una escena de corte o transitando
entre escenas Por ahora, cuando el manager del
juego esté listo anulando
la función ready, le
diremos a la cámara que siga al jugador y active
el manejador de entrada Para ello, tendremos que almacenar cada uno de estos nodos
en variables. Dado que la jerarquía
de la escena del juego es bastante compleja en
comparación con otras escenas, posible
que necesitemos reorganizar los nodos, cambiando su parentesco
en el proceso Cuando eso suceda,
la ruta del nodo en nuestro script ya no
será válida provocando errores. Podemos evitarlo haciendo
clic derecho sobre los nodos nuestro árbol de escenas y seleccionando el
acceso como nombre único. Esto agrega un signo de porcentaje a la derecha del
nodo en el árbol de escenas. Esto nos permite reemplazar
la ruta del
nodo anotado del signo de dólar con el nombre único anotado del
signo de porcentaje Si el nodo tiene un
nombre único ya asignado, se
aplicará automáticamente al mantener control o comando y
arrastrarlo al script Ahora que tenemos todas
estas referencias de nodo, cuando el manager del juego esté listo, podemos decirle a la cámara que siga al personaje
del jugador y
habilite el controlador de entrada Aún no hemos escrito
una función enable para el controlador de entrada, así que cambiemos a
ese script y escribamos creación de una
variable privada está habilitada como booleana, que por defecto será false, y una función de habilitación pública que
podemos establecer está habilitada Entonces antes de manejar cualquier
entrada del reproductor, comprobaremos si el controlador de entrada está habilitado y regresaremos si
no lo es saldrá de la función si
está habilitado es falso, evitando que se ejecute alguno de los códigos
restantes También necesitaremos una función de
desactivación que establezca la
variable is enabled de nuevo en false. Esto puede parecer excesivo, ya que podríamos simplemente hacer pública la variable
is enabled. Pero usando esta estructura
encapsulada, podemos hacer otra lógica
dentro de estas funciones. Como cuando el
controlador de entrada está deshabilitado, dígale al personaje que
deje de moverse estableciendo la dirección a cero y
también dígale que camine Al habilitar el manejador de entrada, dado que el movimiento se está
comprobando en proceso, ya se
detectará automáticamente Pero si el jugador
comenzó a mantener presionado el botón Ejecutar antes de que se habilitara el controlador de entrada, la entrada habrá
sido ignorada, pero el jugador seguirá
esperando que su personaje corra Podemos verificar el estado
del botón de ejecución al habilitar el controlador de entrada y decirle
al personaje que se ejecute en consecuencia Si usamos la
función de entrada para el movimiento, podríamos verificar el singleton de
entrada para el estado del movimiento a la izquierda, eje
derecho, y decirle al
personaje que se mueva aquí también. Volviendo a la escena del juego, ya que la posición del personaje también
está en el origen, esto es lo que
dibujará la cámara cuando comience el juego. Este no es un muy buen encuadre del personaje o de la habitación Por lo general, el jugador
necesita ver más de lo que está por encima de ellos o
lo que le espera. Podemos darle a la
cámara un
desplazamiento de posición para moverla hacia arriba a lo largo del eje y y hacia la derecha a lo largo del
eje X para lograrlo. Lo pondré 64 pixeles arriba y a la derecha y también
cambiaré mi Zoom a dos. Entonces, cuando se establece la
posición de la cámara para que coincida con la
posición del personaje, cada fotograma, se compensará en
esta cantidad después de eso, dando al jugador una vista ligeramente hacia arriba en la
derecha del personaje. Ahora tenemos nuestra cámara
siguiendo al personaje por ahí, pero la cámara solo
mira a la derecha. Te veré en el siguiente video.
25. 3-4 Un vistazo al futuro: Hola, amigos. Y
este video permitirá que la cámara mire por delante del personaje ya sea
a la izquierda o a la derecha. Comenzando en el guión de
caracteres, podemos
facilitarnos las cosas proporcionando nombres de
clase para algunos de nuestros scripts usando el nombre de clase de palabra clave en
la parte superior del script. Nombremos a esta clase algo más genérico como carácter. Esto permitirá a Godot completar de
forma automática los
nombres de las variables y funciones al acceder a los miembros de esta clase
en otros scripts Al igual que usamos
señales para reaccionar
a las acciones del personaje
para producir nubes de polvo, necesitaremos hacer
otra señal para cuando el personaje cambie la
dirección a la que se enfrenta. Declarando una señal llamada dirección
cambiada, tendremos
que pasar a qué dirección se
enfrenta
el personaje ahora como parámetro Añadiendo otra variable a
la sección de locomoción, necesitaremos saber qué dirección se encuentra el
personaje actualmente para saber si
ha cambiado su dirección de orientación Dado que una variable booleana
naturalmente por defecto es false,
voy a nombrar la variable
está orientada hacia la izquierda, lo que cuando false implica
que están En la función cara izquierda, podemos emitir nuestra nueva señal y pasar el valor de
dirección como argumento. Oh, abajo en el proceso de física, al decirle
al personaje que mire la dirección, esto
sucederá cada vez el jugador dé
entrada a cada fotograma. No queremos emitir
esta señal en todos los fotogramas, solo en los fotogramas cuando
cambian de dirección. Entonces agregaremos la condición de
que el personaje esté orientado hacia la izquierda y la dirección
sea mayor que cero, o el personaje no esté orientado hacia izquierda y la dirección
sea menor que cero. Ahora estas funciones
solo se llamarán durante el fotograma cuando el personaje realmente cambie su dirección de
orientación, lo que emitirá la señal
para que reaccionemos ante ella. Cambiando al script de
la cámara, necesitaremos una función
que coincida con la firma de la señal que acabamos de
crear para conectarla. Vamos a llamarlo sobre el tema
cambió de dirección, ya que el personaje
será el sujeto, aceptando la dirección al que se
enfrenta
el personaje como flotador y no
devolviendo ningún valor. Lo que queremos hacer
es tener el desplazamiento X de la cámara para que coincida con
el signo de dirección. Así que tendremos que
almacenar el valor de offset en otra
variable inalterado nombraremos
offset predeterminado y lo
estableceremos el valor de offset
usando una etiqueta ready. Ahora podemos
editar con seguridad el valor de offset sin olvidar
cuál era el valor original. H. Cuando el sujeto
cambie de dirección, estableceremos el valor
de offset para que sea el desplazamiento predeterminado multiplicado
por el signo de dirección. Entonces, si la dirección es positiva, entonces el desplazamiento de la cámara también
será positivo, y de igual manera para negativo. Para conectar esta señal al decirle a la cámara
que siga a un sujeto, si el sujeto no es nulo y el sujeto
es un personaje, la clase que acabamos de nombrar, entonces podemos acceder de manera segura a la señal de
dirección cambiada del personaje y conectarla a nuestra función. Un Godot no reconocerá los nuevos nombres de clase hasta después de que hayas
guardado tus scripts Pero si llamamos a esta función de
seguimiento sobre el mismo tema
más de una vez por cualquier motivo, esto provocará un error ya que la señal ya está conectada. Primero, comprobemos si el sujeto que
se le dice a la cámara siga es el mismo el sujeto al que
ya están siguiendo. En este caso,
no tenemos que hacer nada y podemos simplemente
devolverlo a esta función. Ahora sabemos que el tema es algo distinto
al sujeto actual. Comprobemos si el sujeto
actual
no es nulo y si
es un carácter. Si ambos son verdaderos, entonces también deberíamos verificar si la señal de
dirección cambiada del personaje se ha conectado a la función de dirección
cambiada en sujeto. Y si esto es cierto,
desconectaremos la señal, ya que la cámara ya no
sigue al sujeto y
no necesita reaccionar ante él. ejecutar el juego, esto
colocará a la cámara
por delante del personaje, pero sucederá
instantáneamente, lo que es bastante discortante para el jugador. Lo que sería
mejor es ajustar
el valor de offset
gradualmente a lo largo del tiempo, que es algo que podemos
hacer fácilmente usando una preadolescentes, abreviatura de entre medias Entonces declararemos una nueva variable, llamaremos algo así como
mirar hacia adelante tween A continuación, cuando el carácter
cambia de dirección, asignando el valor de esta
variable para crear tween Crear tween es una función
de la clase de nodo, por lo que cualquier nodo puede usarlo. Cuando se crea la preadolescentes, accederemos a su función de
propiedad Tween Esto acepta un objeto
como primer argumento, que es este nodo en sí. Podemos especificar esto
con la palabra clave self. Entonces la propiedad que queremos
interponer como cadena, que es la propiedad offset, específicamente el componente X, que podemos especificar
con los dos puntos El siguiente argumento
es el valor final, que es el desplazamiento X predeterminado multiplicado por el signo de dirección que calculamos anteriormente. Y por último, la duración
de la preadolescentes en segundos. Por ahora,
lo pondré a 1 segundo. Dado que esta preadolescentes
tardará 1 segundo, pero es muy posible
que el personaje cambie de dirección varias
veces durante ese 1 segundo, esto crearía múltiples
preadolescentes todos
tratando de editar el valor de
offset al mismo tiempo Entonces antes de crear la preadolescentes, debemos verificar si
ya existe primero, y si la mata De esta manera, no puede
existir más de
una de estas preadolescentes a la vez y estar
tratando de editar el desplazamiento X. Ejecutando esto ahora, el desplazamiento X de la
cámara se está tweening para mirar por delante
del personaje más de 1 segundo, pero sigue siendo un poco discortante. Podemos ajustar cómo
ocurre esta preadolescentes exportando
algunas variables más Primero, vamos a exportar una
duración para esta preadolescentes como flotante y darle un valor
por defecto de 1 segundo Después sustituimos el de nuestra
función con esta variable. A continuación, agregaremos un tipo de transición y un
tipo de flexibilización. Juntas, estas tres variables nos
permitirán crear
una amplia variedad de diferentes preadolescentes ajustando la
rapidez con la que cambia el valor al principio y al final de
la preadolescentes. Dado que create tween
devuelve una tween, podemos acceder a su función set
trans y pasar nuestro tipo de transición como
argumento en la misma línea La función set trans
también devuelve la tween, por lo que podemos continuar
esta línea y llamar a la función set Es
inmediatamente después de eso, también. Pasando nuestra variable Es
como argumento. Todo esto
devolverá la preadolescentes con el
conjunto de tipos de transición y facilidad y asignará el
resultado a la variable Desde la escena del juego, seleccionando
el nodo tutti de la cámara, echando un vistazo a sus
propiedades en el inspector, podemos editar los valores
de estas variables con los tipos de transición y flexibilización proporcionando listas
desplegables convenientes También podemos hacer que la duración
de la preadolescentes sea más corta o más larga Voy a hacer que el mío use un quad in
out tween más de 2 segundos. Intente experimentar con
las diferentes opciones para tener una idea de cómo funcionan El tipo de transición determina qué fórmula matemática
se está utilizando para alterar
el comportamiento, mientras que el tipo de flexibilización
decide cómo
afectará a la primera mitad o
segunda mitad de la preadolescentes. Ahora tenemos la cámara desplazando
suavemente hacia la izquierda o hacia derecha para mostrar lo que está por delante de la dirección hacia la que se enfrenta el
personaje, pero a veces el jugador puede querer mirar hacia
arriba y hacia abajo, también. Te veré en el siguiente video.
26. 3-5 Mira hacia arriba: Hola, amigos. En este video, permitiremos que el jugador le diga
al personaje que
mire hacia arriba y hacia abajo. Primero, necesitaremos agregar
más eventos de entrada al mapa de entrada en
la configuración del proyecto para
buscar hacia arriba y hacia abajo. Voy a usar las teclas de flecha arriba y abajo. Los botones
direccionales de arriba y abajo, y el stick derecho
se inclinaron hacia arriba y hacia abajo. Entonces en el guión del jugador, a diferencia de la dirección de movimiento, que sólo está siendo
utilizada por el personaje, la dirección de mirada será utilizada tanto
por el personaje
como por la cámara, lo que significa que necesitaremos una
referencia a la cámara. Vale la pena almacenar la dirección de la mirada
en una variable, por lo que solo necesitamos
calcularla una vez por fotograma. Entonces en la función process, obtenemos su valor
del singleton de entrada, la misma manera que lo hicimos con
la dirección del movimiento usando la función get axis, cambiando los nombres de
las acciones de entrada Recuerda que como
arriba es negativo, será el primer argumento. Entonces podemos enviar
esta dirección de mirada tanto
al personaje como
a la cámara. Para la cámara, voy a
usar una llamada de función. Pero para el personaje,
voy a dislocar
el valor de una variable pública Para que el nombre de
la variable de dirección de la clase de carácter sea
un poco más
claro, podría ser inteligente
cambiarle el nombre para mover la dirección. Como esta función no
existe en el script de la cámara, comentaré por ahora para evitar errores hasta que esté
listo para escribirla. Sobre en el guión de caracteres, podemos abrir el diálogo de reemplazo con Control o Comando R y reemplazar dirección
con dirección de movimiento que quede más claro para qué
se utilizará. A continuación, agregue una nueva variable pública
para la dirección de la mirada. La variable de dirección L no necesita ser utilizada en
ninguna parte del script. Sólo será leída
por el Árbol de Animación. Desde la escena de los personajes, seleccionando el Reproductor de Animación, necesitaré crear animaciones LU
y L abajo. Duplicaré mi animación ociosa
para facilitar las cosas. Entonces solo edita los valores Y de mis fotogramas clave para dibujar el personaje mirando hacia
arriba o hacia abajo en consecuencia. Después en la máquina de estado
Árbol de Animación
editando la máquina de
estado Locomotion, puedo agregar las animaciones de mirar hacia arriba y
mirar hacia abajo Transición a ellos basada en el valor de la dirección de la mirada Y asegurándose de que su
velocidad X siga siendo cero, lo contrario, deberían hacer la
transición para caminar en su lugar. Y volver al ralentí en el caso que la dirección de la mirada
sea igual a cero. O si han empezado a caminar, esto tendrá al
personaje animando para mirar hacia arriba o hacia abajo a medida que presionamos las direcciones
arriba y abajo, pero la cámara aún no se mueve. En la escena del juego, intenta alterar
el desplazamiento Y de la cámara y decide hasta dónde te gustaría que se moviera
la cámara cuando el
personaje mira hacia arriba o hacia abajo. Usaré 128 píxeles y volveré a
restablecer al
valor predeterminado de 64 negativo. Volviendo al guión del reproductor, descomentaré la función de
cámara ahora, luego cambiaré al guión de la cámara para declarar esta función Aceptaré una dirección como
flotador y no devolveré ningún valor. El cuerpo de esta función
será casi idéntico a la función de
dirección en sujeto cambiado. Todo lo que tenemos que hacer es sustituir todas las instancias de
una cabeza con arriba abajo. Después declararlas
como nuevas variables. También necesitaremos otra variable
exportada para la distancia máxima de mirada que
decidimos anteriormente,
que usaremos en lugar
del desplazamiento predeterminado, y el desplazamiento X será compensado Y. Sin embargo, cuando
soltamos las flechas arriba o abajo, queremos que la cámara vuelva al valor de desplazamiento predeterminado, no a cero. Entonces esto requerirá un
poco de lógica extra. Otra forma de agregar sentencias if
simples a tus scripts es usar
una operación ternaria, que en GDScript usa las mismas palabras clave if que una sentencia if
normal, comenzando por el caso predeterminado, que es el valor que
ya hemos calculado, pero solo si direction
no es cero, seguido Entonces, si la dirección es cero, entonces queremos usar nuestro desplazamiento Y
predeterminado en su lugar. Esto funciona, pero en la mayoría de los juegos
que tienen esta mecánica, el jugador tiene que mantener presionado el botón durante algún tiempo
antes de que la cámara se mueva. Podemos lograr esto agregando un nodo temporizador al nodo jugador. Vamos a llamarlo. Mira, sostén. Podemos ajustar el
tiempo de espera del inspector, pero 1 segundo está bien, y el temporizador
tendrá que ser un disparo único. Conectando la
señal de tiempo de espera de este temporizador al guión del jugador, Esto es cuando el
guión de los jugadores le dirá la cámara que comience a mirar
hacia la dirección En la parte superior del guión, tendremos que tomar una referencia
al antiguo nodo temporizador, y también necesitaremos
un booleano para que
sepamos si el jugador está buscando
actualmente o En la función de proceso, después de obtener el valor de dirección de
la
mirada de la entrada Singleton, si el jugador
ya está mirando, entonces también si la
dirección de la mirada es cero, reiniciaremos la
cámara llamando a su función look y pasando
cero como argumento Entonces set está buscando a false. La razón por la que no usé una declaración
y es
para que pueda usar un else si aquí y ahora asumir
que está buscando es falso. Entonces también verifica si la
dirección de la mirada no es cero. En este escenario, donde el
jugador aún no está buscando, pero está dando entrada de dirección de
mirada, entonces si
se detiene el temporizador de espera ,
tendremos que iniciarlo. Añadiendo una
más si el jugador no está mirando y no está dando
ninguna entrada de dirección de mirada, entonces también si el
temporizador de retención de mirada no se detiene, eso significa que tenemos que
detenerlo y cancelar el look. Añadiendo declaraciones impresas
para todos estos, podemos confirmar que
cada uno es llamado solo una vez cuando
sea apropiado. También tendremos que establecer la variable
is looking true cuando el temporizador de
espera de mirada se
agota y la cámara
comience a interconectarse. Ejecutando el juego, tocando las flechas arriba o abajo
sin sostenerlo, el temporizador de espera se inicia pero se detiene y la
cámara no se mueve, pero el personaje sigue
animando mirando hacia arriba y hacia abajo mantener presionadas las teclas
arriba o abajo, el temporizador se agota después 1 segundo y le dice a la
cámara que mire hacia arriba o hacia abajo. Al soltar las teclas arriba o abajo, la cámara se restablece de nuevo a
su posición de desplazamiento predeterminada. Voy a comentar estas declaraciones
impresas y ajustar mi configuración de pregeneración
en el inspector para cuadriplicar más de
medio segundo El jugador ahora puede mantener presionadas las direcciones arriba y abajo
para mirar hacia arriba y hacia abajo, pero es posible que queramos restringir hasta
dónde puede moverse la cámara para evitar mostrar contenido
fuera de la sala actual. Te veré en el siguiente video.
27. 3-6 Límites: Hola, amigos. En este video, restringiremos la cámara para que se mantenga dentro
de los límites del entorno. Comenzando en la escena de la sala, podemos cambiar el
nodo raíz para que sea un nodo D del área dos en lugar de
solo un nodo D normal de dos. Esto es similar
a un cuerpo de física en que tiene forma de
colisión, pero no tiene
masa ni reacciona a las fuerzas. En cambio, se puede pensar en ello como un detector de movimiento o calor. Representa una región
del espacio y
emitirá una señal cuando
los cuerpos físicos entren o salgan de ella. Esto será útil más adelante para detectar cuando el
personaje jugador entra en la sala. Pero por ahora, todo lo que necesitamos
saber es qué forma es. Al agregar una forma de colisión
para denotar como un niño, podemos darle un recurso de forma Usaremos forma de rectángulo. Luego podemos movernos y cambiar
el tamaño de la forma para crear límites de
habitación A adjuntando un script al nodo raíz de la escena, lo
llamaremos Room y
lo ordenaremos en la carpeta de scripts. Necesitaremos una referencia a la forma de
colisión para dende. Voy a renombrarlo para dar forma a nodo. Entonces necesitamos funciones
que puedan ser utilizadas para recuperar la esquina
superior izquierda
y la esquina inferior derecha
de este rectángulo para que devuelvan dos coordenadas
vectoriales. Podemos acceder a la forma de
colisión dos denodes shape propiedad
por su nombre Entonces también queremos
llamar a una función sobre el recurso shape, Get wrecked La función G wrecked
devuelve un naufragio dos, que si abrimos la
documentación para esta clase, podemos ver que tiene una
posición y un final La posición es la esquina
superior izquierda y el final es la esquina
inferior derecha. Pero estos son relativos
a la posición de los nodos. Necesitaremos estas
coordenadas en el espacio global, por lo que las agregaremos a la posición global de
los nodos. La posición global de un nodo será relativa al origen
del juego, no a la posición de los nodos padre. Entonces podemos devolver estos valores. Ahora, todo lo que tenemos que hacer es decirle la cámara que se mantenga
dentro de estos límites. De la
escena del manager del juego, por ahora, solo
tomaremos una referencia a la sala de inicio y la almacenaremos en una variable llamada current room. Cuando la escena del juego esté lista, podemos obtener la esquina superior
izquierda y la esquina inferior derecha
de la sala actual, y las pasaremos
a la cámara
llamando a una función que
establece sus límites. Cambiando al script de
la cámara, declararemos esta
función aceptando los dos vectores dos recuperados
de la habitación actual
y no devolviendo ningún valor En esta función,
descubriremos qué tan cerca puede llegar la cámara a las esquinas superior izquierda e inferior
derecha de esta habitación sin ver
nada más allá de esos puntos. Para ello, necesitaremos crear estas variables como vectores de dos,
y nos ayudará
tener un booleano para saber si la cámara
está enlazada actualmente o no También necesitaremos conocer
el tamaño de la Viewport, que podemos recuperar automáticamente con la
función Get Viewport, luego acceder a su propiedad size y almacenarla en una variable
usando la etiqueta on ready La función Get Viewport se declara en la clase node
y devuelve un vector dos, coincidiendo con el tamaño de la ventana que establecemos en la configuración del proyecto Este tamaño de la ventana gráfica
no es necesariamente el mismo que la cantidad de píxeles que
dibujará la cámara, ya que la cámara
puede acercar o alejar. Tendremos que dividir
el tamaño de la ventana gráfica por el Zoom de la cámara para obtener el tamaño real de píxeles del
área que la cámara puede ver Pero un vector no se puede dividir por otro vector.
Tenemos que usar un flotador. Usaré solo el Zoom X y asumiré que las cámaras Zoom siempre
serán uniformes. Pero esto todavía no es lo suficientemente
bueno porque la posición de la cámara está
en el centro de su visión. La posición más cercana
que la cámara pueda posicionarse a
la esquina superior izquierda o inferior derecha de la habitación
sin dibujar más allá estos puntos
será en realidad la mitad del tamaño. Dividiendo este valor por dos, cambiaré el nombre de la variable
para reflejar su nuevo valor. Al establecer los límites, la
posición superior izquierda será la esquina superior izquierda de la habitación
más la mitad del tamaño de
la vista de la cámara. Mientras que la posición inferior derecha
más será la esquina inferior derecha de la habitación menos la mitad del
tamaño de la vista de la cámara, y podemos establecer el valor de is
bound en true. H. En la función de proceso, después de decirle a la cámara que
coincida con la posición del sujeto, entonces
aplicaremos estas restricciones de
límite usando la función Abrazadera F. La función clamp F toma un parámetro flotante como
la posición de la cámara, luego un valor mínimo
y un valor máximo, luego devuelve un valor que
permanecerá dentro de esos límites. Luego sobrescribiremos la posición de la
cámara con el resultado sujetado y
repetiremos esto para la Y. Pero como nuestra cámara
también tiene un desplazamiento, su posición no es una representación
lo suficientemente precisa del centro
de su También estamos editando el valor del offset en momentos impredecibles. Entonces no es algo que
podamos factorizar en los cálculos de la parte superior izquierda e inferior
derecha, ya que el valor
probablemente cambiará a menudo. Así que tendremos que
factorizar el desplazamiento en las funciones de sujeción
restándolo de la parte superior izquierda e
inferior derecha cada vez Si quieres que tu
cámara se acerque y apague durante el juego sin dejar de
respetar estos límites, también necesitarás
factorizarlos en los cálculos dentro de la función de
proceso Esto funciona, pero
los preadolescentes de cámara parecen luchar contra
los límites de los límites La preadolescentes mueve el
desplazamiento de la cámara ligeramente fuera de
los límites El fotograma se dibuja, luego
el siguiente bucle de proceso empuja la
posición de
la cámara lejos del límite
para compensar el nuevo desplazamiento. Esto sucede repetidamente
hasta que la preadolescentes se detiene. Esto se debe a que las preadolescentes
se ejecutan después del proceso al final del fotograma justo antes de dibujar
todo en pantalla Para solucionar esto, podemos
cambiar nuestras preadolescentes de usar la propiedad tween al método tween en
su lugar Al llamar a un método,
podemos aplicar los límites de límite
al
mismo tiempo que estamos cambiando
el valor de offset. Los argumentos para el método tween, en lugar de una referencia
a un objeto, necesita un método invocable Diremos set Y offset. Seguido
del valor inicial, que es el valor actual
del desplazamiento Y de la cámara, entonces los
argumentos restantes son los mismos. Dos es el
valor final al final de la preadolescentes y la
duración de la preadolescentes. Podemos hacer lo mismo con
la mirada hacia delante entre dos. Sólo tenemos que escribir este
conjunto de función de desplazamiento X, aceptando un solo
parámetro que coincida con el tipo de los argumentos
from y dos. Después de cambiar el
valor del desplazamiento X, podemos imponer el
límite límite en la posición de la cámara
para compensar inmediatamente y hacer lo
mismo para el desplazamiento y. Ejecutando esto ahora,
los preadolescentes compensados no alcanzarán
su punto máximo más allá de
los límites de la habitación Ahora tenemos la cámara limitada para mostrar solo lo que hay
en la sala actual, pero el ambiente
se ve muy plano. Te veré en el
siguiente video.
28. 3-7 Parallax: Hola, amigos. En este video, arreglaremos el desplazamiento de
paralaje
del primer plano y fondo
con Comenzando en la escena de la
segunda sala, voy a copiar todos mis colores de
modulación
de los nodos Parallax Tut
a sus nodos hijos Entonces puedo unparent a
los sprites y eliminar los nodos Parallax Tut mientras sigo manteniendo Luego adjuntaré un nuevo script
a cualquiera de estos sprites, lo
nombraré Parallax y
lo pondré en la carpeta de scripts Este mismo script se puede adjuntar a todos los sprites
que quiero a Parallax Para crear un comportamiento personalizado, ayuda tomar
algún tiempo para
pensar qué es lo que estás
tratando de lograr, qué referencias de nodo y otra información se
requerirá. Tengo varios sprites
diferentes. Quiero moverme en
diferentes cantidades relación con la
posición de la cámara, y sé que la cámara está actualmente encuadernada dentro de
los límites de esta sala. Agregaré temporalmente una cámara
dos nodos D a la escena y acercaré por un factor de dos para fingir que esta
es la escena del juego. Si la cámara está exactamente en
el centro de esta habitación, quería dibujar todo
exactamente como está. Pero cuando la cámara se
aleja del centro, moveré todos los sprites
de
paralaje una cantidad relativa con fondo moviéndose
menos que
la cámara y los elementos primer plano moviéndose
en
la dirección Para ello, cada sprite
necesitará conocer la posición de la
cámara relativa al centro de la habitación, así
como su propia posición
original En el script Parallax, declararé una variable
exportada para contener el factor
por el cual el sprite se mueve con relación a la cámara y le
nombraré escala de desplazamiento
como vector dos Esto funcionará de manera similar a la variable de escala de desplazamiento
en el nodo Parallax two D. Cuando esta sala se carga
en el árbol de escenas, podemos usar la
etiqueta on ready para obtener su posición y almacenarla en una variable
como la posición original. Obtener una referencia a
la cámara actual es fácil gracias a la función nodo
G Viewport Devolviendo el Viewport en el que existe
este nodo, que también tiene la función Get camera to D para obtener la cámara También podemos almacenar esto en
una variable, usando la etiqueta on ready. Anulando la función de proceso, no
necesitamos Delta y
podemos marcarla como no utilizada Simplemente configuraré la
posición del sprite para que sea su posición original más la distancia de la
cámara desde el punto medio de la habitación multiplicada
por la escala
de desplazamiento Ahora la cámara solo necesita una función
pública que nos pueda decir su posición relativa al punto medio de la
sala actual Cambiando al guión de
la cámara, escribiré esta función,
desplazada desde el punto medio, que será la posición de la
cámara más su desplazamiento menos el punto medio
de la habitación actual Declarando esto como
una nueva variable, puedo calcularla
como el promedio de
la esquina superior izquierda e
inferior derecha de la habitación al
aceptarlas desde la función de
límites establecidos Podríamos modificar esta función
para aceptar el punto medio y tamaño del rectángulo en
lugar de sus esquinas superior izquierda e
inferior derecha, pero de todos modos no hará
ninguna diferencia en eficiencia,
así que no me molestaré Ahora podemos establecer la escala de
desplazamiento para cada uno de los sprites de paralaje para
darles a cada uno una
distancia diferente de la cámara Todavía solo usaré paralaje
horizontal, dando a mis colinas una escala
de desplazamiento de un tercio a lo largo del eje X, y las colinas más
atrás dos tercios Para el primer plano,
necesitarán
moverse en
dirección opuesta a la de la cámara, tendrán una escala de desplazamiento de un tercio
negativo y dos tercios
negativos Esto será suficiente
para crear la ilusión de
profundidad para nuestras habitaciones. ejecutar el juego, podemos
pasar a la segunda sala y ver que el efecto de paralaje se ve idéntico al de
la sala de inicio, a pesar de ser realizado
por un guión muy sencillo Dado que los sprites de primer plano se mueven en la
dirección opuesta a la cámara, necesitarán repetir y
envolver su posición para crear un bucle infinito, o simplemente podemos hacer que el
sprite sea más grande que la Hacer mis arbustos 1.5 veces más largos que la habitación y la
hierba duplicar la longitud de la habitación dejará
suficiente extra a
ambos lados para que los bordes nunca
lleguen a la vista de la cámara A sería
posible utilizar el nodo
Parallax two D para dibujar el primer plano y el
fondo usando Viewport
separado
y fondo usando Viewport
separado dibujarlos en
diferentes capas de lienzo
o intentar dibujar siempre habitación actual en
el origen de la escena del
juego Estas soluciones llevarían
a otras complicaciones y limitaciones en el
futuro
a la hora de dibujar el
mapa del juego, por ejemplo. Me parece que escribir
soluciones personalizadas como esta a veces es más fácil que
usar los nodos proporcionados. La solución también mantiene todo para una
habitación en un solo lugar, lo
que simplifica
el diseño y construcción de las habitaciones de
una manera más intuitiva. Ya no necesito esta
cámara nodo Tuti, así que la eliminaré. Eliminando las nubes
del nodo Parallax touti, podemos alterar el script
Parallax, también auto scroll las nubes también Ampliando el naufragio de la región, todo lo que necesitamos hacer para mover
las nubes hacia la derecha es disminuir el valor de
exposición con Adjuntando el
script Parallax a este nodo, primero
podemos establecer
su escala de desplazamiento uno
para que coincida con
el movimiento de la cámara Esto hará que las nubes aparezcan una distancia infinita
en comparación con las colinas Parallax Al exportar otro vector dos
para la velocidad de desplazamiento automático, necesitaremos usar Delta en la función de proceso ahora y
podemos eliminar el guión bajo Accediendo a la
propiedad region rect y su posición, comenzando con la
X, restaremos el valor AutoScrollX Entonces esto hará que la
velocidad de desplazamiento automático píxeles por segundo. Después asigne el resultado a
la región recs X posición. Pero si tuviéramos que ejecutar esto
por mucho tiempo, este número se
acercaría a los límites de un número de punto flotante
y puede causar problemas. El valor de la posición X
coincide con el tamaño, el resultado es en realidad el mismo. Sería mejor restablecer la posición X de nuevo a
cero cuando esto suceda, que podamos recorrer esto por una cantidad infinita de tiempo. Usando la función AP F, podemos proporcionar un valor mínimo
y máximo para limitarlo a estar solo entre
cero y el tamaño rec. Esta función
devolverá un resultado que debe estar entre
estos dos valores, pero a diferencia del pinzamiento, el resto seguirá
siendo incluido en el resultado. Y podemos hacer lo
mismo si
queremos usar el desplazamiento
automático vertical a Voy a dar a las nubes
un gran desplazamiento automático a lo largo de la X para demostración. Y cuando ejecutamos el juego, las nubes se desplazan auto hacia la derecha, dando vueltas infinitamente. Mamá. Mamá. Volveré a restablecer el valor de desplazamiento automático
a una cantidad razonable. Ahora tenemos el
desplazamiento de paralaje de primer plano y fondo Pero las transiciones entre
habitaciones es muy repentina. Te veré en el siguiente video.
29. 4-1 Contenidos: Hola, amigos. En esta sección, permitiremos que el jugador se mueva entre varias
salas en nuestro juego. Al abrir la escena de la sala de inicio, podemos ver que los componentes
visuales de esta sala van fuera de los límites de
la cámara. Si estuviéramos en una habitación
contigua a esta, no
nos gustaría
ver a estos sprites dibujando cuando están destinados
a estar en una habitación diferente Además, si imagináramos todo
nuestro juego
lleno de muchas salas diferentes, sería un enorme desperdicio de
recursos tener todos sus componentes visuales cargados cuando solo estamos
viendo uno a la vez. Entonces agregaremos otro
nodo dos D a la escena. Denle el nombre contenido. Luego repare todos estos otros nodos al nodo
de contenido, excepto la forma de colisión Al hacer clic derecho en
el nodo de contenidos, lo
guardaremos como escena propia. Voy a hacer una nueva carpeta en la carpeta de habitaciones del bosque
para el contenido. Después nombra la escena Contenido de la sala de
inicio. Después borra el contenido
de esta escena. Cuando el personaje jugador
entra en esta sala, todo lo que tenemos que hacer es cargar su contenido y
agregarlo a la escena. Después borre los contenidos
cuando se vayan. Podemos detectar cuando el personaje
jugador entra en la habitación conectando
su cuerpo ingresado señal, ya que el cuerpo del personaje nodo
Tutti es un cuerpo físico Conectando esta señal
al script de la sala, automáticamente
agregará una función para nosotros
en el cuerpo ingresado, aceptando el cuerpo
como parámetro. No necesitamos el
cuerpo, por lo que podemos proceder con un guión bajo
para marcarlo como no utilizado En la parte superior del guión, será útil darle a
este script un nombre de clase. Vamos a llamarlo Habitación. Después exportar los contenidos
vistos como una escena repleta. Y llene esta variable
haciendo clic y arrastrando la escena de contenido desde la pestaña del
sistema de archivos al inspector También declararemos una
variable content como un nodo dos D. Declarando una nueva función
llamada load contents I content es nulo, entonces
le asignaremos el valor de los contenidos vistos instanciados Después agrega el nodo de contenido
a la escena como hijo. Cuando el personaje jugador
entre a esta sala, llamaremos a la función de carga de
contenido. Imprimamos temporalmente el valor del cuerpo para que
podamos ver de qué se trata. También necesitaremos
otra función para descargar los contenidos de la sala
cuando ya no sean necesarios, aunque no podremos probarlo hasta
el siguiente video Primero, comprobando si hay
algún contenido a descargar. Si hay contenido, llame a su función Qu free y
establezca la variable en null. Liberar un nodo
del árbol de escenas no borra automáticamente el contenido de la
variable Entonces, si tuviéramos que salir de una habitación, descargar su contenido, luego
volver a entrar en esa misma habitación, esta declaración if, comprobando si el valor de los
contenidos es nulo, diría, sí, en
realidad hay algo en
esta variable de contenidos Sin embargo, el nodo
que se almacenó aquí fue previamente
liberado del árbol de escenas, por lo que provocará un error Entonces, establecer la
variable en null después eliminarla del
árbol de escenas soluciona este problema. Al ejecutar el juego,
nuestro personaje está dentro del área de colisión de la
sala de inicio, por lo que activa la carga
del contenido de la sala de inicio. Sin embargo,
no queremos que otros cuerpos físicos activen la señal
y
carguen accidentalmente el contenido de la habitación Tenemos que asegurarnos de que
el personaje del jugador será el único cuerpo que
pueda hacer que esto suceda. Al cambiar a la escena del
personaje del jugador, podemos seleccionar el nodo Tutti
del cuerpo del personaje y expandir la sección de colisión en las propiedades heredadas
del objeto de colisión Aquí tenemos una
capa de colisión y una máscara de colisión, cada una con 32 botones numerados. Estas son máscaras de bits, que son solo números enteros
utilizados de una manera particular. Dado que los números enteros se almacenan como 32 ceros binarios y unos, podemos usar cada
bit individual como capa Cuando llega el momento de
verificar si hay colisiones, aplicando
operaciones lógicas simples entre máscara de colisión de
un objeto con la capa de
colisión del otro objeto, podemos determinar si
deben colisionar o Solo si la
máscara del primer objeto tiene uno en la misma posición de bit que la capa del segundo objeto
desencadenará una colisión. De lo contrario, simplemente
pasará como si no estuviera ahí. Cambiando la
capa de colisión del
personaje a cualquier otro número, ahora existirá en su
propia capa de colisión única separada de todo lo
demás en el juego. Como los números están
en grupos de ocho, me gusta usar las
primeras ocho capas
para capas de
colisión ambiental,
las siguientes ocho para
el personaje del jugador, las siguientes ocho para
los enemigos, etcétera El cuerpo del personaje
sigue enmascarando la capa uno, por lo que seguirá colisionando
con el terreno durante su proceso de física
cuando llamemos move y Slide Podemos nombrar estas capas en la configuración del proyecto bajo nombres de
capa Física dos D. Nombraré a la capa uno como terreno y a la capa
nueve como jugador. Estos nombres
se mostrarán al pasar el mouse sobre los
botones de capa en el inspector, junto con su bit
y valor entero En la escena de la sala de inicio, podemos cambiar la máscara de
colisión, por lo que esta área dos dende
solo enmascarará la capa de colisión del
personaje del jugador, solo el personaje del jugador
activará colisiones
con esta Ejecutando el juego de nuevo,
nada va a cambiar, pero podemos estar seguros de
que ningún otro cuerpo va a estar cargando el contenido de la sala. Ahora tenemos nuestra sala
cargando dinámicamente su contenido cuando el personaje
jugador entra en ella, pero todavía solo tenemos una habitación. Te veré en el siguiente video.
30. 4 a 2 habitaciones: Hola, amigos. En este video, agregaremos una segunda habitación para
que el personaje se mueva. Comenzaremos duplicando la escena de
la sala de inicio. Voy a nombrar a esta habitación de 1 segundo. Luego también duplique la escena de contenido de la sala de
inicio y la abra para que pueda editarla, luego quitar los
árboles y el dosel para que sea visualmente distinto
de la sala de inicio. También podemos editar el
terreno y los límites si queremos que las dos
habitaciones sean aún más distintas. Al abrir la escena de la segunda sala, cambiaré el nombre del nodo raíz de la escena para que
coincida con su nombre de archivo. No olvides asignar la
segunda escena de contenido de habitaciones en
la segunda escena de
espacio de habitación para que cargue el
contenido correcto cuando se ingrese. En la escena del juego, ya que mi mundo se
dividirá en regiones, agregaré un nodo dos D
y lo nombraré bosque. Entonces hacer de mis dos habitaciones
hijos de la región forestal. Guarde la región forestal
como su propia escena en la carpeta de habitaciones y abra la
escena de la región forestal para editarla. En la escena de la región forestal, ahora
podemos posicionar fácilmente estas dos habitaciones una al
lado de la otra. Queremos posicionar las habitaciones una
al lado de la otra para que podamos cambiar de habitación cuando el jugador salga de una habitación y
entre a otra. Alternar el ajuste de cuadrícula, luego expandir las opciones de
alineación y seleccionar Podemos establecer el paso de la cuadrícula
al tamaño de mosaico de nuestros mosaicos de terreno -32 píxeles Esto hace que sea muy
sencillo posicionar las habitaciones exactamente alineadas una al
lado de la otra. La señal ingresada en el
cuerpo de los nodos Tutti del área se
emitirá tan pronto como la forma de
colisión del personaje Tutti
se superponga con la forma de colisión de la
habitación Para mantener las cosas simples, tendremos que dejar un poco de
espacio entre habitaciones
lo suficientemente grande como para que el cuerpo del
personaje no pueda superponerse con más de
una habitación a la vez. De lo contrario, necesitaríamos
agregar lógica extra para cuando el personaje entra en una habitación sin salir completamente de
la anterior. Su
cuerpo de personaje se solapa con las áreas de ambas habitaciones
al mismo tiempo, pero luego se da la vuelta y
vuelve a la primera habitación Es mucho más fácil si las
habitaciones están espaciadas. Cuando el personaje
entra en una nueva habitación, sabemos que ya han
salido de la habitación anterior Esto también permitirá que el personaje se mueva
completamente fuera los límites de
la cámara antes activar la transición
a la nueva habitación Dado que la
forma de colisión de mi personaje tiene solo 12 píxeles ancho y la brecha entre
las habitaciones es de 32 píxeles de ancho, sé con certeza que
el personaje encajará entre estas dos habitaciones sin tocar ambas al mismo tiempo. Tener esta brecha
significa que todas nuestras habitaciones también
necesitarán extender su colisión en el piso lo suficiente fuera de los límites de la
cámara de habitación para evitar que
el personaje se
caiga antes de que llegue a
la habitación contigua Alejaré un
poco la cámara y comentaré la línea de código que une la cámara a los límites de la
habitación actual. Al ejecutar el juego, podemos ver que los contenidos de la
sala de inicio se cargan de inmediato
porque el personaje ya
estaba dentro de esta sala. Pasando a donde estará la
segunda sala, su contenido se
carga tan pronto como el personaje jugador
cruza el umbral. Pero también queremos descargar
el contenido de la habitación
anterior que acabamos de dejar Será responsabilidad del manager del juego
manejar las transiciones,
ya que involucrará a muchos componentes de la escena del juego
trabajando juntos. Tendremos que enviar una señal desde la sala en la que se ingresó
al manager del juego, que ni siquiera están en la
misma escena en nuestro proyecto. También tendremos muchas salas
diferentes en nuestro juego
y sería un dolor tener que
conectar manualmente esta señal para cada habitación
individual una a la vez. Por lo que sería más fácil usar
nuestros scripts para automatizarlo. Desde el guión de la sala, agregaremos una nueva señal en la parte superior
del guión que podemos emitir para decir que el
personaje del jugador ha entrado esta sala con la habitación que
se ingresó como parámetro. Entonces, cuando se reciba la
señal ingresada del cuerpo, emitiremos esta señal
en lugar de cargar el contenido y pasaremos esta
sala misma como argumento. Cuando esta sala esté lista, podemos acceder a la raíz de
árboles de escena iniciando una muñeca o firmar la
ruta de nodo anotado con una diagonal hacia adelante, luego la palabra raíz y
otra diagonal hacia adelante Desde la escena Raíz del árbol, el primer nodo
al que queremos acceder se llama juego tal como se nombra
en la escena del juego. Esto nos da acceso al guión
del manager del juego con un punto. Entonces podemos hacer referencia a una función
que aún no hemos escrito. Vamos a llamarlo en el
jugador ingresó a la habitación. Entonces podemos escribir
esta función en el script del administrador de juegos con
un parámetro de sala coincidente. Lo voy a nombrar habitación Entró para ser más claros
en este contexto. Para descargar el contenido de la sala
anterior, necesitaremos saber cuál era
la habitación anterior, así que necesitaremos una variable para mantener la sala en la que se encuentra actualmente el
personaje del jugador Voy a reemplazar este nivel actual habitación actual
y lo dejaré vacío. Ya no necesito
la etiqueta lista. Lo primero que debemos hacer
es verificar si la habitación que se ingresa es la misma que la habitación en la que
se encuentra actualmente
el personaje del jugador. En cuyo caso,
realmente no necesitamos hacer nada y podemos simplemente regresar
de esta función. Ahora podemos suponer
que la habitación actual y la habitación ingresada
son habitaciones diferentes. Al comenzar el juego por primera vez, no
hay habitación actual. Primero comprobaremos si la habitación
actual no es nula. Si hay una habitación actual, debemos indicarle que descargue su contenido usando la función que escribimos en el video anterior Después asignando habitación actual
para que sea la habitación ingresada, ahora
podemos decirle a esta sala
actual que cargue su contenido y finalmente ate la cámara a los límites de la habitación
actual Pero voy a comentar esto para que
podamos ver qué pasa
con el zoom hacia fuera. Ahora cuando ejecutamos el juego, entrar a la segunda sala envía una señal al gestor del juego para descargar el contenido
de la sala de inicio antes de cargar los contenidos
de la segunda sala Ahora tenemos múltiples
salas en nuestro juego, pero el desplazamiento de
paralaje de primer plano
y fondo no
funciona para salas que no están centradas en el origen de Te veré en el siguiente video.
31. 4-3 Parallax: Hola, amigos. En este video, arreglaremos el desplazamiento de
paralaje
del primer plano y fondo
con Comenzando en la escena de la
segunda sala, voy a copiar todos mis colores de
modulación
de los nodos Parallax Tut
a sus nodos hijos Entonces puedo unparent a
los sprites y eliminar los nodos Parallax Tut mientras sigo manteniendo Luego adjuntaré un nuevo script
a cualquiera de estos sprites, lo
nombraré Parallax y
lo pondré en la carpeta de scripts Este mismo script se puede adjuntar a todos los sprites
que quiero a Parallax Para crear un comportamiento personalizado, ayuda tomar
algún tiempo para
pensar qué es lo que estás
tratando de lograr, qué referencias de nodo y otra información se
requerirá. Tengo un número de sprites
diferentes. Quiero moverme en
diferentes cantidades relación con la
posición de la cámara, y sé que la cámara está actualmente encuadernada dentro de
los límites de esta sala. Agregaré temporalmente una cámara
dos nodos D a la escena y acercaré por un factor de dos para fingir que esta
es la escena del juego. Si la cámara está exactamente en
el centro de esta habitación, quería dibujar todo
exactamente como está. Pero cuando la cámara se
aleja del centro, moveré todos los sprites
de
paralaje una cantidad relativa con fondo moviéndose
menos que
la cámara y los elementos primer plano moviéndose
en
la dirección Para ello, cada sprite
necesitará conocer la posición de la
cámara relativa al centro de la habitación, así
como su propia posición
original En el script Parallax, declararé una variable
exportada para contener el factor
por el cual el sprite se mueve con relación a la cámara y le
nombraré escala de desplazamiento
como vector dos Esto funcionará de manera similar a la variable de escala de desplazamiento
en el nodo Parallax two D. Cuando esta sala se carga
en el árbol de escenas, podemos usar la
etiqueta on ready para obtener su posición y almacenarla en una variable
como la posición original. Conseguir una referencia a
la cámara actual es fácil gracias a la función nodo
G Viewport Devolviendo el Viewport en el que existe
este nodo, que además cuenta con la función Get camera to D para obtener la cámara También podemos almacenar esto en
una variable, usando la etiqueta on ready. Anulando la función de proceso, no
necesitamos Delta y
podemos marcarla como no utilizada Simplemente estableceré la
posición del sprite para que sea su posición original más la distancia de la
cámara desde el punto medio de la habitación multiplicada
por la escala
de desplazamiento Ahora la cámara solo necesita una función
pública que pueda decirnos su posición relativa al punto medio de la
sala actual Cambiando al guión de
la cámara, escribiré esta función,
desplazada desde el punto medio, que será la posición de la
cámara más su desplazamiento menos el punto medio
de la habitación actual Declarando esto como
una nueva variable, puedo calcularla
como el promedio de
la esquina superior izquierda e
inferior derecha de la habitación al
aceptarlas desde la función de
límites establecidos Podríamos modificar esta función
para aceptar el punto medio y tamaño del rectángulo en
lugar de sus esquinas superior izquierda e
inferior derecha, pero de todos modos no hará
ninguna diferencia en eficiencia,
así que no me molestaré Ahora podemos establecer la escala de
desplazamiento para cada uno de los sprites de paralaje para
darles a cada uno una
distancia diferente de la cámara Todavía solo usaré paralaje
horizontal, dando a mis colinas una escala
de desplazamiento de un tercio a lo largo del eje X, y las colinas más
atrás dos tercios Para el primer plano,
necesitarán
moverse en
dirección opuesta a la de la cámara, tendrán una escala de desplazamiento de un tercio
negativo y dos tercios
negativos Esto será suficiente
para crear la ilusión de
profundidad para nuestras habitaciones. ejecutar el juego, podemos
pasar a la segunda sala y ver que el efecto de paralaje se ve idéntico al de
la sala de inicio, a pesar de ser realizado
por un guión muy sencillo Dado que los sprites de primer plano se mueven en la
dirección opuesta a la cámara, necesitarán repetir y
envolver su posición para crear un bucle infinito, o simplemente podemos hacer que el
sprite sea más grande que la Hacer mis arbustos 1.5 veces más largos que la habitación y la
hierba duplicar la longitud de la habitación dejará
suficiente extra a
ambos lados para que los bordes nunca
lleguen a la vista de la cámara A sería
posible utilizar el nodo
Parallax two D para dibujar el primer plano y el
fondo usando Viewport
separado
y fondo usando Viewport
separado dibujarlos en
diferentes capas de lienzo
o intentar dibujar siempre habitación actual en
el origen de la escena del
juego Estas soluciones llevarían
a otras complicaciones y limitaciones en el
futuro
a la hora de dibujar el
mapa del juego, por ejemplo. Me parece que escribir
soluciones personalizadas como esta a veces es más fácil que
usar los nodos proporcionados. La solución también mantiene todo para una
habitación en un solo lugar, lo
que simplifica
el diseño y construcción de las habitaciones de
una manera más intuitiva. Ya no necesito esta
cámara nodo Tuti, así que la eliminaré. Eliminando las nubes
del nodo Parallax touti, podemos alterar el script
Parallax, también auto scroll las nubes también Ampliando el naufragio de la región, todo lo que necesitamos hacer para mover
las nubes hacia la derecha es disminuir el valor de
exposición con Adjuntando el
script Parallax a este nodo, primero
podemos establecer
su escala de desplazamiento uno
para que coincida con
el movimiento de la cámara Esto hará que las nubes aparezcan una distancia infinita
en comparación con las colinas Parallax Al exportar otro vector dos
para la velocidad de desplazamiento automático, necesitaremos usar Delta en la función de proceso ahora y
podemos eliminar el guión bajo Accediendo a la
propiedad region rect y su posición, comenzando con la
X, restaremos el valor AutoScrollX Entonces esto hará que la
velocidad de desplazamiento automático píxeles por segundo. Después asigne el resultado a
la región recs X posición. Pero si tuviéramos que ejecutar esto
por mucho tiempo, este número se
acercaría a los límites de un número de punto flotante
y puede causar problemas. El valor de la posición X
coincide con el tamaño, el resultado es en realidad el mismo. Sería mejor restablecer la posición X de nuevo a
cero cuando esto suceda, que podamos recorrer esto por una cantidad infinita de tiempo. Usando la función AP F, podemos proporcionar un valor mínimo
y máximo para limitarlo a estar solo entre
cero y el tamaño rec. Esta función
devolverá un resultado que debe estar entre
estos dos valores, pero a diferencia del pinzamiento, el resto seguirá
siendo incluido en el resultado. Y podemos hacer lo
mismo si
queremos usar el desplazamiento
automático vertical a Voy a dar a las nubes
un gran desplazamiento automático a lo largo de la X para demostración. Y cuando ejecutamos el juego, las nubes se desplazan auto hacia la derecha, dando vueltas infinitamente. Mamá. Mamá. Volveré a restablecer el valor de desplazamiento automático
a una cantidad razonable. Ahora tenemos el
desplazamiento de paralaje de primer plano y fondo Pero las transiciones entre
habitaciones es muy repentina. Te veré en el siguiente video.
32. 4-4 Transición: Hola, amigos. En este video, suavizaremos la transición entre habitaciones con un
simple desvanecimiento a negro. En la escena del juego, la
mayoría de los juegos comenzarán ya sea
con una
pantalla de carga o completamente negra, luego se desvanecerán cuando comience
el juego. Al agregar un nodo a
la capa de lienzo, podemos usar un nodo destrozado de color para dibujar colores simples fácilmente Ampliando la sección de diseño, cambiaremos los anclajes
preestablecidos a naufragio completo Esto le dirá el color destrozado para llenar todo el lienzo Actualmente es blanco, pero el
negro es más común, por lo que podemos cambiar el color
a negro en la parte superior. Cuando comience el juego,
todo lo que tenemos que hacer es cambiar
gradualmente este
color de negro a claro, revelando la
ventana gráfica de la cámara detrás de él Con nuestras habitaciones pequeñas y sencillas,
se cargan instantáneamente. La carga y descarga del contenido de la
habitación no causa
actualmente ningún retraso. Pero si imaginamos que
nuestras habitaciones consistirán en
muchos más sprites y
sobre todo los efectos de muchos más sprites y sonido y música de
fondo que se está cargando, esto hará que la
carga de la habitación tarde
más que un solo fotograma Podemos usar el mismo efecto
hacia atrás para desvanecer a negro, hacer nuestra descarga
y carga de la habitación, luego volver a desvanecerse
cuando todo esté hecho. Este proyecto no va a ser tan grande que necesitemos una pantalla
de carga real. Vamos a cambiar el nombre de este nodo fade
y darle un nombre único. Tendremos que
asegurarnos de que este nodo permanezca en la parte inferior
del árbol de escenas para ser dibujado sobre todo lo
demás o aumentar su índice Z. Tener este gran rectángulo
negro en la escena del juego puede obstaculizar el trabajo
en otras cosas. Podríamos querer tener este
nodo oculto por defecto. Adjuntando un script a este nodo, lo
nombraré fade y
lo guardaré en la carpeta scripts. Anulando la función ready, lo primero que quiero hacer es establecer su
propiedad visible en true, así cubre
todo en negro Necesitaremos dos funciones
públicas para ajustar el color a negro
o claro. Para ajustar el valor de
una propiedad a lo largo del tiempo, la forma más fácil es
usar una preadolescente Entonces declararemos
uno como variable. Si bien no espero permitir desvanezca más de una vez
en rápida sucesión, sigue siendo una buena
idea verificar si la preadolescente ya existe
y matarla por si acaso Luego crea una nueva preadolescente. No hay necesidad de tipos elegantes de transición
o flexibilización aquí, una preadolescente lineal
funcionará bien Y será entre
este nodo en sí, su propiedad de color y cambiando su color para que sea transparente a
lo largo de un tiempo Por ahora, pondré 1 segundo. Hay un
color transparente definido en la clase, pero si colocamos
el mouse sobre él, podemos ver que
tiene valores rojo, verde
y azul de uno, valores rojo, verde
y azul de uno, lo que
significa que es
blanco transparente, no negro transparente Esto no creará
el efecto que quiero, así que definiré mi propio color
transparente como una constante y lo nombraré claro. Usar todas las mayúsculas es convencional al
nombrar constantes. Este será un color
con cero valores rojo, verde, azul y Alfa. También podemos definir una
constante para la duración de la premezcla y reemplazar el 1
segundo con esta constante Esto hace que sea un poco más fácil cambiar la duración sin
tener que mirar a través del script y sin
exportar una variable para algo que quieras
mantener consistente para todo tu proyecto. Para la función feed to black, podríamos copiar y pegar
todo este código,
solo cambiando el argumento de valor
final de la llamada a la
función de propiedad tween, pero sería mejor
evitar la redundancia Et en su lugar hacen de esta su propia función
privada
llamada tween color, aceptando el
color final como un parámetro, luego pasa esto a la
llamada a la función de
propiedad tween como argumento Entonces tanto el destino al negro
como a dos funciones claras pueden llamar a esta función,
pasando diferentes argumentos. En el guión del administrador del juego, tomaremos una referencia
al nodo fade en la parte superior. Cuando el personaje jugador entra en una habitación después de cargar
el contenido de la sala, podemos decirle al desvanecimiento que se
interponga su color para despejar Cuando
comience el juego por primera vez,
no habrá una
sala actual para descargar, por lo que esta se desvanecerá de inmediato. Después de ingresar a la segunda habitación, querremos desvanecernos a negro antes de descargar el contenido de la habitación
actual, luego proceder a cargar la segunda habitación y volver a
desvanecerse Pero esta función
no esperará a que
termine la preadolescente antes de descargar
el contenido de la habitación Lo hará de inmediato. Para pausar esta función mientras
la tween se desvanece a negro, podemos usar la palabra clave wait Esperar será seguido
con una señal. La señal que queremos esperar es la señal de tweens terminada
en el script fade Así podemos devolver esta señal
desde nuestra función de premezcla. Cambiar el tipo de retorno de nuestra función de
void a signal. Pasar la misma señal de
retorno a lo largo nuevo a través de las funciones de fundido a
negro y para borrar. De vuelta en el guión del administrador del juego, el administrador del juego ahora puede acceder a esta señal en cualquier momento que
llame a estas funciones. Podemos esperar fade a negro
o esperar fade to clear, por lo que esta función se detendrá y esperará a que
termine la preadolescente antes de continuar Generalmente no queremos que
el jugador tenga control sobre el personaje
mientras esto sucede. Así podemos llamar al
jugador punto Desactivar en la parte superior de la
función antes de iniciar la transición y volver a habilitar el nodo reproductor al final después de que
se complete la transición. Olvidé actualizar
esta
variable de dirección para moverla de dirección
cuando la cambié de nombre. Si bien estas habitaciones
son bastante pequeñas y deberían estar descargando y
cargando con bastante rapidez, todavía
podríamos
ver una instancia
donde se descarga la
habitación anterior y debido a ver una instancia
donde se descarga la
habitación anterior que no
hay terreno para que el
personaje se pare, caen por
el piso antes cargue
el contenido de la habitación siguiente para proporcionar un nuevo piso Por lo que también debemos
desactivar y habilitar al personaje al
mismo tiempo que hacemos el nodo jugador. Otra forma en que podemos
habilitar y deshabilitar nodos es cambiando su propiedad de modo de
proceso. Configurarlo en deshabilitado cuando se inicia
la transición, luego hereda cuando se complete la
transición Ahora el jugador no puede
controlar al personaje, y el personaje
no se verá afectado por gravedad mientras realiza la transición
entre habitaciones A continuación, trabajaremos en dibujar
nuestras habitaciones en un mapa. Te veré en el siguiente video.
33. 4-5 ventana gráfica: Hola, amigos. En este video, comenzaremos a trabajar en
dibujar nuestras habitaciones en un mapa. Si bien es posible dibujar el mapa por separado
del mundo del juego, es mucho más complicado
mantener la consistencia entre el mundo y el mapa
si tienes que actualizar ambos por separado cada vez
que cambias algo. Posicionar iconos en el mapa, especialmente los iconos que pueden moverse
como el personaje del jugador, puede convertirse en una tarea aún más difícil. Un método mucho más fácil de crear
un mapa es simplemente tener una segunda cámara que vea el mundo desde una perspectiva Zoomed
out, pero dibujar el mundo y sus
contenidos de una manera más simple Así que agreguemos otra cámara a nuestra escena de juego y cambiemos el nombre de
esta para que sea Cámara de mapa. Por defecto, solo se utilizará la primera
cámara, y dibujará la ventana principal del
juego Para dibujar el mapa, la cámara del mapa necesitará dibujar una ventana gráfica
diferente, por lo que agregaremos una como
nodo en el árbol de escenas, que es un nodo sub Viewport Renombrarlo a Map Viewport
y darle un nombre único. En algunos de nuestros guiones, ya
hemos utilizado
la función G Viewport para obtener la Viewport principal del juego, que se está utilizando para dibujar
los dos mundos D del juego El mundo dos D en
este contexto
no es lo mismo que el nodo
mundial Medio Ambiente. Contiene todos los
nodos TD que se encuentran actualmente en el centro, incluido el manager del juego. Si hijo de la cámara del mapa
a la Vista de mapa, esta cámara ahora dibujará la Vista de mapa en lugar de
la ventana gráfica principal del juego, pero no tiene ningún lugar
en la pantalla para dibujarla Y así tendremos
que agregar un nodo de textura destrozada a la capa de lienzo para darle a la cámara un lugar para
dibujar la ventana gráfica Nombremos esto para que sea la textura de
Map Viewport. Eliminaré todos estos nodos de control
ficticios
y me aseguraré de que el
nodo destrozado de textura se dibuje antes el nodo de fundido
poniéndolo más alto en la jerarquía de
escena Al hacer clic en el menú desplegable de
texturas, podemos seleccionar la textura de la ventana gráfica luego seleccionar el
mapa Vista a dibujar como la textura
para este wret de textura La textura rect se
redimensionará
automáticamente para que coincida con el
tamaño de la ventana gráfica Actualmente solo está dibujando el color de
fondo gris predeterminado porque la cámara del mapa y la
ventana gráfica no pueden ver nada Por defecto, cada Viewport
tendrá su propio mundo. Se puede pensar en
estos mundos como mundos
paralelos o
planos de existencia. Pueden ocupar
el mismo espacio
al mismo tiempo pero existir
independientemente entre sí. Pero queremos que esta Viewport dibuje el mismo mundo
que nuestra principal Viewport En el script del administrador del juego, tomaremos una referencia
al nodo Map Viewport Luego en la función ready, establezca la
propiedad world two D de la Viewport Podemos acceder a la ventana
principal
llamando a
los nodos del administrador de juegos obtener la función Viewport, luego acceder a su propiedad mundial
dos D. Ahora, tanto el Viewport principal el Map Viewport
dibujarán el mismo mundo Generalmente queremos que nuestros mapas vean mucho más del mundo, así que lo configuraré en
un octavo Zoom. Si queremos cambiar
las dimensiones de la textura del mapa, podemos establecer las dimensiones de
píxeles de la ventana gráfica
seleccionándola en el árbol de escenas Voy a hacer que sea
la mitad de las dimensiones de mi juego 640 por 360 pixeles. En lugar de dibujar este
color gris cuando no hay nada, prefiero que el fondo de mi Map Viewport sea transparente Voy a alternar sobre fondo
transparente. Sin embargo, esto hace que el
mapa sea difícil de leer, me gustaría tener esta textura de
mapa contenida dentro un panel para que parezca
separado del juego principal. Al agregar un contenedor de panel
a la capa Canvas, repararé la textura del mapa para que sea hijo del nodo contenedor del
panel, luego renombraré el contenedor del panel a Mapa y
le daré un nombre único Con el tema predeterminado, el contenedor del panel dibujará un color negro transparente
y como es un contenedor, automáticamente
se
redimensionará para contener a sus hijos Esto deja claro
que la textura del mapa se está dibujando en el lienzo, no como parte del mundo, y podemos ajustar el
aspecto del contenedor
del panel más adelante a través
del editor de temas. Usaré los anclajes de los
contenedores del panel
para anclarlo al
centro de la pantalla Generalmente queremos que la cámara de
mapa siga al personaje
del jugador
como lo hace la cámara principal, pero sin ninguna de las características de
tweening u otras características A diferencia de la cámara principal, la cámara de mapas nunca
necesitará hacer otra cosa, por lo que es seguro que
siempre coincida con la
posición del personaje del jugador exactamente. No hay forma de
tener la cámara del mapa infantil al personaje del jugador, ya que debe seguir siendo un hijo
del mapa Viewport
para dibujar el Podríamos escribir otro
guión para mover esta cámara, pero hay un nodo que podemos
usar para facilitar las cosas, el remoto transforma dos D. Con la transformación remota dos D como hijo del personaje
del jugador, podemos establecer su
ruta remota a la cámara del mapa. Ahora las propiedades de
transformación de la cámara, rotación de
posición y escala se actualizarán automáticamente para que sean las mismas que el personaje
del jugador. Podemos desactivar
la rotación y la escala expandiendo
la sección de actualización. Incluso si estuviéramos editando la
rotación o escala del personaje del jugador, no
quisiéramos que el mapa
copiara estas propiedades. Mm. Ahora tenemos nuestro mundo de Juegos
dibujado en el Canvas, pero queremos dibujar una versión
simplificada
del mundo en
lugar de una copia exacta. Te veré en el siguiente video.
34. 4-6 Visibilidad: Hola, amigos. En este video, haremos que la cámara de mapas dibuje una
versión simplificada del mundo. Comenzando en la sala de inicio, agreguemos temporalmente
el contenido de la habitación. No quiero dibujar todos
estos sprites en el mapa, solo un contorno de la forma y el terreno de la
habitación Podemos usar cualquier nodo D para dibujar esto
dependiendo del estilo que queramos. Usaré un nodo de capa de mapa de teselas. Dale un nuevo juego de
mosaicos con mosaicos de 32 por 32 píxeles. Voy a importar un nuevo sprite, que es solo un simple cuadrado blanco de 32
por 32 píxeles Luego agrega esto al conjunto de mosaicos. Dibujando este cuadrado blanco
en mi capa Tile Map, dibujaré un contorno de la habitación usando el terreno
como piso en
lugar del límite de la cámara y dejando puertas para
conectarse a otras habitaciones Queremos que la cámara principal
dibuje solo el contenido, mientras que la cámara de mapa
dibujará esta nota de
capa de Tile Map en su lugar. Si bien ambos están
mirando la misma habitación, verán dos versiones
diferentes de la misma. Ahora que tengo la
forma de mi habitación, eliminaré el contenido
de la escena. Dado que el nodo de capa Tile Map siempre
será visto
por la cámara del mapa, siempre
permanecerá cargado en
lugar de cargarse y
descargarse como el contenido Ampliando la sección de
visibilidad, puedo usar la propiedad de modular
color para cambiar mis cuadrados blancos en colores si quiero Ya que esto es parte de
la región forestal, dibujaré su mapa en verde. Para que la cámara de mapa dibuje
esto pero no la cámara principal, voy a cambiar su capa de
visibilidad 1-2. La
capa de visibilidad predeterminada uno
será todo lo que
dibuje la cámara principal del juego, mientras que la capa dos será todo lo que quiera
dibujar en el mapa. Al igual que con las capas de
colisión, podemos nombrar estas capas de
visibilidad en la configuración del proyecto bajo los nombres de
capa dos D render. Voy a nombrar a la capa un
mundo y a la capa dos Mapa. Estas capas de visibilidad
dependen de las
capas de visibilidad de sus padres. Si la ventana gráfica no puede ver
el nodo de área de la sala de inicio, entonces no se molestará en
verificar si puede ver el nodo secundario del nodo de
capa de mapa de teselas El
nodo padre de la sala de inicio necesitará tener su capa de visibilidad establecida
tanto en uno como en dos, ya que tendrá hijos que pueden ser dibujados por ambas vistas. Avanzando por
la jerarquía, la región forestal necesita
tener su visibilidad establecida para usar
ambas capas de visibilidad al igual que
el nodo raíz de escenas del juego. El entorno mundial Node no tiene una propiedad de
capa de visibilidad. Ahora seleccionando la Vista de mapa, podemos establecer su máscara de llamada Canvas para ver solo la capa dos
y no la capa uno Esto funciona de manera similar a la propiedad de máscara de colisión
para objetos de colisión. Solo si el bit para la
máscara se establece en uno, ¿podrá ver algo cuya capa tenga el
mismo bit configurado en uno? Pero no podemos acceder a la ventana principal desde
el editor para cambiar su máscara de llamada Canvas a solo ver la capa uno
y no la capa dos Por defecto, estará
enmascarando cada capa. Así que tendremos que
editarlo a través de script. En la función de
script ready del administrador de juegos, podemos acceder a la ventana gráfica principal con la función G Viewport, luego establecer su propiedad de máscara de
llamada Canvas Al pasar el cursor sobre la capa uno, podemos ver que su
valor entero también es uno Solo podemos establecer el valor de las máscaras de
llamada de Canvas en uno. Ahora solo verá la capa de
visibilidad uno y no la capa dos o cualquier
otra capa para el caso. Copiando el
nodo de capa Tile Map en la sala de inicio, lo
pegaré en la segunda habitación para
dibujar también esta habitación en el mapa. Instanciaré el contenido de la
habitación, luego editaré los mosaicos para reflejar
con mayor precisión la forma de esta habitación y eliminaré el
contenido cuando termine Recuerde establecer la capa
de
visibilidad de los nodos padre para que exista en ambas
capas de visibilidad para que
los hijos sean vistos por
sus respectivas vistas. Ahora, ambas habitaciones son
claramente visibles en el mapa con muy poco esfuerzo
requerido ya que agregamos más habitaciones, solo necesitando agregar el mapa para cada habitación de su escena en una capa de visibilidad
separada. Podemos agregar fácilmente otras
cosas al Mapa dos
agregando más sprites a ellos
y poniéndolos en
visibilidad Capa dos, como un icono de mapa de
personajes de jugador Abriendo la escena de los
personajes del jugador, agreguemos un Sprite para denodar
y ponerle el nombre Icono de Mapa Voy a poblar la textura
con una textura de atlas, usar la misma hoja de sprites y seleccionar una región para
usar como icono de mapa Usaré la
cabeza del personaje
en algún lugar de la hoja de sprites donde
la cola no esté en el camino Después de poblar la propiedad
texture, estableceremos su
capa de visibilidad en dos y no en una Entonces el nodo raíz
de esta escena
necesitará tener tanto la
capa uno como la dos. Me ajustaré al
desplazamiento del sprite, así que se sienta en el suelo
como lo hace el personaje Sabiendo que el
Zoom de la cámara es un octavo, escalaré este icono ocho veces haciéndole parecer
muy grande en la escena. Como no quiero que
este ícono cubra a mi personaje cada vez
que trabajo en la escena, prefiero tenerlo oculto
y esto será cierto de todo en mi juego a lo que quiera adjuntar un ícono de mapa. Voy a agregar un script a este nodo, ponerle
el nombre Icono de mapa. Y solo voy a hacer que establezca la propiedad
de visibilidad en true on ready. Ahora bien, este icono de
mapa muy grande no
necesita ser dibujado en el editor mientras estoy trabajando
en mi personaje, pero se dibujará
cuando ejecute el juego. Ahora tenemos nuestro mapa
dibujando contornos de habitaciones y el
personaje del jugador con un icono, pero es posible que queramos que el mapa encienda y desconecte con un botón. Te veré en el siguiente video.
35. Mapa 4-7: Hola, amigos. En este video, permitiremos que el jugador abra y cierre el
mapa con un botón. Comenzando en la escena del juego, tendré el mapa
oculto por defecto alternando la visibilidad del nodo
contenedor que lo sostiene A continuación, adjunte un nuevo script
al contenedor. Si bien actualmente estoy usando un contenedor de
panel para esto, no
necesitaré acceder a ninguna de las características del contenedor de
panel en este script y puedo heredar del
tipo de control más genérico Si quiero usar
un tipo diferente nodo
de control en el futuro, no
necesitaré
modificar mi script. Este script necesitará funciones
públicas para abrir el mapa
y cerrar el mapa. Para que las cosas sean simples, simplemente
estableceré la visibilidad
del nodo en true o
false en consecuencia. También hay funciones show
and hide definidas en la
clase de elemento Canvas que hacen lo mismo. Si bien esto puede parecer
inútil tener una función que solo
llame a otra función, mantener sus implementaciones
encapsuladas en funciones
públicas como esta significa que podemos
actualizarla fácilmente en el futuro Podemos agregar lógica extra
en estas funciones para hacer que las cosas sucedan cuando se abre o cierra el
mapa, o podríamos usar una preadolescente para mover el mapa fuera de la pantalla o hacer
que crezca y se encoja en lugar de simplemente alternar
su visibilidad Si quiero hacer estos cambios, solo
necesito editar este script, en lugar de necesitar también editar el guión del reproductor o
cualquier otro script que esté llamando a
esas funciones. Como he decidido usar un botón de alternar para activar y desactivar
el mapa, en lugar de llamar a las funciones de abrir
o cerrar, prefiero tener una sola función de
alternar que haga ambas cosas. Añadiendo una variable privada para saber si el mapa
está abierto o no actualmente, haré que la
función toggle cierre el mapa si está
abierto o lo abra si está cerrado. Entonces las funciones abierta y
cerrada pueden establecer el valor de I
open en consecuencia. abrir la configuración del proyecto, la pestaña Mapa de entrada, necesitamos agregar una
nueva acción de entrada para abrir y cerrar el mapa. Usaré la tecla de retroceso y el botón de selección
en mi controlador La mayoría de los juegos con este
tipo de mapa de juego permitirán al jugador
desplazar la cámara también. Ya tengo mirar hacia arriba
y mirar hacia abajo entradas. Solo voy a agregar mira a
la izquierda y mira a la derecha. Usando las
teclas de flecha izquierda y derecha o el stick derecho inclinado hacia la izquierda o hacia la derecha
en mi controlador En el script del reproductor, podemos exportar una variable para
mantener una referencia
al nodo de mapa y
poblarlo en el inspector Luego en la función de entrada, dígale al mapa que active o desactive si se presionó el
botón de mapa. ejecutar el juego, el
mapa comienza oculto, pero al presionar el botón del mapa, muestra el mapa y al
presionarlo de nuevo, lo cierra. Para desplazar la cámara de mapas, solo
tendremos que
ajustar su valor de desplazamiento. Entonces le daremos al
script del mapa una referencia
a la cámara del mapa. Agregar una
función pública llamada pan, aceptando un argumento vector dos para la dirección de desplazamiento
panorámico de la cámara. Añadiremos al desplazamiento de la cámara esta dirección multiplicada
por una velocidad de Pan, y podremos acceder a Delta
aunque no estemos en una función de proceso llamando a las clases de nodo Get
Process Delta t function. Al exportar esta variable
de velocidad de pan, estableceré la mía en 1024. Esto puede parecer rápido, pero recuerde que la cámara del mapa
está muy alejada, por lo que parecerá moverse
a una octava parte de la velocidad Para que el script
del jugador controle esta cámara
cuando el mapa esté abierto, necesitará
saber si el mapa está abierto, lugar de hacer pública la variable
is open, permitiendo que cualquier otro script
modifique su valor, podemos escribir una función que devuelva el valor
de la variable. Cuando el mapa esté cerrado, restableceré el desplazamiento de
la cámara de nuevo a cero, por lo que una vez más se
centrará en el personaje
del jugador. Cambiando al script
del reproductor, agregaremos los controles para panoramizar el mapa en
la función de proceso Pero sólo si el mapa está abierto. Si el mapa está abierto,
le diremos al mapa que se desplace. Al igual que usamos el eje G para obtener el estado de dos
direcciones opuestas como un flotador, podemos usar el vector G para obtener un vector dos desde
cuatro direcciones. Sólo tenemos que
darle los nombres de las cuatro acciones
de entrada
que coincidan con los ejes X e Y. Mira a la izquierda, mira a la derecha, mira hacia arriba y mira hacia abajo. El último argumento
es una zona muerta, que es la longitud mínima del vector que se utilizará. Si el vector es demasiado corto, podemos ignorarlo, lo cual es útil para que los
sticks analógicos ignoren la deriva. Si bien esto no
causará ningún problema en un controlador ya que estoy usando
el stick analógico derecho, los controles de
mi PC están usando las teclas de flecha tanto para el
movimiento como para mirar. Entonces, si el mapa está abierto, pondré el resto de los controles de
mirada y movimiento en una cuadra para saltarlos. Si quieres permitir que el personaje
del jugador
se mueva y mire hacia arriba o hacia abajo
mientras el mapa está abierto, tendrás que cambiar las
acciones de entrada para que no se superpongan. Para evitar que el personaje
continúe moviéndose
después de abrir el mapa, estableceré su dirección
de movimiento cero cuando se abra el mapa. El jugador ahora puede presionar un
botón para acceder a un mapa del mundo, mostrando nuestras dos salas y la posición
actual del jugador, y podemos desplazar la
cámara del mapa si queremos. En la siguiente sección,
comenzaremos a hacer un seguimiento de las estadísticas del jugador y
las dibujaremos en la pantalla frontal. Te veré en
la siguiente sección.
36. HUD 5-1: Hola, amigos. En este video, comenzaremos a mostrar
información sobre el personaje del jugador en
la pantalla frontal. Desde que inició este curso, Godot 4.6 fue liberado. Actualizar el proyecto a Godot 4.6 no causó ningún problema, así que continuaré con las lecciones
en la versión actualizada No recomiendo actualizar a una versión más reciente de ningún motor de
juego mientras estás trabajando en un proyecto
a menos que tengas control de
versiones para
revertir si es necesario Voy a necesitar importar
algunos sprites de interfaz de usuario a mi proyecto para dibujar las estadísticas de los
personajes en la pantalla En la escena del juego, tenemos una capa de lienzo que se establece en la capa uno
en el inspector. El Viewport principal que dibuja los dos mundos D del juego
se considera capa cero Por lo que todo en el
mundo dos D del juego se
dibujará en la capa cero
independientemente de su índice z. La capa de lienzo, la capa uno, dibujará sobre todo eso
para dibujar cosas como menús y nuestros personajes se mostrarán como su
salud y magia. Los nodos en la capa Canvas suelen ser nodos de control Goy, todos los
cuales tienen iconos
verdes para
diferenciarlos de dos
nodos D que son azules Comencemos por agregar un nodo de control como hijo
de la capa Canvas, renombrarlo a HUD, reordenarlo para que esté en la
parte superior de las capas de Canvas hijos y hagamos del
mapa un hijo del Luego podemos agregar
tantos iconos, medidores y texto como necesitemos a este nodo padre para crear
nuestra pantalla frontal. Ayuda que un nodo de
control básico actúe como padre
de todo tu
HUD por varias razones Algunas de las propiedades
del nodo
HUD padre serán heredadas
por todos los nodos secundarios Dado que el
nodo de capa de lienzo no es un nodo de control, no tiene las
mismas propiedades, por lo que no puede proporcionar este beneficio. Si quieres dar a todos
tus elementos de HUD una apariencia
consistente, puedes agregar un tema
al nodo padre y se aplicará a todos
los nodos secundarios
automáticamente También mantiene la transición de
desvanecimiento en la parte inferior del árbol de
escenas de forma natural, ya que solo
agregarás niños por encima de él, por lo que no tendrás que preocuparte por reorganizar el
árbol de escenas cada vez A diferencia de dos nodos D, que utilizan su propiedad de
posición de transformación para definir dónde están relativos
al origen de la escena, los nodos de
control utilizan
tanto una posición un tamaño para definir su ubicación
dentro de un espacio definido. Por lo general, la ventana del juego, que se muestra como
este rectángulo azul. Podemos ver que el
nodo HUD tiene un tamaño de 40 por
40 píxeles y se encuentra en la posición 00, que es la
esquina superior izquierda de la ventana Si bien podemos simplemente mover y
cambiar el tamaño del nodo de control
editando estos valores, estos cambios no
escalarán bien ni funcionarán manera efectiva si cambiáramos tamaño de
la ventana en
la configuración del proyecto Entonces los nodos de control tienen estos anclajes verdes que podemos usar para establecer la
posición y el tamaño de cada nodo de control en relación su padre con
la capa de lienzo que representa toda la ventana Queremos que el Hud cubra toda
la ventana para que
podamos establecer su
preajuste de anclaje en naufragio completo Esto coloca los anclajes en cada una de las cuatro esquinas
de la ventana, luego actualiza automáticamente los
valores de tamaño y posición para que coincidan Si hacemos visible el mapa, su posición no
se ha actualizado, así que restableceré sus
anclajes al centro Ahora podemos ver que ya que está anclado al
centro de su padre, al mover o redimensionar el nodo HUD se moverá el mapa
para permanecer centrado Para dibujar la
salud y la magia del personaje, agregaré un nuevo nodo de
control para mantener estos elementos
agrupados y nombrarlo vitales. Dejaré esto
anclado a la parte superior izquierda pero restableceré su tamaño a cero A continuación, agregaré un nodo de
textura destrozada para dibujar una textura simple, un perfil del personaje y rellenar su propiedad de
textura arrastrando el activo
desde la pestaña del sistema de archivos Añadiendo otro nodo destrozado de
textura, nombraré este ícono de salud y rellenaré su textura
con una textura de atlas,
seleccionando un sprite de mi hoja
de sprites Voy a necesitar tener
múltiples de estos para representar la salud total de mi
personaje. Así que lo duplicaré un montón de veces y los colocaré
más o menos en secuencia. Sería una buena idea
mantener estos iconos agrupados bajo
un único nodo padre. Entonces agregaré otro nodo de
control llamado Health Counter y repararé todos los íconos
de salud para
que sean hijos de este nodo Posicionar manualmente cada uno de estos iconos es una especie de dolor. Por lo que Godot proporciona nodos de control llamados contenedores
para que lo hagan por nosotros. Como quiero que estos iconos
estén dispuestos horizontalmente, cambiaré el tipo
del nodo padre para que sea un contenedor de caja
horizontal. Esto organiza todos los nodos
secundarios automáticamente. Se están estirando para llenar la altura vertical del contenedor de caja
horizontal, que tiene el
tamaño predeterminado de 40 píxeles. Restablecer este valor lo
obligará a colapsar a la altura
del niño más grande Me gustaría que
estuvieran más cerca,
así que bajo el tema anula las constantes de
sección, estableceré la separación en ocho
píxeles negativos Agregar más iconos
a este contador es tan simple como duplicar
el nodo hijo Es una buena idea diseñar tus elementos de HUD con sus límites
máximos en mente Entonces tendré nueve íconos de salud, que es la cantidad máxima que
planeo incluir en mi juego. Al seleccionar cualquiera de
los nodos hijos, sus valores de posición
ya no se pueden editar manualmente, ya que el nodo contenedor es ahora el encargado de controlar
su posición. Así que ten en cuenta esta limitación. Si quisieras animar las posiciones de estas
texturas individualmente, no
podrías hacerlo mientras están dentro de un
contenedor padre A continuación, agregaré otro
nodo destrozado de
textura para dibujar el medidor mágico del
personaje A continuación, rellene su propiedad de
textura con el activo desde
la pestaña del sistema de archivos Si bien esta textura no es
funcional como un medidor real, ayuda a dibujar todo lo que quieras incluir en
tu capucha para tener una idea de cómo quieres que
se presente antes de
entrar en implementación. Al igual que los íconos de salud, quiero ver cómo este medidor
mágico encajará en mi diseño cuando esté
en su límite máximo. Estirar esta imagen para
hacer que el calibre sea más largo estira los píxeles individuales de la imagen, lo que se ve mal. Nos ocuparemos de esto en el
siguiente video, pero por ahora, solo
necesitamos una idea de cuán grande o pequeño puede ser el medidor
mágico. Es posible que desee tomarse
un tiempo para obtener el diseño de los elementos de su cabaña con el
aspecto que desee. Este diseño se ve bien. Pero cuando ejecuto mi juego,
es muy pequeño y no coincide con la densidad
de píxeles del resto del juego. Como estoy usando un zoom de
cámara de dos, todos mis píxeles se
duplican en tamaño. Entonces estableceré la escala de
mi nodo vital en dos, duplicando los tamaños de
todos sus hijos Esto es más fácil de leer y coincide mejor con la estética
de mi juego. Cambiando los presets
de anclaje del nodo padre vitals, podemos
cambiarlo fácilmente para definir su posición relativa
a cualquier esquina de la pantalla o al
centro de cualquier borde O el centro de la
pantalla como el mapa. Luego puedes ajustar
las posiciones de los nodos secundarios en
relación con el padre anclado, y ellos conservarán
sus posiciones relativas incluso si decides cambiar
la resolución de tu juego Mantendré el mío en la esquina
superior izquierda y
le daré 20 pixeles de relleno desde
el borde de la ventana. Ahora tenemos algunas texturas
dibujadas en la pantalla frontal, pero en realidad aún no están
haciendo nada. Te veré en el siguiente video.
37. Calibre 5-2: Hola, amigos. En este video, implementaremos el
medidor mágico mediante el uso de cajas de estilo. Empecemos por cambiar el
tipo del nodo del medidor mágico. Hay un
nodo de control que hace exactamente lo que necesitamos
una barra de progreso. Cambiar el tipo
elimina la textura. La barra de progreso se dibuja como un rectángulo
gris semitransparente, y tiene un porcentaje
mostrado en el texto. No quiero esta etiqueta
porcentual, así que la deshabilitaré
en el inspector. La palanca indeterminada
no es aplicable a un medidor, sino que está destinada a barras de progreso que en realidad no
miden ningún Después de establecer los valores mínimo
y máximo para nuestro medidor mágico, podemos establecer el
valor
en cualquier número intermedio para ver cómo se llena la barra de
progreso. El valor del paso es el más pequeño
que el valor puede incrementar, obligándolo a ajustar
al paso más cercano Las otras propiedades
heredadas del rango no son realmente apropiadas para
un medidor y pueden ignorarse. También podemos cambiar la
dirección en
la que se
llenará la barra de progreso si queremos. Voy a dejar el mío como de principio a fin. El aspecto de la barra de progreso
está determinado por el tema. Como aún no tenemos un tema, está usando el
tema predeterminado proporcionado por Godot Si solo queremos cambiar el tema para este
nodo por sí mismo, podemos ampliar la sección de
anulaciones de tema Como no estoy usando la visualización de texto
porcentual, los colores, constantes, fuentes y tamaños de fuente
son irrelevantes Pero puedes
usarlos para alterar cómo se escribe
la fuente en tu barra de
progreso si quieres. Debajo de la sección de estilos
es donde podemos encontrar los cuadros de estilo para cómo dibujan
el fondo
y el relleno de las barras de progreso. Al hacer clic en el menú desplegable, podemos seleccionar el cuadro de estilo vacío, que simplemente no dibujará nada. Estilo de línea de caja para dibujar
solo una línea simple, estilo cuadro plano para dibujar un rectángulo simple o textura de caja de
estilo para usar
un activo de textura importado. Al hacer clic en la textura de la caja de
estilo para expandir sus propiedades, podemos rellenar la propiedad de
textura con un activo desde
la pestaña del sistema de archivos Si cambiamos el tamaño
de la barra de progreso, la textura se
estirará para llenar el espacio, lo que no se ve muy bien. Los cuadros de estilo tienen más propiedades para alterar la forma en que
se dibujará la imagen cuando se estira. Los márgenes de textura
convertirán la textura
en una rebanada de nueve,
rebanando la imagen dos veces horizontalmente y
dos veces verticalmente, por lo que se
divide en nueve segmentos No se estirarán las esquinas. Los bordes se estirarán en una
sola dirección para
conectar las esquinas, y el medio
se estirará en ambas direcciones para llenar el
resto del espacio. O podemos alternar
el dibujo del centro de la textura
y dibujar solo los bordes. Si no desea
que se estiren los segmentos individuales, las propiedades de estiramiento del eje
darán la opción de
usar el mosaico en su lugar, o la opción de ajuste de mosaico
utilizará una combinación de mosaico y estiramiento para adaptarse
mejor al espacio asignado Expandir márgenes
dibujará la textura más allá del rectángulo definido por la posición y tamaño de los nodos. puede usar una subregión para dibujar una región
de una hoja de sprites Modulate funciona igual que lo hace con la visibilidad
del elemento Canvas, multiplicando el color de
cada píxel por Los márgenes de contenido son para cuadros de
estilo utilizados para
dibujar nodos contenedores, por lo que no serán
aplicables aquí. Agregar otra textura
de cuadro de estilo para el relleno de barras de progreso y rellenarlo con
la textura adecuada Si no desea ingresar los
valores de región de textura manualmente, también se puede
usar
el
editor de subregiones para editar visualmente
los márgenes de textura. Usando estos activos, el medidor mágico no está destinado
a estirarse verticalmente. Voy a establecer su altura
para que sea la misma que la de los activos en 16 píxeles. Pero usando las cajas de estilo, el calibre se puede estirar tanto
como sea necesario horizontalmente, y se dibujará sin
estirar los píxeles. El valor también se puede editar
y la textura de relleno
también se estirará tanto como sea necesario sin que se estiren los extremos de la
barra. Si quisiéramos que
estos cuadros de estilo se aplicaran a más
de una barra de progreso, podemos hacerlo
automático editando el tema en lugar de
usar anulaciones de tema Seleccionando el nodo HUD luego
expandiendo la sección de tema, podemos crear un nuevo tema
desde el menú desplegable. Al hacer clic en el
recurso temático se abrirá el panel temático en la
parte inferior de la ventana del editor. Aquí podemos ver la mayoría de los nodos de
control que Godot tiene para ofrecer y cómo están siendo
dibujados
actualmente por el tema, incluyendo una barra de progreso aquí Al hacer clic en el botón Más, podemos agregar la barra de progreso a
este tema y anular sus propiedades de tema de
la misma manera que lo hicimos desde el inspector para
el nodo de la barra de progreso. Todas las mismas
propiedades del tema están aquí para colores, constantes, fuentes,
tamaños de fuente y estilos Si hacemos clic en los botones más junto al fondo y
rellenamos, podemos agregar cuadros de estilo a este tema para
la barra de progreso. Como ya creamos
estos cuadros de estilo, podemos seleccionar el nodo de barra de
progreso. Luego haga clic y arrastre los recursos
del cuadro de
estilo del inspector
al editor de temas. La barra de progreso en
la vista previa del tema se actualiza para usar
los cuadros de estilo. Ahora cada barra de progreso que hereda del
nodo HUD heredará este tema y utilizará estos cuadros de estilo para dibujar la barra de
progreso automáticamente Esto nos da la
opción de tener todos los nodos de control del
mismo tipo dibujados de la misma manera o usar sobrescrituras de tema para dibujar
nodos de control individuales de manera diferente Podemos eliminar las anulaciones de
tema nodo
de la barra de progreso ya que estos cuadros de estilo ahora
se heredan
del tema de HUDs Si quieres usar
este tema para todo
tu proyecto sin necesidad de copiarlo
en cada escena, puedes guardarlo como
recurso del proyecto. Luego en la configuración del proyecto, bajo el tema GUI, podemos establecer un tema personalizado seleccionando
el recurso de tema guardado. Esto requerirá reiniciar
el editor para que surta efecto. Ahora, cada barra de progreso en cada escena de
todo el proyecto se
dibujará de la misma manera. Pero imaginemos
que quieres tener múltiples medidores mágicos que usen estas cajas de estilo y varias otras barras de progreso
que usen otras cajas de estilo En lugar de tener
múltiples temas, podemos usar variaciones de
tipo de tema. Al hacer clic en el botón Más, podemos escribir un
nombre personalizado para agregar
al tema como Magic gauge. Después haz clic en el botón Herramientas
y dale un tipo base de barra de progreso ya sea
escribiéndola o
seleccionándola de la lista. Ahora las otras pestañas contienen
las propiedades heredadas
de la Barra de Progreso, y podemos cambiar los valores
de los cuadros de fondo y estilo de
relleno. Copiaré las cajas
de estilo de mi nodo de medidor mágico, luego haré clic en el icono del eslabón de la
cadena para desvincularlas de
donde fueron copiadas Cambiando a las propiedades del tema de la
barra de progreso, eliminaré los cuadros de estilo, volviendo todo
al tema predeterminado Después seleccionando el nodo de
medidor mágico en el árbol de escenas, expandiendo la
sección temática en el inspector. Puedo seleccionar el medidor mágico
en la variación de tipo para decirles que usen las propiedades del tema
para el medidor mágico. Ahora mi juego puede tener
múltiples medidores mágicos si
necesito sin tener que configurar
los estilos para cada uno
de ellos individualmente. Solo necesito decirle al tema que
use las propiedades del
tema del medidor mágico, y todavía puedo tener
otras barras de progreso en mi juego que
no sean medidores mágicos,
que también se pueden dibujar usando
diferentes estilos Ahora tenemos un medidor mágico
simple, pero aún necesitamos
implementar el contador de salud. Te veré en el siguiente video.
38. 5-3 Icono: Hola, amigos. En este video, crearemos un ícono de
salud que tenga animaciones para
cuando el personaje recupere o pierda la salud Actualmente tenemos los iconos de
salud mostrados como nodos destrozados de
textura organizados horizontalmente por el nodo contenedor
de caja horizontal Si quisieras
animarlos como sprites, podrías pensar en cambiarlos a Sprite
Animado dos nodos D. Pero mezclar nodos de control con dos nodos D causa problemas. Rápidamente configuraré el
recurso de fotogramas de Sprite de Animación para poder demostrarlo Dos nodos D no se
comportarán como nodos de control. No anclarán
sus posiciones relación con sus padres ni serán organizados por nodos contenedores o redimensionarán automáticamente para
ajustarse a la resolución de la ventana En lugar de cambiar el
tipo de nodo que estamos usando, necesitaremos animar este nodo wret de
textura tal como es Si ampliamos el desplegable de
propiedades de textura, podemos ver que hay una opción de textura
animada Este recurso de textura animada solo
puede contener una
sola animación, ya, realmente no se
ajusta a nuestras necesidades en este caso. Si quisiéramos usar esto
para animar el icono, necesitaríamos establecer cada fotograma
individual de
la animación como
una textura de atlas separada con
una duración en segundos a través de
esta interfaz torpe Y después de todo eso,
necesitaríamos usar un script personalizado para controlar qué fotogramas de la animación
se están utilizando de todos modos. Si quisiéramos tener
la misma textura, reproducir múltiples animaciones. Por lo que sería mejor dejar esta propiedad de textura
como una textura atlas. Si bien podríamos escribir un script
personalizado para cambiar el valor de la
propiedad region de esta textura de atlas, la cantidad de tiempo y esfuerzo que tomaría realmente no valdría la pena cuando ya existe el nodo Animation Player. Entonces, solo agreguemos un nodo de
Animation Player como hijo de este ícono de salud. Antes de hacer alguna animación, sería una buena idea guardar primero
este icono como escena
propia. Esto encapsulará el nodo
Animation Player, ya que no es realmente relevante para el contexto del
HUD del juego En esta escena, primero, estableceré la
región de los iconos a lo que quiero usar como su estado predeterminado,
que estará vacío. Luego crea una nueva animación
para cuando este ícono se llene,
configurando la velocidad
de fotogramas en 12 fotogramas por segundo, ajustando el Zoom y
activando el ajuste de fotogramas Luego voy a marcar
esto para el inicio de la animación y agregaré
esto a la pista de reinicio. Aunque no quiero usar esto como el primer fotograma
de la animación, ahora
es el estado predeterminado que usa la animación de
reinicio. A continuación, sobrescribiré
la primera clave de mi animación de relleno con
el primer fotograma real Después continúe con el resto de los marcos llenando el icono. Voy a establecer la duración de la
animación en ocho fotogramas. Recuerda cambiar
el modo de actualización a discreto cuando uses animaciones de
fotogramas como esta. Eso se ve bien, así que lo
duplicaré y
haré otra animación para cuando el personaje sufra daños, lo que vaciará el icono. Como sé que mis
sprites de hojas de sprites están todos espaciados uniformemente, simplemente
puedo editar los valores de región
con claves por múltiplos de 32 píxeles para
obtener los fotogramas que Esta animación es más corta
con solo seis fotogramas. Es importante que estas
animaciones terminen con el frame que será
persistente después de que terminen. Una vez que se reproduce esta animación vacía, el icono permanecerá vacío hasta que se reproduzca la
animación de relleno. Asimismo, después de que se reproduzca la animación de
relleno, el icono permanecerá lleno
hasta que se reproduzca la animación vacía. Adjuntar un script
al nodo raíz del icono de salud y guardarlo en una nueva
carpeta para los scripts de la interfaz de usuario. Supondremos que este
script se puede usar para cualquier icono animado en caso de que queramos usarlo para
algo que no sea salud. Este script solo necesita obtener una referencia al
nodo
Animation Player cuando esté listo. Luego proporcionar funciones públicas para reproducir cada una de las
animaciones cuando sea necesario. De vuelta a la escena del juego, podemos eliminar todos los
demás íconos de salud. Cambiaré el nombre de este primero
a ícono de Salud uno, luego lo duplicaré ocho
veces para recrear el resto de ellos con el Reproductor de
Animación y
guión adjunto Si queremos probar esto, podemos usar el
guión del jugador para decirle
al ícono de salud que llene
o vacíe con una pulsación de tecla Al presionar el botón Ejecutar, usaré la ruta del
nodo anotado con el
signo de dólar para decirle a este
primer ícono de salud que debe llenar Cuando suelte el botón Ejecutar, haré lo mismo
para decirle que se vacíe. Ya que esto es solo
para fines de prueba, no
necesito importarme lo
ineficiente que es este código Ejecutar el juego,
presionar el botón Ejecutar, llena todos los iconos, aunque solo le dije
al primero que llenara. Esto se debe a que Godot naturalmente trata de ser lo más eficiente
posible en
recursos y ha creado solo un recurso de textura atlas para ser utilizado para todos los iconos Entonces, cuando animamos un icono, todos los íconos están
usando la misma textura, por lo que todos están animados En la escena del ícono de salud, podemos anular este comportamiento
expandiendo el
recurso de textura del atlas en el inspector. En la sección de recursos, active la opción local
a escena. Esto le dirá a Godot que cada instancia de
la escena necesitará su propia copia única de
este recurso de textura de atlas
con su propia propiedad de región Esta hoja de sprites seguirá
siendo compartida por todos los iconos, pero qué región de
la hoja de sprites dibujan será única Ejecutando el juego otra vez. Esta
vez solo se
llena el primer icono cuando presiono
el botón de ejecución y se vacía cuando
suelto el botón Con la prueba exitosa, podemos eliminar o comentar
las líneas adicionales de código. Ahora tenemos íconos animados de
salud, pero el contador de salud
en realidad no cuenta la salud de nuestro
personaje. Te veré en el siguiente video.
39. Contador de 5-4: Hola, amigos. En este video, escribiremos un
guión que gestione los íconos animados para reflejar un valor y
un valor máximo. Aquí tenemos nuestros íconos animados, pero necesitamos adjuntar un guión al nodo padre
que controlará cómo y cuándo se animan para reflejar el conteo de la salud del personaje del
jugador Nombraré este contador de iconos y lo pondré en la carpeta de scripts de
UI. No hay nada
en este script específicamente usando las características del contenedor de caja horizontal, así que extenderé el tipo de
control
más genérico para permitir cambiar el tipo de este nodo
más adelante si quiero. El guión
necesitará dos enteros, uno para la salud
máxima del personaje y otro para su salud
actual Como quiero que este script sea útil para
contar cualquier cosa, no solo salud, usaré
el término genérico valor. Por ahora, podemos establecer
el valor predeterminado de salud máxima para que sea igual al número de hijos tiene
este nodo usando
la etiqueta on ready. A continuación, necesitaremos dos funciones
públicas que establecerán ambos
valores, aceptando un parámetro entero y anulando el
valor antiguo con el nuevo Cuando tengamos a nuestro personaje
jugador tomando daño y
recuperando la salud, podremos llamar a
estas funciones públicas para comunicar los
cambios de valor de salud al jugador. Será responsabilidad de este script controlar
cuántos iconos se muestran y cuáles se llenan o
vacian en
función de los valores de estos enteros y
cómo cambian Empezaremos por establecer el valor de su salud
actual. Lo primero que debemos hacer
es validar que el número nos están dando para establecer el
valor sea un número válido. No podemos mostrar al personaje tenga menos de cero salud, ni nada
mayor que el número de iconos
disponibles,
su salud máxima. Entonces primero estableceremos el
valor al retorno del entero
clamp entre
cero y max health. Si intentamos llamar a esta función
con un número negativo, su lugar establecerá
la salud en cero. Y de igual manera, cualquier cosa por encima del máximo
se limitará al máximo. A continuación, si estamos estableciendo el valor en el mismo
número que ya es, no
deberíamos tener que
hacer nada, así que podríamos simplemente regresar
de esta función. Una vez que hayamos establecido que
estamos cambiando el valor que muestra
este contador de iconos a un nuevo número válido, el proceso diferirá si el número aumenta
o disminuye. Si el nuevo valor es
mayor que el valor anterior, le
diremos algunos de
los íconos para llenar. Pero, ¿qué íconos? Los iconos
son convenientemente dibujados por el contenedor de caja horizontal en el mismo orden que su
índice hijo en el árbol de escena. Usando un simple bucle de cuatro, usando I como índice, podemos contar a través del
rango de valor a nuevo valor. Range devuelve una matriz
que contiene la secuencia de números enteros contando
desde el primer número
hasta el segundo, pero excluye el segundo Entonces, si el valor antiguo era uno
y el nuevo valor es cuatro, esto nos dará los
números uno, dos y tres. Dado que el índice hijo
del primer hijo es cero, no uno, esto se alinea perfectamente con los índices de los iconos
que necesitan ser llenados. Entonces obtendremos el nodo hijo en el Índice I y le diremos que llene. El proceso para disminuir
el valor es muy similar. Sólo como sabemos que el nuevo valor es
menor que el valor anterior, necesitamos proporcionar
un argumento extra a la función range, uno
negativo, que
le dirá que cuente atrás. Si el valor antiguo era cuatro
y el nuevo valor es uno, range devolverá 43 y dos. Estos no son los
mismos que los
índices hijos de los íconos,
sino que son uno mayor. Entonces podemos arreglar esto
restando uno de I en función get child y
decirle a estos íconos Sólo después de que todo esto esté hecho, ¿establecemos el valor antiguo
al nuevo valor? Podemos
probar esto sin agregar scripts
adicionales
o asignaciones de entrada Todo lo que tenemos que hacer es agregar una función de
entrada al script. Primero, verificaremos si
el evento de entrada fue una tecla de evento de entrada y si el evento fue
una tecla presionada. Luego usa una declaración de coincidencia
en el coode clave del evento. Si la tecla que se
presionó era alguna de las teclas numéricos, podemos establecer el
valor del contador de iconos en ese número. Declarando una
variable numérica como un entero, podemos calcular el número
que se presionó simplemente restando la clave cero
del código clave de eventos Esto funciona porque los
coodes clave son una enumeración,
una simple Cualquiera que sea el código clave
para la clave cero, el código clave para la clave
siete va a ser el coode clave para la
clave cero Podemos imprimir una declaración
que diga algo así como establecer la salud
actual dos más el
número convertido en una cadena. Luego llame a la
función de valor establecido pasando el número. Si ejecutamos el juego, al presionar
cualquier tecla numérica se establecerá
el contador de iconos ese número y se animarán los iconos de acuerdo a si se
están
llenando o vaciando Y podemos hacer lo mismo para establecer el valor máximo también. Si bien ya podríamos tener el número
máximo de iconos en la escena y simplemente
ocultar los que no estamos usando, sería más escalable
instanciar nuevos iconos
según los necesitemos Como esto no
sucede muy a menudo, no afectará el rendimiento
y se acomodará agregando tantas más como necesitemos si
decidimos que queremos
contratar al máximo más tarde. Así que exportaremos una
variable para mantener la escena del icono como
una escena repleta. Copiar el contenido de
la función de valor establecido. Después de cambiar cada instancia
de valor a valor máximo, solo
hay algunos
cambios más que deben realizarse. Primero, no podemos validar el valor máximo
basándonos en sí mismo. Así que tendremos que establecer algún límite a qué tan alto puede ser el
valor máximo. Es posible que desee exportar este límite en lugar de
codificar un valor. En lugar de llenar iconos, estaremos instanciando nuevos íconos y agregándolos como niños. Y en lugar de vaciar íconos, los
estaremos retirando
del árbol de escenas llamando gratis Para probar esto, usaré el mismo sistema de entrada de
tecla numérica, pero requiero que mantenga presionada la flecha hacia arriba para establecer
el valor máximo. Entonces, si
se presiona la acción de punto de entrada, buscaré, entonces imprimiré Max
Health y estableceré ese valor en su lugar y colocaré la
parte de salud actual en el bloque else. ejecutar el juego, puedo cambiar el
valor máximo de salud manteniendo presionada la flecha hacia arriba y presionando
cualquiera de las
teclas numéricos y soltando la flecha hacia arriba, todavía
puedo cambiar el valor
actual salud, también. Recuerde comentar la función de
entrada después de la prueba. Ahora tenemos un contador de
iconos animados que puede hacer un
seguimiento de los personajes del jugador máximo y los valores de
salud actuales. Pero ni el contador de
iconos de salud ni el medidor mágico están realmente conectados con el personaje
del jugador. Te veré en el siguiente video.
40. Caja de 5 a 5 heridos: Hola, amigos. En este video, le
daremos al personaje
algo de salud para que se conecte con el contador de iconos de
salud. Podríamos agregar variables de salud al guión
del personaje
y rastrearlo de esa manera. Esto permitiría que
cada personaje de nuestro juego tenga salud
sin ningún trabajo extra. Pero si consideramos
que las cosas que
no son personajes también pueden
necesitar tener salud, como
paredes rompibles, por ejemplo, esto se vuelve menos beneficioso, sobre todo porque nuestro
personaje es un personaje cuerpo dos D y el
Muro rompible sería un cuerpo estático dos D. Y tal vez tengamos otro cuerpo rígido
a D que también necesita Tendríamos que tener
las mismas variables y funciones en múltiples scripts
para cada uno de estos casos. Podríamos reescribir nuestro guión de
personaje para heredar del cuerpo
físico dos D, todo en nuestro
juego que necesite salud también puede usar este Pero hay muchas cosas
en este script que no
serían aplicables
a estos otros objetos. Sería derrochador
tener todas estas variables y
funciones unidas a una pared rompible
que nunca
necesitaría utilizarlas y así mismo,
tener las variables y funciones destinadas un muro rompible unidas
a En casos como este, es posible que desee usar el
patrón compuesto en lugar herencia orientada a
objetos para reutilizar sus scripts en
su proyecto de juego. Al crear un componente de salud, puede existir independientemente
de lo que esté apegado. Los personajes pueden tener un componente de
salud y las paredes
rompibles también pueden tener
un componente de salud En la escena del personaje,
agregaremos un nuevo hijo, un nodo Área dos D, y lo nombraremos Caja de daño. Luego agrega un nodo TD de
forma de colisión como hijo de la
Caja de Daño para definir su forma. Esta será la zona
en el personaje aéreo donde si son
golpeados, recibirán daños. Es posible que no siempre
quieras que esta sea la
misma que la forma de colisión
del cuerpo de su personaje. Además,
generalmente siempre querrás que la
colisión del cuerpo del personaje permanezca activa, mientras que la Caja de Daño a menudo
se desactivará para evitar que el personaje
reciba daño mientras esquiva o durante
escenas de corte, por ejemplo Por lo tanto, ayuda
darle a tu Caja de Hurt un área de colisión separada. Voy a hacer la mía también una cápsula, pero un poco más pequeña que
el cuerpo del personaje y pondré su color de depuración en
verde para poder
diferenciarlos más fácilmente. Esta zona no necesita ser responsable de
monitorear nada. Solo necesita ser monitoreable para que los hit boxes puedan detectarlo Ampliando la sección colisión
bajo colisión Objeto dos D, podemos establecer esto para que esté en la capa diez y quitar su
máscara por completo. En la configuración del proyecto, voy a dar a dos D Physics layer ten el nombre del jugador Hurt Box. Ahora bien, cualquier cosa en el juego
que sea tanto de monitoreo como enmascaramiento de la capa diez
podrá lastimar al personaje
del jugador. Adjuntando un script a este nodo, lo
llamaré Hurt Box. Este script necesitará
los mismos valores máximos de salud y salud actuales
que tiene el contador de iconos. Como voy a estar indicando el valor de
salud con iconos, estos tendrán que ser enteros. Si estás usando un medidor para la salud de
tu personaje, tienes la opción de
usar flotadores en su lugar ya que un medidor puede
indicar valores decimales Por ahora, solo estableceré la salud
máxima en cinco y usaré la etiqueta “on ready” para establecer la
salud actual en Max Health. A diferencia del script de contador de iconos, la principal forma en la que una Caja de Daño estará modificando el valor de salud
actual
será recibiendo
daños por caja de impacto
o recuperando la salud. Por lo que estas serán nuestras funciones
públicas, ambas
aceptarán una cantidad de salud para perder o
ganar como un entero. Al recibir daño, simplemente
restaremos cantidad de la salud actual del
personaje Entonces podemos usar la función max para devolver
este valor o cero, lo que sea mayor, y
establecerlo como el nuevo
valor de la salud actual Esto evitará que su salud llegue alguna vez por debajo de cero. Podemos hacer que la función de
recuperación sea
multiuso dando al
parámetro un valor predeterminado. Si llamamos a esta
función de recuperación sin argumentos, asumiremos que eso significa que
deben recuperar toda
su salud hasta su máximo
ajuste de su salud hasta su máximo salud actual a salud máxima. Si se le dio un argumento
a la función de recuperación, entonces agregue esa cantidad a la salud
actual del personaje y use la función MIN
para devolver este resultado o Max health,
lo que sea menor Por lo que la salud actual nunca
superará la salud máxima. En ambos casos,
se está cambiando el valor de la salud actual y necesitamos que este cambio sea reflejado por el
contador de iconos en el HUD Pero el Hurt Box está en la escena del personaje y el contador de iconos está
en la escena del juego. En la mayoría de los casos,
siempre que necesites
comunicar información entre nodos y
diferentes escenas, la mejor manera será usar señales y
formar su conexión
a través su ancestro común más cercano En la escena del juego, el ancestro común más cercano
entre el personaje y el contador de salud
es el nodo
raíz de escenas del juego , el administrador del juego Vamos a darle un nombre único al
contador de salud. Entonces agarra una referencia a ello
en el guión del manager del juego. Podríamos intentar decirle
al contador de salud que monitoree la Caja Hurtada del
personaje. Podemos usar la función Get node para recuperar la caja de daño del
personaje. Pero entonces nuestro
script de contador de iconos estará confiando en ciertas funciones o variables existentes en la entidad
que está monitoreando. Por lo que esencialmente solo
sería útil como contador de salud, que no es reutilizable
como guión para contar
otras cosas. revertir esta lógica,
sería mejor decirle a la Caja Hurtada que sea monitoreada
por ese contador de iconos. Entonces llama a una función que
aún no hemos escrito como set counter y
pásalo el contador de salud
como argumento. Ten en cuenta que esta función get node fallará
si cambias el nombre de tu nodo Hurt Box o
reorganizas la estructura de tu árbol de escenas para que ya
no sea un hijo directo Prefiero esta dependencia a
escribir una nueva función en el script de caracteres para recuperar el nodo Hurt Box ya que ese script
ya es bastante largo. De vuelta en el script de Hurt Box, escribiremos esta nueva función, aceptando un contador de iconos como
parámetro de control de tipo, ya que no le dimos
un nombre de clase específico. Ahora tenemos el Hurt Box y el contador de salud
en el mismo guión, para que podamos
comunicarnos fácilmente entre ellos. Más importante aún, el script del contador de
iconos todavía se
puede usar para
lo que queramos, y cualquier Hurt Box en nuestro juego que no necesite ser
monitoreado por un contador, puede simplemente ignorar
esta función. Podríamos llamar directamente a las funciones de
contadores de iconos, pero eso daría como resultado
que cada Hurt Box en el juego
verificara constantemente si tiene
un contador de iconos monitoreándolo antes de
llamar a estas funciones. Sería mejor usar
señales para comunicar
estos cambios, una para cuando cambia la salud
máxima y otra para cuando cambia la salud
actual. Ambos necesitarán
parámetros enteros para sus nuevos valores. También podemos querer otro para
cuando la salud llegue a cero, lo que no requerirá
ningún parámetro. Ahora cuando su
salud actual cambia a
consecuencia de recibir
daño o recuperar la salud, podemos emitir esta señal pasando su nueva
salud actual como argumento. Si la salud actual es cero
después de recibir daños, debemos emitir la señal
teñida dos. Ahora cuando configuramos un contador
para monitorear esta Caja Hurtada, simplemente
podemos conectar
estas señales a los contadores de iconos
establecer funciones de valor, ya que los parámetros pasados
por las señales coinciden con
los parámetros de
las funciones de contadores de iconos tanto
en cantidad como en tipo. También sería una buena
idea emitir estas señales de
inmediato para que el contador de iconos pueda establecer sus valores para que
coincidan con la Caja de Daño. Para probar esto, podemos escribir una función de entrada simple
en este script. Si presiono hacia arriba, el personaje
recuperará una salud. Si presiono hacia abajo, el personaje
recibirá un daño, y si salto, el personaje
recuperará la salud completa. ejecutar el juego,
presionar hacia abajo el personaje recibe un
daño con cada pulsación de botón. Se ignora recibir daños a cero
salud. Al presionar hacia arriba se recupera una salud, y se
ignora la recuperación de la salud en Max. Volviendo a bajar primero a un valor
más bajo, luego
saltaré y
recuperaré completamente toda la salud. Recuerde eliminar o comentar esta función
de entrada
después de la prueba. Ahora tenemos a nuestro personaje capaz recibir daños y
recuperar la salud, pero su salud
no se está salvando. Te veré en
el siguiente video.
41. 5-6 Datos: Hola, amigos. En este video, crearemos un recurso personalizado
que puede realizar un seguimiento de las estadísticas del jugador y
progresar en el juego
entre sesiones de juego. Si queremos que el jugador pueda
obtener mejoras de salud Max, entonces manténgalas
la próxima vez que juegue. El juego necesitará una
forma de saber lo que tienen y lo que no han
encontrado en el juego. Para ello, podemos crear
nuestros propios recursos. Ya hemos estado usando varios recursos
en este proyecto, como el recurso Sprites
Atlas Texture del personaje
o el recurso de máquina de
estado del árbol de animación Y el tema. Estos
recursos son de todos los tipos definidos por el motor de
juego Godot para proporcionar funciones específicas
para los nodos que los utilizan. Pero también podemos crear las nuestras propias para satisfacer nuestras propias necesidades
específicas. Vamos a crear una nueva carpeta dentro la carpeta llamada resources. Entonces podemos crear un nuevo
script en esta carpeta llamado data en lugar de
heredar del nodo, este script
heredará del recurso Los recursos no se representan
como nodos en el árbol de escenas. Lo primero que queremos hacer
al crear un recurso personalizado es
asegurarnos de darle un nombre de clase. De lo contrario, no podremos
crear instancias del mismo. Dado que el propósito
de este recurso es realizar un seguimiento de
los datos del jugador, podemos incluir tantas
variables como necesitemos para todo lo que queramos guardado
entre sesiones de juego. Por ahora, voy a necesitar variables
para los caracteres Salud
máxima y
salud actual como enteros. También agregaré su
máxima magia
y magia actual como carrozas Todas estas variables serán de acceso
público
a otros scripts. También podemos incluir
cadenas para cosas como su nombre o booleanos para hacer un seguimiento de algo que
se enciende o Las matrices se pueden utilizar para almacenar grupos de información
relacionada, como una matriz de
booleanos para saber qué actualizaciones han sido encontradas por el jugador
y cuáles no Los diccionarios son muy útiles para almacenar clases enteras
de información, ya que podemos usar nombres de
atributos como claves en el diccionario con sus valores correspondientes. Más allá de los tipos de variables básicas, también
podemos incluir
otras clases integradas en Godot como vectores para
almacenar dos coordenadas D, colores, o incluso otras
clases personalizadas que creamos Cualquier variable que
quieras guardar entre sesiones de
juego necesitará
tener la etiqueta de exportación. Otras variables
que no tienen la etiqueta de exportación aún pueden
ser útiles si, por ejemplo, no
quieres guardar la salud actual del
personaje, solo su salud Max
e iniciar al jugador con plena salud cada
vez que carga su juego. estas
variables no exportadas seguirán permaneciendo si tu juego cambia embargo, estas
variables no exportadas seguirán permaneciendo
si tu juego cambia de
escena durante la
sesión de juego. Si tuvieras que hacer la transición fuera de la escena del juego
por algún motivo, tal vez para jugar una escena de corte, luego regresaras a la escena del
juego una vez más, estas variables
conservarán su valor. Si bien también podemos escribir funciones
en este script, no suele ser necesario. Si desea realizar alguna inicialización
automatizada
de su recurso, podemos anular
la función init. Esta función innit será
llamada automáticamente por Godot cada vez que creamos una nueva instancia de este recurso
a través de un script Así podemos darle a las variables
algunos valores predeterminados, establecer las longitudes de las matrices, o agregar algunas claves a
nuestros diccionarios. Asegúrese de guardar este script con el nombre de clase definido antes de intentar
usarlo de alguna manera. Entonces Godot reconocerá
este nombre de clase. Necesitaremos otro script para acceder a nuestro recurso personalizado, que cubriremos
en el siguiente video. Por ahora, podemos probar
nuestro recurso personalizado creando uno en
la pestaña del sistema de archivos. Hacemos clic, seleccionamos
Crear nuevo recurso,
luego tecleamos el nombre de la clase o lo
seleccionamos de la lista. Entonces dale un nombre.
Al crear este recurso lo
abriremos automáticamente
en el inspector, donde podremos ver y editar todas
nuestras variables exportadas. Al crear un recurso de esta manera no se utiliza la función nit, sino que se utilizarán los valores proporcionados para las variables asignadas en
sus declaraciones Si selecciona otra cosa y desea volver a
editar este recurso, puede hacer doble clic sobre él
en la pestaña del sistema de archivos. Voy a probar rápidamente la creación un recurso de datos en el script del administrador de
juegos. Podemos crear una
instancia de nuestro recurso declarando primero una variable con el nombre de la clase como tipo Después asigne el valor
de esta variable para que sea el nombre de clase
seguido del punto Nu. Entonces podremos acceder a cualquiera de las variables que
declaramos en esta clase, tanto exportadas como no exportadas, sobrescribir sus valores y utilizarlos según sea necesario
mientras jugamos el juego Recuerde eliminar
o comentar
este código de prueba y eliminar
el archivo de recursos de datos de prueba. Ahora tenemos un recurso de datos que incluye a nuestros personajes Max
Health y salud actual, pero aún no se está guardando. Te veré en el siguiente video.
42. Archivos de 5 a 7: Hola, amigos. En este video, guardaremos y cargaremos los datos del jugador usando
nuestro nuevo recurso personalizado. Para ello, necesitaremos
otro script que administre acceso al recurso que
creamos en el video anterior. Este script deberá ser accesible desde cualquier parte
del proyecto. El personaje necesita
conocer sus estadísticas. Los cuartos necesitarán saber si
el jugador ha abierto una puerta, encontrado una mejora o
derrotado a un jefe. Incluso la interfaz de usuario y el mapa necesitarán acceder
a los datos guardados. Podemos hacer que algunos nodos
sean fácilmente accesibles así
haciéndolos globales. Vamos a crear una nueva carpeta dentro la carpeta de scripts
llamada Globals. Después crea un nuevo script
en esta carpeta llamada file. El propósito de este
script será proporcionar un acceso rápido y fácil a los jugadores guardar datos en
cualquier otro script que escribamos a lo largo de
todo el proyecto, además de guardarlo en el sistema del reproductor
y cargarlo también. Necesitaremos una variable del
tipo de nuestro recurso personalizado. Le voy a nombrar datos
con una
D. minúscula . Entonces necesitaremos tres funciones públicas
para administrar estos datos, iniciar un nuevo juego,
guardar el juego y cargar el Empezar un nuevo juego es sencillo. Solo necesitamos establecer
el valor de los datos para que sea nuestro nombre de clase
seguido de punto neu. Esto creará una nueva instancia del recurso e inicializará Cuando estemos listos
para salvar nuestro juego, necesitaremos saber dónde
queremos guardarlo también. Para ello, declararé
una constante de cadena, ya que esto es algo
que nunca voy a cambiar, la ruta a la ubicación donde quiero guardar el archivo de datos del
jugador. Godot proporciona una taquigrafía
simple que funciona en cualquier plataforma Windows, Mac, Linux, web y consolas pueden usar esto. Usuario Colon reenvía
adelanteslash. Do reemplazará
esto automáticamente con la ruta
apropiada para la plataforma como una
ubicación que es específica tanto para el usuario
del sistema como para el juego. Declarando una variable para el nombre de
archivo también como una cadena, voy a nombrar el mío guardar seguido punto TRS corto para Ahora para guardar el juego, podemos acceder a una
clase Singleton del Godot, Ahorrador de
recursos, luego
llamada la función guardar Pasando el recurso que
queremos guardar y la ubicación en la que queremos guardarlo agregando la
ruta y el nombre del archivo Si quisiéramos tener
múltiples ranuras para guardar, todo lo que tenemos que hacer es cambiar
el nombre del archivo para cada ranura. Cargar nuestro juego es
similar a guardar. Todo lo que tenemos que hacer es usar
Godot loader Singleton. La función de carga solo requiere la ubicación del
recurso que estamos cargando. Y devuelve el recurso. Entonces lo asignaremos a
nuestra variable de datos. Como nuestro juego no
tiene una escena de título, simplemente
asumiré automáticamente que si existe un archivo guardado, querré cargarlo, o si
no inicia un juego nuevo. Entonces en la función REDI, usaré el cargador de recursos para verificar si hay un archivo de
datos para cargar, y si es así, cargarlo De lo contrario, inicia un nuevo juego. Incluso con una escena de título, es útil poder comenzar tu juego directamente
desde la escena del juego sin tener que
pasar por la pantalla de título cada vez mientras estás
desarrollando y probando. Tenemos nuestro recurso de datos aquí. Podemos crearlo,
guardarlo y cargarlo. Ahora todo lo que tenemos que hacer
es hacer que este script sea fácil de acceder desde
cualquier lugar de nuestro proyecto. Al abrir la configuración del proyecto, cambie a la pestaña Globales. Da clic en el botón de carpeta
para abrir un navegador y navegar hasta el script de archivo que
acabamos de crear. Luego haz clic en Abrir. Podemos proporcionar un nombre
diferente para este nodo global si queremos
o usar el proporcionado. Después haga clic en agregar para agregar el script a la
lista de nodos globales. Ahora, cualquier script que escribamos puede acceder a este script de archivo
con solo su nombre. De la misma manera
hemos estado usando los singletons input, resource saver y resource
loader Para probar esto, estableceré la
salud máxima del personaje para que coincida con lo que hay en el Safle en lugar de configurarlo en la
parte superior del guión Entonces agregaré una función
inicializada a este script después de aceptar
un nuevo parámetro de valor Max, configurando el antiguo valor máximo
al nuevo valor máximo. Entonces el valor actual
al valor máximo, emitiré ambas señales cambiadas. Ahora el administrador del juego
después de obtener la Caja de Hurto del personaje puede inicializarla con el valor máximo de salud
del archivo de datos del jugador También agregaré una función de entrada, que al presionar las teclas de flecha
arriba o abajo aumentará o disminuirá
la salud
máxima del personaje en
el archivo de datos y
volverá la salud
máxima del personaje en a inicializar
la Caja de Daño para que coincida Entonces guarda el juego
llamando a file dot save game. Voy a necesitar invertir
el orden de estas operaciones para mostrar
los valores correctos. ejecutar el juego, el personaje comienza con cinco Max Health, pero puedo cambiar este valor
presionando las teclas de flecha arriba o
abajo. Entonces cerraré el
juego y lo ejecutaré nuevo para ver que
su salud Max se
ha guardado y cargado. Para encontrar el archivo de datos que
guardamos en el menú del proyecto, seleccione Abrir carpeta de datos de usuario. Esto abrirá una ventana del navegador de
archivos, y podremos ver nuestro archivo DotTRS
guardado Haga clic derecho sobre este archivo y
ábralo usando cualquier editor de texto. Podemos ver que solo se salvó la salud
máxima. Godot realiza un seguimiento de qué
variables son utilizadas por el juego y solo guardará las variables que
realmente usamos y modificamos Así que ten esto en mente. De hecho, podemos editar este archivo aquí, y el juego
realmente lo cargará con los valores editados
siempre que el formato coincida. Esto es genial para nosotros mientras estamos construyendo y
probando nuestro juego. Pero tal vez no quieras
dejar que tus jugadores editen
fácilmente su archivo seguro
cuando estés listo para publicar. En el script del archivo,
simplemente cambie la extensión TRS en el nombre del
archivo a punto RES. En lugar de un recurso de texto, este ahora se guardará
como un recurso binario, que no se puede abrir y
editar en un editor de texto. Ejecutando el juego de nuevo, voy a abrir el
archivo guardar puntos que acabo de crear. Esto ahora es imposible
para mí de editar. Ahora tenemos la capacidad de
guardar y cargar datos sobre el
progreso del jugador a través de nuestro juego. En la siguiente sección, agregaremos nuestras habilidades
desbloqueables Te veré en
la siguiente sección.
43. 6-1 doble salto: Hola, amigos. En este video, le
daremos a nuestro personaje
la posibilidad de doble salto. Si bien muchos personajes
de nuestro juego pueden necesitar la habilidad de caminar, correr, saltar y caer, las habilidades
desbloqueables suelen ser exclusivas del personaje
del jugador En el
guión del personaje, en lugar de
agregar más variables y
funciones a este script, que ya es bastante largo, podemos crear un nuevo guión que solo
será utilizado por
el personaje del jugador. Asegúrate de que el guión de tu
personaje tenga un nombre de clase y esté
guardado antes de continuar. En la escena del personaje, haga clic
derecho en el nodo raíz del
personaje y seleccione adjuntar guión. En lugar de heredar
de CharacterBody dos D, podemos heredar del nombre de clase
de nuestro carácter
de guión original Entonces dale
un nombre a este nuevo script y guárdalo en
la carpeta correspondiente. Dado que este nuevo script
hereda del carácter, tiene acceso a todas
las mismas variables y funciones que creamos para esa clase, y todos los valores para
las variables exportadas y conexiones de
señal también se copian a este nuevo script Pero ahora podemos agregar más que sólo
son útiles para
el personaje jugador. Siguiendo este patrón
de herencia, personaje se llama
la superclase y nuestro personaje jugador
es una subclase Primero, necesitaremos una variable
que nos diga si
este personaje ha desbloqueado o no la capacidad de doble salto. Y para limitar
al personaje a solo
doble salto una vez, necesitaremos otra variable para saber si su doble
salto está listo. También podría ayudar tener
una señal para emitir cuando realizamos con éxito
un doble salto para dibujar un
efecto de partícula si quieres, igual que hicimos
con el otro salto. Dado que el salto doble generalmente usa el
mismo botón que el salto normal, no
necesitamos hacer ningún
trabajo adicional con el mapa de entrada en la configuración del proyecto o editar el script del reproductor para
llamar a ninguna nueva función. Simplemente podemos anular la declaración de la función
Jump. Al anular una declaración de
función, la firma de función
debe permanecer igual El nombre de la función,
sus parámetros, cantidad, orden y tipos, así
como el tipo de retorno. Dado que la función de
salto original en el script de caracteres
no aceptó parámetros y
devolvió un booleano, esta anulación de salto tampoco debe tener parámetros
y devolver un Todavía queremos que ocurra toda
la
funcionalidad original del salto. Por lo que este personaje
podrá
saltar si se cumplen
las condiciones adecuadas. Podemos acceder a las funciones de
superclase usando la palabra clave super
luego usar un punto, el nombre de la función y paréntesis tal como
llamaríamos a una
función de cualquier otra manera Dado que la
función salto de superclase devuelve un booleano, también
podemos devolver el resultado para
satisfacer el requisito
de devolver Cuando el jugador presiona
el botón de salto, el guión del jugador llamará a esta función de
salto de personaje del jugador, que luego llamará a la función de salto de personaje más genérica. Esta estructura
nos permite interceptar el proceso agregando
código extra por encima de la línea de retorno, lo que nos permite verificar si
este personaje jugador puede doble salto en respuesta
a la solicitud de saltar primero, luego solo proceder con el
comportamiento de salto predeterminado después Entonces, si este personaje jugador
puede hacer doble salto y el doble salto está listo y el personaje
no está en el suelo, entonces deberíamos
permitirle realizar un doble salto y regresar verdadero. Si alguna de estas
condiciones es falsa, entonces tenemos que proceder a verificar si este
personaje puede saltar en condiciones normales usando la función de
salto de superclase de personaje Podemos prácticamente simplemente
copiar las líneas de código que implementan un salto al
realizar un salto doble, pero emiten una señal diferente. Y tendremos que establecer el doble salto está
listo variable a caídas para evitar que el personaje
jugador realice
más
de un doble salto. En la mayoría de los juegos con
un salto doble, la capacidad de realizar
el doble salto se restablece después de
aterrizar en el suelo. Dado que la
clase de caracteres ya tiene una función a la que se llamará
cuando el personaje aterrice, también
podemos anularla. Cada vez que este personaje aterriza, si su doble
salto no está listo, podemos volver
a establecer la variable en true para que esté lista. Entonces llama a la función de
superclase. En este caso, el orden
de si queremos ejecutar la función de superclase antes
o después no importará Para probar esto, agregaré una declaración print
cuando el personaje doble salte con éxito. Y otra cuando se restablece el
doble salto. Luego establece el valor predeterminado
de C double jump a true. Ejecutando el juego, podemos presionar el botón de salto
dos veces para doble salto. Al presionarlo tres o más veces no se
producen más saltos, y la capacidad de doble salto
se restablece al aterrizar. Ahora todo lo que tenemos que hacer es bloquear y desbloquear esta capacidad
de doble salto. Entonces estableceré el valor predeterminado de C double jump back a false. En el reproductor guardar datos, voy a eliminar todas estas variables
innecesarias. Necesitaremos variables que nos digan qué habilidades ha desbloqueado el
jugador, que podemos almacenar en
una matriz de booleanos Las matrices se indexan
usando enteros, necesitaremos que
a cada una de nuestras habilidades se le asigne un
número en secuencia, comenzando desde el conteo cero
hasta actuar como sus
índices a esta Si no quieres memorizar
un montón de enteros, podemos crear una
enumeración para darle a cada entero un nombre que
nos resulte más fácil de Me gusta poner estas
enumeraciones en un guión separado llamado enums Si bien Godot nos obliga a heredar de una clase existente
al crear el script, podemos eliminar esta línea de
nuestro script después de que se Entonces dale a este script
un nombre de clase para que podamos referenciarlo
en otros scripts. Normalmente usaré
el mismo script para contener todas las enumeraciones
para todo el proyecto Podemos declarar una
enumeración usando la palabra clave num,
seguida de llaves Dentro de las llaves,
podemos escribir los nombres de
cada una de nuestras habilidades en
una lista separada por comas Ya he creado
un doble salto como mi primera habilidad desbloqueable, y voy a crear un salto de pared, un
tablero, un sombrero y
disparar un Las enumeraciones se nombran
convencionalmente en caso
Pascal mientras que las entradas de
enumeración están en mayúsculas La enumeración
asignará el valor de la primera entrada
como cero, luego uno,
dos, etc., lo que
significa que podemos usar estos como índices a nuestra
matriz con bastante facilidad Estos no necesitan
estar en el orden en que serán
desbloqueados por el jugador. El orden es arbitrario y sólo sirve para asignar a cada
habilidad un número único. Al inicializar los datos de guardado del
jugador, podemos cambiar el tamaño de la matriz para que coincida con el tamaño de
la enumeración, dándonos
automáticamente
el número correcto de booleanos y por defecto Recuerde que
las variables deben tener la etiqueta de exportación para ser guardadas. De vuelta en el guión del jugador, podemos hacer referencia a la matriz de
habilidades desbloqueadas y almacenarla en una variable
del mismo nombre usando
la etiqueta on ready. Tenga en cuenta que esto
no solo hace una copia de la matriz
en su estado actual. Crea una referencia
a la matriz, por lo que cualquier cambio afectará a ambos. Esto significa que para desbloquear una habilidad para que
el personaje la use, solo
necesitamos establecer su valor
en el recurso de guardar datos. Ahora podemos reemplazar la variable de
salto doble C con indexar la matriz de habilidades desbloqueadas con Enums dot abilities
dot Double Esta
matriz de habilidades desbloqueadas ahora se puede usar a lo largo de todo este
script para cada habilidad. En el script del administrador del juego, usaré la
función de entrada para probar desbloqueo de la capacidad de
doble salto al presionar la tecla de flecha hacia arriba Configuración de archivo punto datos
punto Habilidades desbloqueadas, índice punto enums habilidades de
punto punto Doble Saltar a verdadero Entonces podremos guardar el juego
para que esto sea permanente. Ejecutando el juego, mi
personaje no puede hacer doble salto. De vuelta en el Editor Godot, cambiaré a la pestaña
remota para ver el árbol de escenas del juego
que se está ejecutando actualmente Aquí puedo ver el
archivo nodo global, que tiene un recurso de datos. Dentro de este recurso de datos, la matriz de habilidades desbloqueadas tiene cinco booleanos, que
son todos falsos El nodo de personaje jugador también tiene una referencia
a la misma matriz. Volviendo a la simulación, presionar hacia arriba se desbloquea la capacidad de
doble salto En el árbol de escenas remotas, puedo ver que el booleano
en la matriz se estableció true tanto en el
recurso de datos como en el personaje Cerrando el juego y
ejecutándolo de nuevo. El doble salto ya está
desbloqueado desde que se salvó. Podemos eliminar las
declaraciones impresas ahora que se
confirma que el doble salto está funcionando. Ahora tenemos una capacidad de
doble salto desbloqueable, pero tenemos varias habilidades
desbloqueables más Te veré en el siguiente video.
44. 6-2 Diapositiva de pared: Hola, amigos. En este video, permitiremos que el personaje
se deslice por una pared, agregando fricción para
ralentizar su descenso. Primero, tenemos que decidir qué va a hacer
esta habilidad y
cuándo queremos que suceda. Al implementar una
nueva característica como esta, es una buena idea configurar primero
las pruebas que
quieras poder aprobar. Empezaré en la escena del contenido de la
habitación y esconderé los árboles
para poder ver mejor. Para crear una mecánica de
deslizamiento de paredes, voy a crear dos
paredes en mi habitación. Consideraré que mi mecánica
de
Wall Slide está completa cuando el
personaje pueda saltar, luego deslizarme hacia abajo por cualquiera de
las paredes a una velocidad de caída reducida. También me gustaría reproducir una animación diferente
mientras esto sucede. La diapositiva de pared debe terminar cuando el personaje
ya no está en contacto con la pared si
toca el piso o
presionamos la dirección del
movimiento para alejarlo de la pared. Por lo que implementar esto será alterar la física
aérea del personaje. En el guión del personaje del jugador, anularemos el proceso de física
aérea del personaje. Entonces llama al proceso de Física
Aérea de la superclase desde el guión del personaje Aquí podemos separar nuestro código
en tres bloques separados. Cuando el personaje está
realizando una diapositiva de pared, comprobando cuándo puede comenzar a
realizar una diapositiva de pared, y en cualquier otra ocasión llamamos
el proceso de superclase
Airphysics Necesitaremos saber
cuándo el personaje está realizando una diapositiva de pared, por lo que debemos declarar esto
como una variable booleana También sería útil
exportar un flotador para usarlo como
multiplicador a la gravedad del
personaje mientras realiza una diapositiva de pared. Voy a usar el 10%. Volviendo al proceso de
física del aire, ahora
podemos ramificarnos en
función de si la
variable de deslizamiento de pared es verdadera o falsa o
no. Si el personaje
ya está deslizando la pared, podemos continuar con
el deslizamiento de pared o terminarlo dependiendo de si se cumplen
otras condiciones. Si el personaje
no es deslizamiento de pared, entonces necesitamos verificar
si pueden deslizarse de pared, y si se cumplen las condiciones para iniciar el deslizamiento de la pared, entonces hágalo. Y finalmente, si todo
esto es falso, entonces deberíamos proceder con la física aérea de la superclase
como predeterminada Escribir tu algoritmo en comentarios de pseudocódigo como este hace que sea mucho más fácil completar después y reorganizar si es necesario También hace el
resultado final ya comentado. Comencemos con
iniciar una diapositiva de pared comprobando si la
habilidad Salto de pared ha sido desbloqueada. Después añadir también la condición que este personaje
debe estar en una pared. La
clase de cuerpo de personaje proporciona esta función que actúa
igual que en el piso. También me gustaría agregar
más condiciones de que su velocidad Y debe ser
mayor o igual a cero. No quiero que el personaje
comience a deslizar la pared si
se mueve hacia arriba, y el jugador debe estar presionando la
entrada de dirección de movimiento hacia la pared. El cuerpo del personaje dos denodo también nos da otra función Consigue Wall normal. Esto devuelve un vector
apuntando lejos de la pared. Entonces, si usamos la
porción X de este vector, ésta siempre será negativa
si la pared está a
la derecha del personaje
o positiva si la pared está a la izquierda del
personaje. Comparando esto con la dirección de movimiento del
personaje, multiplicaré ambos
lados por
uno negativo y requeriré que
los resultados sean iguales. Esto no permitirá que
la dirección del movimiento sea cero. Hay varias condiciones
en esta declaración I, y no caben
dentro de mi ventana de guión. Si desea escribir las condiciones de su declaración
if en varias líneas, puede hacerlo
envolviéndolas entre paréntesis. Esto puede hacer que tu
código sea más fácil leer y depurar si
prefieres este formato. Si bien mis paredes son
perfectamente verticales, es posible que necesites usar el seno de las paredes normal X si
tus paredes están anguladas. Si todo esto es cierto, permitiré que el
personaje inicie una diapositiva de pared
configurando I deslizamiento
de pared true y tapando su velocidad Y a cero
usando la función min. Esto creará
un breve reinicio de la velocidad de caída para hacer que
el deslizamiento de la pared se sienta más lento. También imprimiré una declaración
para fines de prueba. Ahora asumiremos
que el personaje ya
está realizando
un deslizamiento de pared, y queremos anular su gravedad para
ralentizar su descenso. Simplemente agregando a la velocidad Y del
personaje, tiempos de
gravedad Delta el multiplicador de
gravedad Wall Slide, que he establecido en
10% de la gravedad normal. Pensando en esto desde
una perspectiva física, esto equivale a decir que
existe un coeficiente de fricción de 0.9 entre
el personaje y la pared. Y por último, podemos pensar en
cuándo terminar el Wall Slide. Si el personaje
ya no está en la pared o si el jugador
presiona la dirección opuesta del movimiento
alejándose de la pared. Entonces, si no está en la
pared o si la señal de dirección de movimiento es la
misma que las normales de pared X, entonces configuraré Is wall sliding false e imprimiré una declaración de que el
Wall Slide ha terminado Sería más sencillo
poner el tobogán de pared continuando como el
bloque else a esta declaración I, así que lo cortaré y pegaré aquí. Hay una condición más
que necesita terminar una diapositiva de pared cuando el
personaje toca el piso. Como ya tenemos
una función que se llama
automáticamente cuando
el personaje aterriza, simplemente
voy a agregar otra
declaración I aquí que
termina el Wall Slide. Si el personaje
es pared deslizante, establezca I pared deslizante en falso, luego imprima
otra declaración. Ayuda si estas dos
declaraciones son diferentes para que
podamos ver cuándo cada una está
sucediendo realmente durante nuestras pruebas. Esto funcionará para el teclado, pero no para un controlador ya que la dirección de movimiento puede
ser un valor decimal. Entonces tendré que aplicar
la función sign a ambas comprobaciones para trabajar
con la entrada del controlador. Lo último que
tengo que hacer es agregar una animación de Wall Slide
al reproductor de
animación del personaje. Entonces duplicaré
su animación de caminata. Cambie la posición Y de la región de la
hoja de cálculo que se esté
utilizando y elimine la pista de
pasos Agregar esta animación al recurso
de la máquina de estado. Permitiré que el personaje haga la
transición a este estado
ya sea de salto o caída si el deslizamiento de I
Muro se establece como verdadero. Luego, la transición
de un tobogán de pared a caer si el
deslizamiento de la pared se establece en caídas. O a la locomoción si
tocan el piso. En el guión del administrador del juego, cambiaré desbloqueando
el doble salto desbloquear el Wall Esto debería ser
suficiente para pasar mi prueba, así que correré el juego. El personaje
todavía puede saltar normalmente, y saltar contra la
pared no realiza un deslizamiento de pared ya que esa
habilidad aún está bloqueada. Pero presionando hacia arriba para
desbloquear el Salto de Pared, ahora si salto mientras me
muevo hacia la pared, se deslizan hacia abajo y se detienen
cuando tocan el piso. Intentando esto en la otra pared, la corredera de pared termina cuando llegan al
fondo de la pared. Y otro intento contra
la primera pared, el tobogán de pared no comienza hasta que el personaje
comienza a caer, y puedo terminar el deslizamiento de pared temprano
alejándome de la pared. El comportamiento normal de
salto del personaje
no se ve afectado al realizar
ninguna de estas acciones. Con todas las pruebas superadas, recuerde comentar
las declaraciones impresas. Ahora tenemos a nuestro personaje
capaz de realizar un Wall Slide, pero aún tenemos que
implementar el Salto de Pared. Te veré en el siguiente video.
45. 6-3 Salto de pared: Hola, amigos. En este video, permitiremos que el
personaje salte
lejos de la pared mientras
realiza un deslizamiento de pared. En el guión del personaje, ya
hemos anulado
la función de salto para hacer un doble Cuando queremos que el
personaje salte de pared, todas estas condiciones en el doble salto también
pueden ser ciertas. Por lo que primero tendremos que considerar
el Salto de Pared como una posibilidad
y descartarlo antes de verificar
el doble salto ya que las condiciones para el
Salto de Pared son más específicas. Solo tendremos que verificar si la habilidad Salto de pared se ha desbloqueado y si
el personaje está realizando actualmente
una diapositiva de pared. Si no se cumplen estas condiciones, entonces podemos verificar
si el personaje puede saltar doble en su lugar. Sin embargo, esto no
permitirá que el personaje realice un salto de pared hasta que
el Wall Slide haya comenzado, lo que está esperando hasta que
el personaje haya alcanzado la cúspide de su salto. Si quieres permitir el
salto de pared antes de iniciar la diapositiva de pared cuando la
velocidad Y del personaje es negativa, entonces también podemos agregar
más condiciones. O los personajes que realizan una diapositiva de pared o
no están en el piso
y están en una pared, y la dirección de movimiento
es hacia la pared. Con el orden de
las operaciones para la lógica, necesitamos poner el
o entre paréntesis para que se revise
antes de la primera y. Podemos usar múltiples
niveles de corchetes y sangría para establecer
visualmente el orden de las operaciones
de lógica compleja como esta para que sea más fácil de
entender si es necesario Ahora que estamos listos
para realizar un salto de pared, podemos hacer todas las mismas cosas como lo haríamos con
cualquier otro salto. Entonces devuelve true, así
el manejador de entrada sabe que esta
pulsación de botón de salto fue exitosa En cuanto a establecer la velocidad del cuerpo del
personaje, queremos que no solo suba
sino que también se aleje de la pared. Entonces, en lugar de simplemente establecer
la velocidad Y del personaje, estableceremos todo el vector de
velocidad, creando también un nuevo vector. Para la X, podemos usar las
paredes normales vector punto X, y para Y, podemos usar uno. Esto nos da un vector apuntando hacia arriba y lejos de la pared, así que tenemos la dirección
correcta. Multiplicando esto
por la fuerza de salto, obtendremos un vector con
una magnitud mayor nuestro salto normal ya el vector original ya
tenía una longitud mayor a uno Podemos normalizar este
vector de dirección si queremos, pero la forma en que funciona en este momento realmente
producirá
un mejor resultado, en mi opinión, con la altura
total del salto, más la fuerza extra que se
aplica lejos de la pared. Pero como la fuerza de salto
es un número negativo, esto invertirá
el Muro normal para apunte hacia el muro
en lugar de alejarse de él. Entonces agregaré un negativo
al frente de wallnormalt X para que sea un
doble negativo, lo que
se vuelve positivo Para animar el Salto de Pared, la máquina de estado del personaje
necesitará una transición de
Wall Slide para saltar bajo la condición de que
el personaje esté saltando Esto entra en conflicto con la
transición a la caída ya que el personaje
ya no es pared deslizante
al mismo tiempo. Por lo que la transición al
salto necesitará un valor de menor prioridad
para ser considerado primero. En lugar de que el doble salto esté listo, tendremos que establecer Is wall sliding to falls al
realizar el Salto de Pared. Si ejecutamos el juego, ya
podemos realizar el salto de pared ya que se
desbloqueó en el video anterior. Saltando contra la pared,
podemos saltar de ella. La cantidad de
velocidad lateral alejada de la pared es igual a la fuerza
vertical que se aplica. Pero como la gravedad está tirando constantemente
al personaje
hacia abajo, es mucho
menos notable que la fuerza que se
aleja de la pared, que sólo se está reduciendo
ya sea por el
control de aire del personaje o por los frenos de aire. Preferiría que
mi personaje tuviera mucha menos
fuerza lateral aplicada y pudiera regresar a la
misma pared después realizar un salto de pared y
seguir escalando hacia arriba. Esto requerirá múltiples alteraciones
diferentes de la física
para que funcione correctamente, tanto reduciendo la cantidad de fuerza
lateral que se aplica al Muro Saltar
lejos de la pared, así
como darle al
personaje más control
aéreo para poder regresar a la
pared a mayor altitud. Primero, tratemos con
la fuerza lateral. En lugar de codificar duro un valor, siempre
es mejor usar variables
exportadas para que
puedan ser retorcidas y ajustadas. Exportaré un vector dos
llamado Wall Jump force multiplicador y le daré un valor predeterminado de
negativo uno positivo. Entonces podemos multiplicar el vector de velocidad resultante por este nuevo multiplicador de
fuerza Wall Jump. Este negativo
eliminará la necesidad tener el negativo aplicado
al vector normal de pared, lo cual me parece más
intuitivo ya que
pienso en negativo como
alejado de la pared. Al multiplicar dos vectores, el resultado
será producto tanto de Xs
como del producto de ambos Con estos valores, esto funcionará igual
que lo hace actualmente. Pero como se exporta el valor, puedo cambiarlo en mi
escena de personaje a 0.5 negativo, reduciendo la velocidad X a la mitad. Si quieres darte recordatorios de cómo funcionan
tus variables, agregar un
signo de número extra frente a
un comentario encima de la declaración de la
variable
creará una punta de herramienta que se
mostrará cuando pases el
mouse sobre la
variable en el inspector Ejecutando el juego de
nuevo, mi personaje tiene toda la
fuerza ascendente del salto, pero solo la mitad de la fuerza de salto se aplica en la dirección X. Pero todavía no puedo volver a la pared en un punto más alto
para subir más alto. Para eso, voy a necesitar darle a mi personaje mucho
más control aéreo, pero no quiero que
el personaje
tenga más control aéreo
en ningún otro momento. Por lo tanto, tendré que anular el valor del control aéreo específicamente solo al
realizar un Salto de Pared, luego volverlo a
su valor normal. En las variables exportadas
para salto de pared, exportaré un nuevo flotador para control de aire
Wall Jump y lo
pondré en algo
muy alto, como cuatro. Esto hará que el personaje acelere cuatro veces
más rápido de lo que lo haría en el suelo y ocho
veces más rápido de lo que lo
harían durante un salto normal con mi control aéreo
por defecto en 0.5 También almacenaré esto en otra variable
usando la etiqueta ready. Entonces, cuando quiera ponerla de nuevo a su valor normal,
sabré qué es eso. Como no sé
si el jugador estará saltando lejos de la pared o de regreso hacia ella o cualquier otra cosa
que quiera hacer, la única forma confiable de
volver
a ajustar el control aéreo a su configuración predeterminada
sería usar un temporizador. Añadiendo un
nodo temporizador a la escena, lo
llamaré Wall Jump, le daré un nombre único, luego obtendré una referencia a él
con la etiqueta on ready two. Voy a nombrar esta anulación de control
aéreo de Wall Jump para que quede un poco más
clara en este contexto. Ahora, cuando realizamos
el Salto de Pared, podemos cambiar el valor del control
de aire a Control aire
Wall Jump e iniciar el temporizador de anulación de
control de aire Wall Jump. Seleccionando el nodo temporizador, podemos establecer su propiedad one
shot true y darle un corto
tiempo de espera. Voy a usar medio segundo. A continuación, conecte la señal de
tiempo de espera del temporizador al script. Cuando el temporizador se agota, podemos
volver a ajustar el control aéreo del
personaje a su valor predeterminado. Probando esto, está más cerca, pero todavía no puedo
subir por la pared. Entonces tendré que ajustar
mi
multiplicador de fuerza Wall Jump y los valores de
control de aire Wall Jump hasta que funcione. Ejecutando el juego de nuevo, ahora
cuando realizo un Wall Jump, mi personaje tiene
suficiente aceleración para volver a la misma
pared en un punto más alto, lo que me permite
subir por la pared. Ahora tenemos nuestro
personaje capaz de
saltar a la pared para escalar superficies
verticales. A continuación, agregaremos una habilidad
elegante
completa con marcos de
invencibilidad Te veré en el siguiente video.
46. 6-4 Guiones: Hola, amigos. En este video, le
daremos al personaje una habilidad de guión
desbloqueable Comenzando en la configuración del
proyecto, la pestaña Mapa de entrada
necesitará un botón que
se pueda usar para guiones. Usaré la tecla D o el
botón del hombro derecho en mi controlador. Entonces en el guión del jugador
en la función de entrada, si se presionó el botón del tablero, intente salpicar, y
si no tiene éxito, búfer la entrada del tablero para volver a
secar el siguiente fotograma, tal como hicimos con el salto El guión necesitará una dirección, la cual podremos obtener usando
la entrada Singleton,
obtener eje, movernos a la izquierda, movernos a la derecha Para proporcionar argumentos
a un callable, usamos la función bind, luego pasamos los argumentos
a esa función en su lugar Por lo que sería mejor llamar solo
a la función de entrada get axis una vez
y almacenar el resultado. Dado que esto
solo sucederá durante los
fotogramas cuando se presione el
botón del tablero, no
es tan malo
declarar una variable aquí. Cuando se llama a la
entrada en búfer, pasará los argumentos
enlazados. Si el guión se
presionó originalmente con el stick
izquierdo inclinado, se almacenará en búfer con esa
misma entrada direccional Ahora podemos escribir
esta función dash en nuestro script de personaje jugador, aceptando la
dirección a dash como parámetro y
devolviendo un booleano, devolviendo false por defecto Antes de escribir esta función, necesitaremos algunas variables. La distancia que queremos que
el personaje corra, yo estableceré el mío en 128 píxeles. La cantidad de fuerza
requerida para alcanzar esa distancia calculada
usando la etiqueta on ready, podemos usar la
misma fórmula que el cálculo de altura de salto, la raíz cuadrada de distancia multiplicada por la fuerza
negativa, que en este caso es
la desaceleración por dos También me gustaría suspender gravedad mientras ocurre el
guión. Así que también almacenaré la gravedad
predeterminada del personaje en una variable usando
la etiqueta on ready. Ahora para la función dash, si la habilidad dash
ha sido desbloqueada, entonces queremos que el personaje
mire hacia la dirección del guión, lo que podemos hacer estableciendo la dirección de
movimiento a ese valor. Luego establece la velocidad del
personaje para que sea un nuevo vector dos con la dirección del guión multiplicada por fuerza del
tablero como la X
y cero para la Y. Dado que el
stick analógico izquierdo se puede inclinar, esto significaría que el
jugador puede lanzar más lento o más rápido en función de lo lejos que incline el stick analógico
en el controlador No quiero que esto suceda, así que usaré la función sinusoidal para eliminar la inclinación
de la ecuación. Podemos suspender la gravedad mientras
el guión está sucediendo, estableciendo el valor
de la gravedad en cero, luego volver verdadero porque el guión fue exitoso y
no necesita ser amortiguado. cuanto a la dirección a guión, hay varios
casos a considerar, no sólo si el jugador está
dando entrada direccional, sino también si no lo
son y también si el personaje está
realizando actualmente un deslizamiento de pared. Dado que ese es el caso
más específico, primero lo
revisaré. Si el carácter
es muro deslizante, sobrescribiré el
valor de dirección para
ser signo de wallNRmaltx Si no son de pared
deslizante y el jugador está dando entrada direccional cuando presionan al botón del tablero, entonces voy a usar el pecado de
dirección como la dirección, eliminando cualquier inclinación analógica de la entrada para poder quitar
esto de la línea de abajo. Si el jugador no está dando ninguna entrada direccional
cuando presiona el botón del tablero, asumiré que quieren correr
hacia adelante. Usaré un ternario si para establecer la dirección para
que sea negativa si el personaje está orientado hacia la izquierda
o uno positivo si
no están restaurando la
gravedad de nuevo a la normalidad, necesitaremos otra función para llamar al final del guión Esto no necesita ningún
parámetro ni devuelve un valor. Simplemente volveremos a establecer la
gravedad del personaje a su valor predeterminado. En la escena del personaje, el guión necesitará una animación en
el nodo Animation Player. Al establecer los fotogramas por
segundo y acercar el zoom, agregaré mis fotogramas clave
para animar el guión Tendremos que agregar una pista de
método de llamada y un fotograma clave en esta pista para llamar a
la función end dash al final de la animación O cualquier fotograma que quieras para restaurar la gravedad del
personaje. Usando este procedimiento, si es posible interrumpir esta
animación por cualquier motivo, aún
necesitaremos llamar a la función end dash para restaurar
la gravedad del personaje, a diferencia del temporizador que usamos para restaurar el control de errores del
personaje. Así que ten esto en mente y haz un comentario para
recordarte esto más adelante. Añadiendo esta animación
a la máquina de estado, debería ser posible realizar un guión desde cualquiera de nuestros estados de movimiento
existentes. Por lo tanto, sería mejor
poner esta animación
en una nueva capa. Guardando la
máquina de estado actual como recurso de proyecto, nombraré movimiento y pondré en la carpeta de
escenas de personajes. Luego cree un nuevo recurso
de máquina de estado para
el Árbol de Animación. Añadiendo la máquina de
estado de movimiento como nodo en esta
nueva máquina de estado, renombraré a
movimiento y crearé una transición de inicio a movimiento, por lo que
es la predeterminada. Al agregar una nueva animación de guión
a esta máquina de estado, podemos agregar una transición de movimiento a guión y de
regreso al movimiento. Para reproducir una
animación una vez, la transición que conduce a ella
debe establecerse en habilitada, y la transición
que sale de la animación debe
tener su modo de conmutación configurado en
al final y dejando el modo
avanzado como automático. Podemos probar esta animación haciendo clic en el
botón de reproducción en el estado. Con cada clic, juega
una vez en su totalidad y vuelve al estado de
movimiento cuando
se termina. Dado que la transición que conduce a la animación no es automática, nos toca a nosotros activar esta animación manualmente
a través de nuestro script. Declarando una nueva variable, esta será utilizada para
múltiples habilidades diferentes, así que la pondré en la parte superior
y solo la nombraré
animación para abreviar El tipo de esta
variable será una reproducción de
máquina de estado de nodo de animación. Esto es lo que usa Godot para navegar por la máquina de estado
y reproducir animaciones Seleccionando el nodo
en el árbol de escenas, podemos ver este recurso de
reproducción bajo parámetros de reproducción. Podemos recuperar este
recurso haciendo clic y arrastrando el
nodo Árbol de Animación para obtener su ruta de nodo Luego usa corchetes para obtener un recurso
de este nodo. Hacer clic y arrastrar
este recurso desde el inspector a los corchetes nos da
la ruta al recurso Si ampliamos el movimiento
y la locomoción, se
puede ver que cada capa de la máquina de estado tiene su
propio recurso de reproducción Si bien actualmente
solo necesitamos este para
activar manualmente el tablero, pronto
agregaremos
más habilidades Esta ruta también cambiará a medida que agreguemos más capas a
la máquina de estado, por lo que deberá actualizarse. Para activar la animación de guión, al
realizar con éxito un guión, podemos decirle a esta
reproducción que viaje
al estado de guión
especificando su
nombre de cadena como argumento. Esta línea de código
equivale a presionar
el botón de reproducción en
el Árbol de Animación cuando previsualizamos la animación También quiero eliminar
la capacidad del jugador para controlar al personaje
mientras el guión está sucediendo. Así que anulando el proceso de
física, podemos
interrumpirlo rápidamente y verificar
en qué estado se encuentra actualmente
la
máquina de estado de animación se encuentra actualmente
la
máquina de estado de animación usando la función
G nodo actual Esto devuelve el nombre de cadena que
escribimos en
el nodo en el Árbol de Animación, que podemos comparar para ver
si es movimiento o no. Si es
otra cosa que no sea movimiento, estableceré la dirección
del movimiento en cero antes continuar con el proceso normal de física de la
superclase Esto evitará que
el personaje se
mueva o mire en una dirección
diferente mientras realiza cualquiera de las habilidades en
la capa superior de la máquina de
estado. En el guión del administrador del juego, voy a cambiar la tecla de flecha hacia arriba
para desbloquear la dashability Ejecutar el juego, presionar
el botón del tablero no hace nada. Después de presionar la tecla de flecha hacia arriba para desbloquear la dashabilidad, podemos correr, haciendo que el
personaje se desplace hacia adelante Al presionar una dirección, el personaje corra
en esa dirección. Y si corremos
mientras la pared se desliza, el personaje se
alejará de la pared. Ahora tenemos nuestro personaje de jugador capaz de correr por
el entorno, pero tendremos que agregar un temporizador de
enfriamiento para evitar que el
jugador lo use con demasiada frecuencia. Te veré en el siguiente video.
47. 6-5 horas de enfriamiento: Hola, amigos. En este video, agregaremos fotogramas de invencibilidad y un enfriamiento a
nuestra habilidad de tablero Antes de comenzar a agregar marcos de
invencibilidad al tablero, sería útil
tener un hit box en nuestra escena para que podamos
probar corriendo a través En la escena de
contenido de la sala de inicio, agregaré un área para denodar
y renombrarla para darle un toque a Box Luego agrega una
forma de colisión cuando era niño. Dale una forma de rectángulo como recurso y establece su color de
depuración en rojo. Te puedes imaginar que
esto representará a un enemigo que daña al personaje
del jugador al contacto. Voy a hacer que sea un azulejo de espesor, 32 píxeles, y dos
teselas de alto, 64 píxeles. Después muévelo hacia la izquierda. Consideraré que mi prueba fue aprobada si el personaje del jugador puede correr por esta área
sin ser perjudicado Para que esta
zona de colisión inflija daño al jugador
, deberá estar monitoreando. No necesita
ser monitoreable, aunque dejar esta casilla marcada no hará
ninguna diferencia No necesita
existir en ninguna capa, sino que debe estar enmascarando la capa del
jugador Hurt Box. Si te ayuda a entender mejor
las colisiones, está bien considerar
que
esta caja de impacto existe en
una capa de caja de impacto enemiga o una capa de peligro
ambiental Los únicos requisitos
son que debe estar monitoreando y enmascarando
al jugador Hurt Box. Adjuntando un script a este nodo, conectaremos su señal de
entrada en el área al script. Después de verificar si el área
tiene un método de toma de daño, llamaremos a este método y pasaremos uno como la
cantidad de daño. Esto asegurará
que el área que ingresa esta tenga el
script de Hurt Box que creamos anteriormente, que tiene el método take
damage, aceptando la cantidad de
daño como parámetro. Si otra área activa la señal sin
un script de Hurt Box, causaría un
error ya que no
habría un método de toma
daño para llamar. Para poder ver nuestras
formas de colisión mientras probamos el juego, podemos abrir el menú de depuración y seleccionar formas de colisión visibles. Si ejecutamos el juego,
podemos ver el hit box, y el personaje jugador recibe un daño cada vez
que ingresa a esta área. Hay un mensaje de error porque el
contenido de la habitación se está
cargando en respuesta a que nuestro personaje ingrese a
un área de colisión, y a Godot no le gusta agregar otra área de colisión
durante un evento de colisión Ignoraremos esto por ahora ya que solo estamos
realizando una prueba, y esto no va a ser
parte de nuestro juego final. En la escena del personaje, selecciona el nodo Reproductor de animación
y la animación de guión. Para agregar fotogramas de invencibilidad
a nuestra animación de tablero, todo lo que tenemos que hacer es fotogramas clave la propiedad monitoreable de
Hurt Box Podemos establecer el marco exacto cuando la Caja Hurt se apaga y
cuando se vuelve a encender. Si lo deseas, también
puedes fotogramas clave la visibilidad de tu
Hurt Box para que coincida con su
propiedad monitoreable para que pueda verla apagarse y volver a encenderla mientras juegas al juego Esto hace que sea más fácil saber cuándo tu personaje es
realmente invencible También podría ser útil
desactivar la visibilidad
de la forma de colisión del
cuerpo del personaje para ver mejor la Caja de Daño. ejecutar el juego, ahora
podemos
atravesar el hit box
sin recibir ningún daño. Caminar hacia el
área aún inflige daño al igual que terminar el
guión dentro del área Ahora agreguemos un
Cooldown al guión. Comenzaremos agregando un nodo
temporizador a la escena del
personaje. Voy a nombrar a este temporizador Dash Cooldown y estableceré su propiedad de one
shot en true Dejaré su
tiempo de peso como 1 segundo. Este será el tiempo de
enfriamiento de la habilidad. Teniendo en cuenta que esta es
la segunda habilidad con un nodo temporizador asociado, y es posible que queramos agregar
más en el futuro, es posible que desee considerar usar un nodo normal como una
carpeta plegable para contenerlos. Pero ayudará a
darle un nombre único en caso de que queramos
reestructurar el árbol de escena No necesitamos
conectar la señal
al script para usar este nodo
temporizador como enfriamiento. En las declaraciones de variables
para Dashability, usaré la etiqueta on ready para obtener una referencia a
este nuevo nodo temporizador Todo lo que tenemos que hacer es iniciar el temporizador ya sea al
arrancar o al finalizar o al salpicar. Depende de tu
preferencia cuál, pero si quieres
comenzar el
enfriamiento al final del guión, se
requerirá
otra condición para
evitar que el jugador se apague dos veces seguidas Iniciaré el
temporizador de Enfriamiento después de que termine el tablero. Después volvemos a la
declaración I donde
comprobamos si este personaje
puede comenzar a correr. Podemos verificar si el nodo
actual de
la
máquina de estado de animación es movimiento. Esto también tendrá beneficios
agregados más adelante, ya que no permitiremos que
el personaje se desplace mientras realiza otras habilidades de acción
similares. Para hacer cumplir el temporizador de Enfriamiento, solo
necesitamos verificar
si este temporizador está parado para saber si deberíamos
poder volver a correr Si la animación del tablero ya se está reproduciendo o el
temporizador de enfriamiento no se detiene, eso significa que el tablero fallará Ejecutando el juego ahora, presionando el botón del tablero permite al
personaje correr solo una vez, luego obliga a un
enfriamiento de 1 segundo antes de que
puedan volver a correr. Esto funciona, pero no se está
comunicando al
jugador de ninguna manera. Por lo general, juegos como este
tendrán un indicador diagético, algo que
existe en el juego, no en el HUD para decirle
al jugador cuándo termina el
enfriamiento Así que agreguemos un nodo Animated
Sprite two D a la escena del personaje y
llamémosle el efecto Dash Cooldown. Al crear un
recurso de marcos Sprite para este nodo, podemos importar una hoja de Sprite Simplemente pondré esto en
la carpeta de polvo por ahora en lugar de crear una nueva carpeta de activos
para una hoja de Sprite Y agrega los marcos Sprite
de la hoja Sprite. Desactivaré el ciclo, estableceré
los fotogramas por segundo en 12, y también agregaré un fotograma
en blanco al final de la animación Esto no está centrado
en el personaje, así que lo voy a mover hacia arriba 12 píxeles. Esta animación es de
más de 1 segundo, pero la marca de 1 segundo es cuando
quiero que el enfriamiento
se considere terminado. Voy a darle
un nombre único a este nodo. De vuelta al guión,
todo lo que tenemos que
hacer es agarrar una referencia
a este nodo. Un dígale que juegue
cuando termine el guión. Pero como mi animación es más larga que el temporizador Dash
Cooldown, en realidad
tendré que
detener la animación
antes de reproducirla en caso de que todavía
se esté reproduciendo Esto restablecerá la
animación de nuevo al inicio. A Ahora, cuando ejecutamos el juego y
usamos la habilidad dash, se reproduce la animación,
pero no está siguiendo
al personaje. Esto se debe a que un nodo normal
no tiene una transformada. Por lo tanto, no
tiene una posición. Esto rompe la
línea de herencia del nodo raíz del personaje. Por lo que el nodo animado Sprite
dos D ahora está comenzando su propia ascendencia
para dos transformaciones D, comenzando en la posición 00 Podemos cambiar el tipo de
la carpeta de habilidades a no dos D para que
proporcione una línea de sucesión
a través del árbol de escenas, y el Sprite Animado
seguirá el nodo raíz Ahora es claro para
el jugador que su habilidad de tablero está
en Cooldown y exactamente cuándo puede
volver a correr sin tener que
agregar ninguna
información extra sobre el HUD Ahora tenemos nuestra capacidad de tablero capaz de atravesar cajas de impacto sin que nos golpeen y enfriemos antes de
poder volver a usarse. A continuación, agregaremos una habilidad
pasiva que cambia la apariencia del
personaje. Te veré en el siguiente video.
48. 6-6 sombreros: Hola, amigos. En este video, implementaremos una habilidad
pasiva que altera la apariencia del
personaje Comenzando en la escena del
contenido de la habitación, duplicaré el área
de
colisión de antes para esta prueba. Esta vez, el área de
colisión representará específicamente un calor
intenso desde el interior de un volcán. Voy a cambiar el color a naranja
así sé cuál es cuál. Quiero que el jugador
no pueda pasar por
esta área hasta
que no haya desbloqueado un sombrero mágico que le permita
proceder ilesos Pero llevar el sombrero
aún les permitirá recibir daños de cajas de impacto
normales. Entonces, en lugar de tener esto enmascarando la capa normal del jugador
Hurt Box, usaré una capa diferente. Utilizaré la capa 14 como una capa dedicada a este efecto de calor
ambiental. Esto me será fácil de
recordar ya que está
directamente por debajo de diez. En la configuración del proyecto, voy a nombrar a esta capa de calor. Entonces en la escena del personaje, voy a hacer que la Caja de Hurto
también exista en esta capa. Ahora bien, esto funcionará de la misma manera que antes el
área de colisión, infligiendo un daño
al jugador cada vez
que ingrese a esta área. Sólo está comprobando
colisiones en la
capa 14 en lugar de en la capa diez Entonces, todo lo que tenemos que hacer para que el personaje del jugador sea inmune
al daño por calor mientras usa el sombrero es quitar la capa 14 de su propiedad de capa de
colisión Hurt Box. Para alterar la apariencia del
personaje, colocaré
sprites adicionales sobre el personaje Importaré nuevas hojas de sprites para tres mejoras diferentes, una gema, una capa y un sombrero Después en la escena del personaje, agregaré un nodo Sprite Tu
Di extra para cada uno de ellos. Todo con texturas atlas al
igual que el sprite corporal. A continuación, asigne las hojas de sprites como la propiedad atlas
para cada nodo La forma en que se dibujaron estos activos, voy a necesitar ponerlos
específicamente en el
orden del gato,
luego la capa específicamente en el
orden del gato, , luego el
sombrero, y la mermelada en la parte superior Comenzaré cada uno con el primer sprite en la
posición 00 con un tamaño de 32 por 36 píxeles y les daré el mismo desplazamiento para
moverlos hacia arriba por 18 píxeles Estos activos se
dibujan para animar sincrónicamente con el sprite de carácter
normal Por lo que todos
los valores de región serán los mismos para cada capa
al mismo tiempo. Todo lo que tengo que hacer es agregar región de textura del atlas de
cada sprite a la animación Después copia y pega las teclas
del cuerpo de la pista de Sprite
a las otras pistas Y cambiar su
modo de actualización a discreto. Ahora la animación
también incluye todas las capas de sprites en
perfecta sincronización Voy a necesitar hacer esto para
todas mis animaciones, pero no va a tomar
tanto esfuerzo. Para voltear cada uno
de estos sprites, podríamos establecer todas
sus propiedades flip H cada vez que
cambien de dirección Pero hay una manera más fácil usar la herencia del
árbol de escenas. Si hacemos que todos
los demás sprites hijos del sprite corporal, heredarán su
transformación de él Y podemos voltear un sprite usando su transformada estableciendo su escala
X a una negativa Tenga en cuenta que este truco no
debe usarse para nada que involucre
física o colisiones. Aquí funciona bien porque solo
estamos dibujando sprites. En la función cara izquierda
en nuestro script de caracteres, lugar de establecer flip H, podemos establecer el punto de escala
X a uno negativo, si se deja, de lo contrario, uno
positivo. Esto sincronizará ahora el volteo de todos
los sprites Con toda la configuración de
los sprites completa, configuraré la visibilidad de los otros sprites por defecto,
luego
los encenderé a medida que se
desbloqueen las habilidades En el guión del personaje del jugador, necesitaremos una función para
gestionar qué capas de Sprite son visibles en función de qué habilidades ha desbloqueado
el jugador Lo llamaré Actualizar visibilidad de
Sprite. Luego, dale a cada uno de los sprites un nombre único y establece su visibilidad para que coincida con el valor de habilidades desbloqueadas
para la habilidad de emparejamiento Al doble salto
se sumará el manto. El sombrero es obvio. Y la capacidad de disparar
proyectiles agregará la gema. En el guión del administrador del juego, cuando empezamos a
jugar el juego por primera vez, podemos llamar a esta función para actualizar la visibilidad de
Sprite de los personajes de
inmediato en caso de que hayamos cargado una cerveza segura con habilidades
ya desbloqueadas Mientras jugamos el juego, también
querremos llamar a esta función cada vez que el
jugador desbloquee una nueva habilidad Entonces agregaremos una señal
a este script para cuando se
haya desbloqueado una habilidad, con el
número entero de habilidades como parámetro. Después escribe una función pública
para desbloquear una nueva habilidad, aceptando el mismo número de
habilidad y omitiendo la señal Entonces podemos conectar esta señal
al personaje del jugador. Sin embargo, no
escribimos la función de visibilidad de
Sprite de actualización para aceptar ningún parámetro Entonces, cuando conectamos la señal, debemos desvincular un argumento para evitar causar errores Esto funcionará para cambiar
la apariencia del personaje, pero seguirán tomando daño por
calor mientras
llevan puesto el sombrero. Al actualizar la visibilidad del
sprite del personaje en el caso específico
de adornar el sombrero, también
eliminaré
la capa de colisión daño
por calor para que
sean inmunes a ella Para eliminar una sola
capa específica de una máscara de bits, primero, coloca el cursor del mouse sobre la capa y toma
nota de su valor La capa 14 tiene un valor de 8,192, que es dos a la potencia de 13 o dos a la potencia
de 14 menos uno La capa de colisión es en
realidad un entero, que en binario es una
secuencia de ceros y unos. Actualmente, es todo ceros, salvo que los bits décimo
y 14 son uno Todo lo que tenemos que hacer es cambiar el bit 14 a cero para
eliminarlo de esa capa. Empezaremos agarrando una
referencia a la caja het. Dado que esta función no
se llama muy a menudo, está bien usar una ruta de nodo. Para eliminar la capa de colisión, podríamos restar
su valor 8,192 Sin embargo, esto depende la capa de colisión
existente actualmente en la capa 14. Si llamáramos a
esta función por alguna razón cuando la capa 14 ya
está apagada, resta
simple no
funcionaría Usando el operador de bits y en la capa de
colisión de nuestra caja Hurt, si podemos proporcionar una secuencia de todos los con solo
el bit 14 como cero, el resultado será
establecer el bit 14 20 independientemente de
su valor actual. Para obtener ese número,
podemos revertir los bits de 8,192, el valor de las capas Esto se hace con el operador nada
bit a bit, que en GDScript es Esta es una forma
matemáticamente eficiente de eliminar las capas de colisión Si quieres agregar
una capa de colisión, estableciendo su bit en uno, todo lo que tienes que hacer es usar el
operador u en lugar de y
y quitar el nudo. Pero no nos
interesa hacer eso aquí. En el guión del administrador del juego, actualizaré mi
función de entrada para desbloquear cada nueva habilidad en secuencia al presionar la
flecha hacia arriba para mi prueba. Declarando una nueva variable aquí, por lo que se incluye con
mi código de prueba Recordaré
eliminar esto junto con la función de entrada cuando
ya no la necesite para probar. Voy a nombrarla siguiente habilidad como un entero que naturalmente
por defecto es cero Cada vez que presione la flecha hacia arriba, desbloquearé la siguiente habilidad e imprimiré el
nombre de esa habilidad. Podemos usar la función keys en una enumeración
para obtener una matriz de cadenas que son las
mismas que las que
escribimos como las entradas de
enumeraciones Entonces, al indexar la matriz de claves con el número de habilidad, se obtiene
el nombre de esa habilidad Luego incrementaré la
siguiente habilidad, pero la mantendré sujeta para que esté
entre cero y el tamaño de
la enumeración de habilidades menos uno para evitar errores Eliminaré el archivo seguro
actual para que mis habilidades comiencen bloqueadas y enciendan formas de colisión
visibles. Ejecutando el juego,
comenzamos sin habilidades desbloqueadas y el personaje
predeterminado Sprite Abriré el
árbol de escenas remoto y seleccionaré a los personajes Hurt Box para verificar que
están en las capas diez y 14. Presionando una vez la flecha hacia arriba, la habilidad de doble salto ahora
está desbloqueada, por lo que el personaje
lleva una capa Al presionar nuevamente la flecha hacia arriba, se desbloquea
el salto de pared, pero la apariencia del personaje
permanece sin cambios ya que esa habilidad no se asoció
con un cambio cosmético. Al tocar cualquier área de colisión el personaje
sufrirá daños. Presionando una vez más, ahora el guión
también está desbloqueado, y aún así el
personaje se ve igual. De nuevo para desbloquear
el sombrero mágico, y podemos ver que la Caja de Hurto del
personaje ya no
está en la capa 14, sino en la capa diez. Tocar la caja de
golpe normal causa daño, pero entrar en la nueva caja de impactos de
calor volcánico no lo hace, lo que significa que el personaje es inmune a ella mientras usa el sombrero. Presionando una última vez, desbloqueamos la
habilidad de disparar y agregamos la gema, pero aún no la hemos
implementado. Ahora tenemos nuestro
personaje cambiando atuendos para que coincida con su
progreso a lo largo del juego. La última habilidad que agregaremos
es disparar un proyectil. Te veré en el siguiente video.
49. 6-7 Proyectil: Hola, amigos. En este video, agregaremos un hechizo de
proyectil que el jugador puede disparar
gastando sus puntos mágicos Primero, tendremos que darle a este personaje
puntos mágicos para gastar. En el guión del personaje del jugador, agregaré una nueva
categoría de exportación para lanzar hechizos Después dos variables por su magia máxima y su magia actual
tanto como carrozas También necesitaremos señales para emitir cada vez que cambien estos valores
para poder actualizar el HUD Anulando la función ready, podemos establecer la magia máxima al valor de los datos de guardado del
jugador Entonces solo arrancaré al
jugador con magia completa, configurando el valor actual
al valor máximo y emitiré las señales cambiadas
para actualizar el HUD Desde la escena del juego, podemos conectar
fácilmente
las señales
del personaje del jugador al medidor mágico ya que existen
en la misma escena. El medidor mágico no tiene un guión adjunto,
pero no necesita uno. Dado que la barra de progreso ya proporciona las funciones que
necesitamos, solo tenemos que
desactivar los métodos de script solamente. La clase range nos da la función set max
aceptando un parámetro float. Así como la función set
value, aceptando
también un parámetro
float. Ahora el medidor mágico se
actualizará automáticamente con las variables mágicas del
personaje del jugador. En la configuración del proyecto, la pestaña Mapa de entrada
necesitará un botón que pueda ser presionado por el
jugador para lanzar un hechizo. Usaré la tecla C o el botón Face superior
en mi controlador. Después en el guión de los jugadores, podemos copiar el mismo
formato que el salto para intentar lanzar un hechizo
y si no tiene éxito, amortiguar la entrada para volver a
intentar el siguiente fotograma De vuelta en el guión del
personaje del jugador, podemos escribir la función cast, no
aceptando parámetros
y devolviendo un booleano Todo lo que realmente necesitamos hacer aquí es verificar si la habilidad ha sido desbloqueada y si el personaje
no está ocupado realizando
otras acciones, si el nodo
actual de la animación es el movimiento. Entonces dígale a la animación que
viaje a la animación del elenco y devuelva true si la entrada fue exitosa o
false si no lo fue. En caso de que no queramos que el lanzamiento de nuestro hechizo
sea instantáneo, todo lo demás tendrá que suceder en una función separada Vamos a nombrar a este proyectil de un
disparo. No necesita ningún argumento
ni devolver ningún valor, y aún no tenemos ninguna información para escribir
esta función,
pero necesitaremos que esta función sea declarada y guardada antes de poder
incluirla en la animación de casting. Cambiando a la escena del
personaje, comenzaremos agregando
un Sprite Animado para dende para usarlo como efecto
de lanzamiento Esto necesitará un recurso de
marcos Sprite. Antes de importar mis
hojas de sprites para lanzar hechizos, haré una nueva carpeta
para sprites mágicos y moveré el
efecto de enfriamiento del guión a Después importa los sprites para el lanzamiento, el proyectil y
sus sprites de impacto Agregar los sprites de
animación de lanzamiento
al recurso de fotogramas de Sprite Y Lo
pondré 12 cuadros por
segundo, no en bucle Y agregaré un fotograma
en blanco al final de la animación, luego lo moveré hacia arriba 18 píxeles
con el desplazamiento Y. Esto se ve bien, pero si le
hacemos esto al
personaje Sprite, también
volteará para enfrentar la
misma dirección que el personaje Seleccionando el nodo
Animation Player, podemos duplicar cualquiera de las animaciones existentes para
crear una animación de casting. Después de eliminar pistas
innecesarias y actualizar todos los fotogramas clave de la región de
Sprite, agregaremos pistas del método de llamada
tanto al nodo
raíz del personaje al efecto de casting Sprite
animado no dos D. Para el efecto casting, todo lo que tenemos que hacer
es decirle que Para el personaje, agregaremos un fotograma clave para disparar
el proyectil Estos fotogramas clave se pueden ajustar
fácilmente para que ocurran en cualquier momento durante
la animación de casting Comenzaré el efecto de lanzamiento en el segundo fotograma y dispararé el proyectil
en el tercer marco El resto de la animación
actuará como recuperación. En el Árbol de Animación, solo
necesitamos repetir el mismo proceso que
usamos con el guión. La transición al
reparto está habilitada, y estamos volviendo al movimiento al final
de la animación A continuación, ensamblemos
el proyectil real. Comience agregando una nota D del área dos a la escena del
personaje. Entonces dale una
forma de colisión y un recurso de forma. Usaré un círculo pero reduciré
su radio a ocho píxeles, y cambiaré su color de
depuración a algo que aún no he usado, como el morado. Después agrega un Sprite Animado para denodar y dale un recurso de marcos de
Sprite Primero, agregaremos
los fotogramas de sprite para el proyectil como queremos que comience y
lo usaremos como
la animación predeterminada de Sprite Esto será en bucle y estableceré mi velocidad de fotogramas en 12
fotogramas por segundo Después haremos clic en el botón agregar
Animación para crear una segunda animación de Sprite y nombraremos a ésta
algo así como Impact Ahora podemos agregar más fotogramas
Sprite para una animación de impacto
que será reproducida por el mismo proyectil
cuando choca También es posible que desee agregar un fotograma
vacío al final de esta animación para permitir que el último fotograma se dibuje
durante toda su duración. Recuerda establecer la
animación predeterminada para reproducción automática,
así que reproduciremos esta animación cuando el proyectil genere Aún dentro de la escena del
personaje, reposiciona el
proyectil hacia donde
quieras que comience en
relación con el Puedes hacerlo
más fácil seleccionando el proyectil y
el árbol de escena y sosteniendo Alt
mientras lo mueves El mío es de 12 píxeles a la derecha y arriba desde
el origen del personaje. A continuación, agregue un marcador dos nodos D como hijo del proyectil Esto asegurará
que su posición coincida exactamente con el proyectil El marcador al nodo D es exactamente
el mismo que un nodo dos D, excepto que dibuja
un pequeño artilugio en el editor para que podamos ver
exactamente dónde está Esto nos da la posición
en la que queremos generar el proyectil en nuestra escena
al lanzar el hechizo Así podemos nombrar el nodo Marker
Tutti en consecuencia. Después reparar el
nodo Marcador Tutti al personaje Sprite Al ser hijo
del personaje Sprite, volteará su exposición cuando el personaje cambie su dirección de
orientación automáticamente Guarda la rama del proyectil como escena
propia y guárdala en una nueva carpeta de escenas
para proyectiles Después elimínelo de
la escena del personaje. Ahora tenemos un proyectil y sabemos dónde lo
queremos generar,
así que volveremos al guión del personaje del
jugador Podemos exportar el proyectil como una escena repleta y
poblarlo en el inspector También podemos tomar una referencia
al marcador de spawn. Sería mejor
que tuviera un nombre único. Y tendremos que especificar un costo mágico para disparar
este proyectil Pondré el mío en
16 puntos mágicos. Antes de permitir que el jugador comience
a lanzar el hechizo, también
debemos
verificar si tiene suficientes
puntos mágicos comprobando si su magia actual es
mayor o igual al costo mágico. Entonces, cuando la animación de reparto llama a la función de
proyectil disparar, ya que hay una ventana de
tiempo
muy breve entre cuando se llaman estas
dos funciones, no
es mala idea verificar
también que el personaje tiene
suficiente magia restante para lanzar el
hechizo nuevamente aquí Por lo que comprobando si la magia actual
es menor que el costo, al regresar de esta función no
se disparará el proyectil Sabiendo que este no
es el caso, podemos restar el costo
de nuestra magia actual y emitir la señal de magia actual cambiada para
actualizar el HUD Después crearemos
un nuevo proyectil instanciando
la No queremos que esto siga
al personaje alrededor niño más bien como
hermano dentro del mundo, para que pueda moverse por sí solo Así que primero conseguiremos al padre antes de agregar este
proyectil cuando era niño Luego establece su posición
dentro del mundo para que sea la posición global del
marcador de generación de proyectiles Tenemos que usar la
posición global aquí porque la posición local del marcador está en relación con la posición del
personaje, pero el proyectil
se está agregando al nodo mundial,
no al personaje Entonces queremos la posición
del marcador en relación con
el mundo. Y por último, le diremos a este proyectil en qué
dirección está disparando Podemos pasar un argumento
como Vector dos puntos izquierda si el carácter está orientado hacia la
izquierda o hacia la derecha, de lo contrario. Ahora tendremos que escribir esta
función para nuestro proyectil, abrir la escena del proyectil, luego agregar un script
a su nodo raíz, lo
llamaremos Proyectil
y lo guardaremos en la Ayudará darle a este script un nombre de clase para que podamos hacer
referencia a él más adelante. Este proyectil necesitará
algunas variables exportadas, como una velocidad de lo rápido que se mueve y la cantidad de daño que hace cuando
golpea algo Voy a nombrar este
daño por defecto para que pueda ser anulado y
darle un valor de uno También necesitaremos una referencia
al nodo Animated Sprite Tu Di para decirle qué
animación reproducir Necesita saber en qué
dirección se está
disparando y cuánto daño
infligirá realmente, si no el predeterminado, y si se está moviendo o no
actualmente. Cuando se nos dice que disparemos, podemos aceptar la dirección como un vector dos y la cantidad de daño como un entero con un valor
predeterminado de cero, convirtiéndolo en un parámetro opcional. Estableceremos la dirección al
parámetro direction y voltearemos el sprite si el punto de
dirección X es algo menor que
cero, es decir, left Luego establece daño en daño si se proporcionó algún valor de
daño, lo contrario, use el
daño predeterminado para el daño, y finalmente set se está
moviendo a true. Anular la función de proceso. Si este proyectil se está moviendo, entonces podemos establecer su
posición para que sea más igual dirección multiplicado por
velocidad por Delta Este proyectil
necesitará chocar tanto
con cuerpos como con Entonces tendremos que
conectar tanto en el área ingresada como en las
señales ingresadas en el cuerpo al guión. Los cuerpos con los que
colisionará este proyectil serán el terreno, mientras que las áreas
serán cajas de Hurt Ambos harán
mucho de las mismas cosas. Entonces llamaremos a una función
privada separada de ambas y la nombraremos en cuanto al impacto. Cuando el proyectil
impacte en algo, haremos que deje de moverse luego desactive más colisiones poniendo su máscara de
colisión a cero Esto apaga todas las capas
de la máscara de colisión. Luego reproduce la
animación de impacto y conecta la señal de animación terminada a la función de cuarto para eliminar
automáticamente el
nodo de la escena. Si el proyectil
choca contra una caja Hurtada, podemos decirle a esa Caja de
Daño que tome la cantidad de daño antes de
llamar al impacto No estamos usando el parámetro
body, así que podemos marcarlo como
no utilizado con un guión bajo Si el proyectil
no golpea nada, aún
necesitamos limpiarlo. Una forma sencilla es hacer que la habitación la destruya
automáticamente
cuando sale de la habitación en la
que se generó Desde el guión de la sala, en lugar de conectar
esta señal a través del inspector cada
vez por cada habitación, sería más fácil
hacerlo a través del scripting. Entonces escribiremos una función on
area salida, aceptando un área como un no dos
D y devolviendo ningún valor Si el área que salió de
esta habitación era un proyectil, haremos cola para que se libere del árbol
de escena Luego conecte la señal de área de salida en
la función ready También podemos hacer esto
para
conectar automáticamente las señales
ingresadas al cuerpo, también. Solo recuerda que si alguna de las escenas de tu habitación ya tiene
estas señales conectadas, debes
desconectarlas para evitar errores. Pero a medida que creamos
cientos de habitaciones, hacer que estas
conexiones de señal se
registren automáticamente nos ahorrará mucho
más tiempo y esfuerzo Para que el colisionador
de la habitación detecte un proyectil que
sale de
ella, necesitará enmascarar la capa de colisión en
la que se encuentra el proyectil Ejecutando el juego, ya
empiezo con cada habilidad desbloqueada del video anterior y mi medidor mágico está lleno. Abriré el árbol de
escenas remotas para que pueda ver mi proyectil engendrar
y limpiarme Al regresar al juego, al presionar el botón disparar se lanzó un hechizo, que dispara el proyectil El proyectil choca con la pared y explota Mi medidor mágico se reduce
por el costo del hechizo. Apuntando en la otra dirección, el proyectil
no tiene nada que golpear, por lo que saldrá de
la habitación actual Pero en lugar de
seguir moviéndose hacia el infinito, se destruirá una vez que abandone los límites
de esta sala. Ahora tenemos todas nuestras
habilidades desbloqueables en el juego, y estamos listos para
comenzar a agregar enemigos Te veré en
la siguiente sección.
50. Ritmo 7-1: Hola, amigos. En esta sección, agregaremos algunos
enemigos a nuestro juego. Empezaré haciendo
una nueva carpeta para contener a mis sprites enemigos e importar una hoja de sprites de mi primer enemigo, el ratón ciego También necesitaremos una nueva
carpeta de escenas para los enemigos. Podemos hacer las cosas
más fáciles si duplicamos nuestro personaje de jugador existente para usarlo como plantilla
para hacer nuestro enemigo. Después muévalo a
la carpeta del enemigo. Al abrir la nueva escena,
renombraré el nodo raíz para que
coincida con el nombre de la escena. Después pasa por la jerarquía de
escenas y decide qué nodos son necesarios para el enemigo
y cuáles no. Todavía necesitaremos
una forma de colisión para chocar con el terreno, una caja de daño para recibir daño y un sprite para
dibujar al personaje Pero los hijos del
Sprite no son necesarios, ya que este enemigo no tiene ningún otro sprites ni la
capacidad de disparar proyectiles Conservaremos el Reproductor de
Animación, el árbol y los nodos de efectos de sonido, aunque es posible que
desee cambiar los sonidos. El temporizador Coyote
no será necesario. Si
quieres o no que tus enemigos sean dibujados en el mapa
depende de tu preferencia, pero obviamente
necesitarás cambiar la textura si decides
mantener el ícono del mapa. Y también podemos eliminar
todos los nodos de habilidad. El nodo raíz tiene el script del
personaje del jugador adjunto. Tendremos que reemplazarlo con el guión de personaje normal, ya que este no es el personaje
del jugador y
no tienen ninguna de las habilidades del personaje
del jugador. Seleccionando el nodo Sprite Toti, podemos reemplazar la propiedad atlas
texturas atlas con una hoja Sprite
para Dado que la hoja de sprites es diferente a la de mi personaje jugador,
tendré que pasar por cada una de mis animaciones en mi nodo Animation
Player y verificar que tengan el número
correcto de fotogramas y los valores de
región correctos Este enemigo tiene menos animaciones que el personaje
del jugador, así que puedo borrar todo lo que no
sea ocioso y caminar. La animación inactiva funciona bien, ya que los
valores de región con clave coinciden exactamente, pero la animación de caminata
no coincide, así que tendré que arreglarla para que coincida con los valores de región para
la hoja de sprite Actualizaré rápidamente a los valores de la región Y con clave para que
esta animación funcione Ignoraremos las animaciones de hit
y dead por ahora ya que aún no
podemos probarlas. El Árbol de Animación necesitará una
máquina de estado mucho más simple para este enemigo, no la misma que está usando el personaje
jugador. Entonces haremos un nuevo recurso de máquina
estatal. Luego agregue las animaciones de ralentí
y caminata transición de
inicio a ralentí por defecto para caminar si la
velocidad X no es cero, luego vuelva a ralentí si la velocidad
X es cero Eso es todo lo que este enemigo
tiene que hacer por ahora. Echando un vistazo al
guión del personaje por un momento, el guión ya
tiene todo lo que necesitamos para hacer un
ritmo de carácter de ida y vuelta. Aunque como no quiero que mis enemigos tengan tiempo de coyote, tendré que
mover cualquier código relacionado con él
para que solo esté en el guión del personaje del
jugador, o simplemente puedo
asegurarme de que ninguno de códigos
relacionados con
el tiempo Coyote se ejecute si no hay
tiempo o nodo Coyote Como ya he usado el nodo get o la función null para verificar el nodo temporizador
Coyote, esta variable será nula
si no existe tal nodo La única vez que estamos usando el nodo temporizador Coyote es
en el proceso de física, y solo podemos
verificar si hay un nodo temporizador Coyote
antes de
intentar llamarlo función start
para evitar errores Este mismo proceso también podría
usarse si no quieres
incluir todos los mismos nodos exactos en
tus diversas escenas de personajes y enemigos para cosas como
sonidos o efectos de partículas. Cambiemos a cualquiera de
nuestras escenas de contenido de sala existentes y agreguemos a este nuevo
enemigo a la habitación. Mi plan para este enemigo es que tengan un ritmo de ida y
vuelta. Cuando chocan contra una pared,
quiero que se den la vuelta, esperen un segundo y luego
caminen en sentido contrario. Entonces editaré mi
terreno para crear una plataforma sencilla con
paredes a cada lado. Entonces este enemigo va a caminar
de un lado a otro aquí. También agregaré otra
plataforma sin muros, y el enemigo debería salir
de la repisa en este caso Es posible que desee escribir
otro guión como el guión del personaje del jugador que
hereda del personaje, que también incluye
este comportamiento Pero es mejor pensar
en este comportamiento como una alternativa al
nodo jugador en la escena del juego, a través del cual el jugador puede controlar al personaje del jugador. En cambio, escribimos un guión que controla el comportamiento de este
enemigo. Entonces crearemos un nuevo nodo
como hijo del enemigo. Voy a nombrar a este nodo pace. De esta manera, se
puede usar el mismo script de
comportamiento para múltiples enemigos
diferentes, y también el mismo tipo de enemigo podría tener múltiples scripts de comportamiento
diferentes. Incluir este nodo en la escena propia del
enemigo haría que se aplicara automáticamente a
todos los enemigos del mismo tipo. Si bien ponerlo en la escena del contenido de la
sala
permitirá que los mismos enemigos tengan potencialmente comportamientos
diferentes. Adjuntaremos un script
a este nodo y lo
pondremos en una nueva
carpeta de scripts para enemigos. Para decirle a un
enemigo qué hacer, necesitaremos una referencia
al propio enemigo
almacenada en una variable. Podemos llamar a la
función G parent para obtener el padre directo de este nodo y asignarlo a la variable usando
la etiqueta ready. Tenga en cuenta que esto solo funcionará si el nodo de comportamiento es un hijo
directo del enemigo. También deberíamos
exportar una variable para decir en qué dirección irá primero este
enemigo. Entonces le nombraré
dirección y le daré un valor por defecto de uno, es
decir, a la derecha. Anulando la función de proceso, todo lo que tenemos que hacer es establecer la dirección de movimiento del enemigo en
esta dirección para que
comiencen a caminar Cuando el enemigo está en una pared, podemos decirle al
personaje que mire hacia la izquierda y ponga su dirección de movimiento
a cero, para que se detenga. Para esperar poco
tiempo, necesitamos un temporizador. Dado que este nodo
no tiene un tipo, podemos usar este nodo como el propio temporizador
cambiando su tipo. El tipo que este script extiende también
necesitará cambiar a
temporizador para acceder a cualquiera de los nodos,
propiedades o funciones del temporizador. No necesitamos conectar
la señal de tiempo de espera, ya que todo lo que realmente necesitamos saber es si el
temporizador está parado o no Si se detiene el temporizador, estableceremos la
dirección de movimiento del enemigo en dirección. De lo contrario, podemos ponerla a cero porque este enemigo
está esperando actualmente. Cuando el personaje choca contra una pared, estableceremos el valor de
dirección para que sea el seno de las paredes X normal
y arrancaremos el temporizador. Para hacer que el personaje derecha cuando choca contra una
pared a su izquierda, también
tendremos que hacer que esto dependa del seno
de los muros X normal. También solo queremos detener al personaje y
darle
la vuelta si su dirección de
ritmo actual
no es la misma que la normal de
las paredes Estamos llamando a esta función
normal get Wall varias veces, por lo que sería más eficiente almacenarla en una variable local. Hagamos un poco de
refactorización de la luz aquí. En la escena del contenido de la habitación, podemos ajustar la cantidad de tiempo de espera y establecer la propiedad one
shot en true. Duplicaré el nodo de ritmo y lo adjuntaré
al otro enemigo. Entonces dale a mis dos enemigos valores
diferentes para su dirección
inicial de ritmo. Ahora cuando ejecutamos el juego, con la ayuda de nuestro guión de
comportamiento, los enemigos caminan, uno a la izquierda y
otro a la derecha. El segundo enemigo
se baja de la repisa, pero el primero choca contra la pared, se da la vuelta y
espera un segundo
antes de darse la vuelta y
caminar en la otra dirección Y ambos repiten
este comportamiento. Pero es posible que hayas notado que sus animaciones no
siempre coinciden con su velocidad. Ambos personajes en realidad se están animando en sincronización Esto se debe a que al
igual que los íconos de la salud, están compartiendo un recurso. En la escena de los enemigos, tendremos que seleccionar el nodo
Sprite two D y hacer que el recurso de textura del atlas sea
local para esta escena Ahora cada instancia de
este enemigo tendrá su propia textura atlas y podremos animarnos
independientemente unos de otros Sin embargo, si alguna de
tus animaciones está cambiando la propiedad
de textura del nodo Sprite two D, esto puede romper las animaciones
que están haciendo referencia Eliminaré esta pista
de mi animación de reinicio. Tampoco necesitamos la conexión de
señal, que se copió de la escena del personaje
del jugador, que se utiliza para
jugar Jump efforts. Ejecutando de nuevo el juego, ahora
podemos ver que son capaces de reproducir correctamente sus animaciones inactivas y
caminando. Ahora tenemos un enemigo que
puede caminar de un lado a otro,
dando la vuelta en las paredes, pero también tenemos que asegurarnos de que no
puedan salir de la habitación. Te veré en
el siguiente video.
51. 7-2 paredes invisibles: Hola, amigos. En este video, impediremos que nuestros enemigos
salgan de la habitación en la que
fueron engendrados Para ello, necesitaremos que nuestros
enemigos tengan colisiones con paredes invisibles que no afecten al personaje del
jugador Tenemos el cuerpo del
personaje del jugador en la capa nueve de colisión, enmascarando el terreno
en la capa uno. En la escena de nuestros enemigos, estableceremos la capa
de
colisión corporal algo diferente,
como la capa 17. Todavía necesitan enmascarar
la capa del terreno, pero también vamos a hacer que enmascaren una segunda capa que
usaremos para muros invisibles. Voy a usar la capa cinco. Abriendo los ajustes del proyecto, nombres de
capa Física dos D. Nombraré a la capa 17 como enemiga y a la capa
cinco como muros invisibles. En la escena de mi habitación, voy a copiar
el nodo de capa Tile Map, que está dibujando el mapa, ya que este ya tiene los
límites de la habitación. Después pégalo en la escena del contenido y
cámbiele el nombre a Muros invisibles. Con la nota de
capa Mapa de teselas seleccionada, haciendo clic en el recurso Conjunto de
teselas, necesitaremos agregar una
capa de física a este conjunto de teselas, existente en la capa cinco
para muros invisibles. Desde el panel Conjunto de azulejos, podemos pintar esta
capa de física sobre la baldosa. cambiar al panel Mapa de azulejos con la herramienta de pintura
y el mosaico seleccionado, podemos cerrar las puertas de esta
habitación, sellando
completamente la
habitación por todos lados con una capa de física que
solo está enmascarada por los enemigos y no por
el personaje del jugador No queremos que estos
muros invisibles se dibujen en el mapa, así que no deberían estar en la capa de
visibilidad dos, y queremos poder
verlos mientras estamos probando. Pongámoslos en la capa de
visibilidad uno. Editaré el terreno y moveré a
mis enemigos para que puedan caminar
libremente por toda
la habitación. Ahora, cuando corremos el juego, los enemigos caminan
hacia el borde de la habitación pero son
volteados por las paredes. Mientras que nuestro personaje jugador
puede caminar a través de ellos. Yo preferiría que
estas paredes estuvieran fuera del
área visible de la habitación, así que las moveré cada una
de ellas una baldosa más. Todo lo que tenemos que hacer para que las
paredes sean completamente invisibles para el jugador es desactivar
su propiedad visible, ya sea en el árbol de escenas
o en el inspector. Ahora tenemos que hacer que este enemigo realmente amenace
al jugador, cosa que ya hemos hecho antes. Todo lo que tenemos que hacer
es agregar un área al nodo
D, nombra golpear Box. Dale una
forma de colisión al nodo D como hijo y dale al
nodo Tut de forma
un recurso de forma a
la forma de colisión Establece la caja de golpe para enmascarar
la Caja de Daño del jugador. Y debe ser monitoreo. A continuación, adjunte el script de Hit box y conecte la señal ingresada en el
área de encendido. A ahora cuando ejecutamos el juego, hacer contacto físico con un enemigo hace que el
personaje del jugador sufra daño. Nos ocuparemos de
hacer que el combate más atractivo en
la siguiente sección. Por ahora, tratemos con
estos mensajes de error. Estos mensajes de error ocurren cuando cargamos el contenido de una habitación. Esto se debe a que estamos cargando el contenido de la sala
en respuesta a un evento de colisión cuando el
cuerpo del personaje del jugador entra en una habitación. Y a Godot no le gusta que agreguemos más áreas de colisión u objetos mientras ya está ocupado resolviendo colisiones
para este fotograma actual Entonces, si seguimos los
consejos que nos dan los mensajes de error y
usamos llamados diferidos, esto le dirá
al motor del juego que cargue el contenido de la sala
después de que se complete la resolución de colisión para el
fotograma actual El ciclo de Godot comienza con manejo de
entrada,
seguido de la física, que incluye colisiones, luego procesa y termina
con llamadas diferidas Entonces podemos usar esto para
realizar cualquier acción que
queramos como lo último
antes del final de cualquier frame. Ejecutando el juego de nuevo, ya no
hay más mensajes de error. Nuestro enemigo ahora se quedará en esta sala y puede herir
al personaje del jugador. Pero necesitamos agregar más variedad
enemiga a nuestro juego. Te veré en el siguiente video.
52. 7-3 Detección de bordes: Hola, amigos. En este video, agregaremos otro
enemigo que puede detectar cuñas y darse la vuelta en lugar
de alejarse de ellas. Empezaremos duplicando a
nuestro enemigo existente. Al abrir la escena del enemigo, cambiaremos el
nombre del nodo raíz para que coincida con el enemigo. Importe su hoja de sprites y configúrela como atlas
en el inspector Todos los sprites
para la hoja de Sprite son los mismos que el primer enemigo, así que no hay nada que arreglar
en términos de animaciones En mi escena de contenido de habitación, eliminaré a los dos
enemigos y agregaré este nuevo enemigo luego editaré el terreno para que estén en una terraza elevada con una repisa a cada lado
de diferentes alturas Quiero que este enemigo se detenga
en la repisa más alta, espere un momento, luego se dé la
vuelta y camine en
la otra dirección Pero entonces deberían caminar
fuera de la repisa más corta. En lo que respecta a los muros, deben actuar de la misma
manera que el enemigo anterior. Dado que este comportamiento
es tan similar, sería bueno
usar el mismo script. Entonces agregaré una nota de temporizador
como hijo del enemigo. Renombrarlo, adjuntarle el guión de
ritmo y establecer su
propiedad one shot en true. Entonces este enemigo debería comportarse
exactamente como el ratón ciego. Ahora solo tenemos que
averiguar cuándo el enemigo está caminando
hacia una repisa, lo cual podemos hacer usando
un nuevo tipo de nodo,
un nodo D de lanzamiento dos Nombraremos este detector de borde de
nodo. Después muévalo una corta distancia hacia la derecha del personaje y hacia arriba. El rayo tiene una máscara de
colisión que ya
está establecida en la
capa uno para el terreno. Ampliando el colisionar
con sección, nuestro terreno es un cuerpo físico, por lo que el rayo chocará con él Si usa un
nodo de transmisión de rayos para detectar áreas, deberá verificar las áreas
aquí antes de que funcione. El reparto de rayos se representa
en el editor como una flecha, pero será invisible
mientras el juego se esté ejecutando, al igual que nuestros nodos de área de
colisión. Dispara un rayo
partiendo de su posición en dirección a la flecha e informa si golpea o
no algo. En este caso, tanto
si golpea terreno como si no. Entonces, si golpea terreno, el enemigo seguirá
caminando hacia adelante, y si no lo hace el
personaje necesita detenerse. La distancia a la derecha
del personaje
determinará qué tan adelante
buscarán la repisa La distancia hacia arriba desde el
suelo no tendrá mucho efecto siempre y cuando esté por encima del suelo y por debajo de la altura
del personaje. La posición objetivo debe apuntar hacia abajo para
detectar el suelo, pero hasta qué punto dispara
el rayo afectará lo que considera que es una
repisa y lo que no Voy a poner el mío para que sea 64
píxeles abajo o dos mosaicos. Esto quiere decir que si
el enemigo se encuentra con una repisa que
solo tiene una baldosa de altura, seguirá caminando. Pero si son dos o
más tejas de altura, el rayo no golpeará el terreno, y por lo tanto, el
enemigo se detendrá. Sin embargo, a diferencia de las áreas de colisión, el nodo de lanzamiento de rayos no emite ninguna señal a la
que podamos reaccionar. Así que tendremos que adjuntar nuestro
propio script a este nodo. Lo pondré en la carpeta de guiones
enemigos. Podemos comenzar declarando
nuestra propia señal, que vamos a querer admitir
cuando se detecte una repisa y pasar por la
dirección de la repisa en relación con el
enemigo como No es tan
sencillo como si el rayo está pegando
o no a
algo, aunque. Similar a como hicimos que
el temporizador Coyote solo arrancara en el marco exacto cuando el personaje se baja
de una repisa, solo
queremos detectar una repisa una vez durante el fotograma exacto cuando el rayo deja de chocar
con
el Entonces necesitaremos una variable booleana para saber si el rayo golpeó o no el último fotograma del
terreno y otros cuatro si golpeó
terreno este Durante el proceso de física, vamos a establecer estaba colisionando con el valor anterior
de está colisionando, luego colisionando al valor actual
devuelto por
el Si el rayo estaba colisionando último fotograma pero no está
colisionando este fotograma, este es el
momento exacto en el que hemos detectado una repisa y
emitiremos nuestra señal La dirección de la
repisa puede ser solo el signo de la
posición del nodo Conectemos nuestra señal
detectada de repisa al script
de ritmo y llamemos a una función llamada
wait and turnaround Podemos copiar estas tres
líneas desde arriba, que le dicen al enemigo que se detenga, cambia la dirección del ritmo
y arranca el temporizador Después reemplazarlos por
una llamada a nuestra función. Pero tendremos que pasar
lo contrario de las paredes normales X como argumento de
dirección para que coincida con lo que está
pasando por el detector de bordes. El detector de repisa envía la
dirección hacia la repisa. Entonces aquí tenemos que dar la
dirección hacia la pared. La nueva
dirección de estimulación es, por lo tanto la opuesta al parámetro de
dirección Esto funcionará
siempre y cuando el enemigo se
mueva hacia la derecha, pero tendremos que reposicionar el nodo de lanzamiento a la
izquierda del enemigo cuando se dé la vuelta Afortunadamente,
ya hemos emitido una señal cada vez que un
personaje cambia de dirección. Entonces todo lo que tenemos que hacer es conectar esta señal al
detector de borde para reaccionar ante él. Vamos a renombrarlo en enemigo
cambió de dirección. Dado que esto nos da
su nueva dirección, simplemente
estableceremos la posición de los
nodos para que sea el valor absoluto de su posición multiplicado
por uno negativo si la dirección es menor que cero
o positiva en caso contrario. Rastreando esta omisión de señal de
dirección cambiada nuevo al guión del personaje Originalmente escribí
esto pasando la variable de dirección de movimiento
como parámetro de señal. Sin embargo, esto no funciona en el contexto en el que estamos
usando este personaje enemigo, ya que el valor de la
dirección de movimiento no necesariamente coincidirá con la dirección que les estamos diciendo que enfrenten. Entonces, en lugar de
pasar la dirección del movimiento, es más preciso
pasar uno negativo si le dice al personaje que mire hacia izquierda o uno positivo para la derecha. Ahora, el ray cast dende siempre
estará frente al
personaje,
ya sea que estén
mirando a la izquierda o a la derecha Vamos a activar las formas de
colisión visibles para que podamos ver el lanzamiento del rayo mientras el
juego se está ejecutando y golpear play. El rayo fundido se dibuja en rojo cuando está colisionando
con algo Nuestro enemigo se acerca
a la primera cornisa. El lanzamiento del rayo se vuelve azul para indicar que no está
golpeando nada, y el enemigo se detiene
por un corto tiempo, luego se da la vuelta y
va por el otro lado. Al acercarse a
la repisa más corta, el rayo lanzado es
lo suficientemente largo como para que aún
golpee el terreno, por lo que el enemigo se aleja y continúa en
la misma dirección Eventualmente chocan contra la pared
invisible en los bordes más alejados de la habitación y se dan la vuelta
como lo hace el enemigo anterior. Ahora tenemos un segundo tipo de enemigo que se comporta
de manera diferente al primero, pero necesitamos mucha más variedad
para que nuestro juego sea divertido Te veré en el siguiente video.
53. 7-4 Vuelo: Hola, amigos. En este video, agregaremos un enemigo volador
que rebota alrededor de una habitación Empecemos importando una nueva hoja de sprites
para el enemigo volador Después duplicando una de
las escenas enemigas existentes. Después de abrir la
nueva escena enemiga, cambiaremos el nombre del nodo raíz para que coincida e intercambiaremos el atlas con la hoja de sprites
adecuada Estos sprites son de
32 píxeles cuadrados, a diferencia de los otros enemigos hasta ahora Entonces voy a ajustar la posición Y del Sprite ahora para
bajarlo ligeramente Este enemigo no tiene animaciones
separadas de ralentí y
caminando, así que eliminaré la animación de
caminata y editaré la animación inactiva para tener el
número correcto de fotogramas. Luego edite los valores con clave para que la animación inactiva tenga
la altura de píxel correcta Ahora la animación inactiva
se ve correcta. Al activar la visibilidad de la forma de
colisión del cuerpo del personaje, giraré 90 grados para que
la cápsula quede horizontal, lo que
coincide más cerca de la forma de este enemigo y ajustaré su
radio y altura según sea necesario. Entonces haz lo mismo
con la Caja Hurtada. Y el daño de contacto golpeó la caja, asegurándose de que se ajusta al
tamaño y forma del enemigo, por lo que cualquier daño infligido
al jugador se sentirá justo En cuanto a la máquina de estado del
árbol de animación, ya que en este momento solo hay una
animación, solo
necesita tener un estado
inactivo que haga la transición de inicio a inactivo En cuanto al guión adjunto al nodo raíz de este
enemigo, no
necesitamos que este
enemigo camine o salte, pero aún necesitamos que este enemigo pueda enfrentar a
izquierda o derecha, tener aceleración
y desaceleración, verse afectado por la gravedad y la velocidad
terminal, etcétera Así que hay suficiente
beneficio para seguir usando el mismo guión de caracteres aquí en lugar
de comenzar desde cero. Pero hay suficiente diferencia en el comportamiento de
un enemigo que puede volar como para que escribamos una nueva subclase que
herede del carácter Así que vamos a crear un nuevo
script llamado Flying Enemy, heredando del personaje, y guardarlo en la carpeta de
scripts enemigos Nuestro enemigo volador
necesitará una dirección para volar. A diferencia de caminar o correr, que se representa como un flotador, ya que solo necesita
preocuparse por el eje X, una dirección de vuelo puede ser
cualquier dirección en el espacio D, por lo que la almacenaremos
en un vector dos. También necesitaremos una variable
booleana para saber si este
enemigo está volando o no actualmente Luego podemos anular
el proceso de física para incluir una nueva verificación para ver
si el enemigo está volando, y si es así, llamar a una función de
física voladora. Si el enemigo no está volando, entonces podemos llamar como normal a la definición
de
súper clase del
proceso de física. También es posible que desee exportar
una velocidad de vuelo como flotador si desea tener
un enemigo que tenga diferentes velocidades de caminata
y vuelo. Le voy a dar un valor predeterminado
de 100 píxeles por segundo. Sostendré Control o comando y pulsaré sobre
esta función llamada al proceso de física de
la superclase para ir directamente a su declaración para que
podamos echar un vistazo a
lo que contiene Tenga en cuenta que la llamada a la función move and
slide está dentro de la definición
de superclase de nuestro proceso de física debe llamar a esta función para aplicar el cuerpo del personaje
a la velocidad de los Dnodes y verificar si hay colisiones También queremos que
nuestro enemigo volador enfrente
a la dirección en la
que están volando. Entonces tendremos que hacer eso en
la función de física voladora. Copiaré este bloque
de código y volveré al guión
del enemigo volador y lo
pegaré en mi física voladora. En lugar de verificar el
valor de la dirección de movimiento, tendremos que verificar el valor
de la dirección de vuelo punto X. También
tendremos que
llamar a la función de movimiento y deslizamiento si
el enemigo está volando. Entonces podemos aplicar una
lógica similar que usamos para el control
aéreo en nuestros personajes
no voladores para hacer volar a nuestro enemigo volador. Si la dirección de vuelo tiene un valor, moveremos la velocidad del
enemigo hacia la dirección de vuelo
multiplicada por velocidad de
vuelo a una velocidad de aceleración multiplicada por el control aéreo
multiplicado por Delta. O si no se da ninguna
dirección de vuelo, podemos mover su velocidad
hacia el vector dos punto cero a una tasa de desaceleración multiplicada por los frenos aéreos
multiplicados por Delta O. Cuando estábamos editando
solo Velocity dot X, que es un float, un tipo de datos
primitivo, tuvimos que llamar a Godot
move direction function para
poder editarlo Pero como un vector
dos es una clase, puede tener sus propias funciones. Sostener control o comando y hacer clic en el
nombre de
la clase nos lleva a la documentación
de esa clase donde podemos ver todas sus propiedades y funciones si es necesario. Así que aquí tenemos la opción de llamar a velocity
dot move into, que difiere de
Godot función move into en que el
primer parámetro ya
se conoce como
el vector mismo También es posible que desee
exportar diferentes valores para aceleración de vuelo,
desaceleración, control de aire y frenos de aire
para sus enemigos voladores si desea que
usen valores diferentes mientras no están volando También necesitaremos una función
pública que le diga a este enemigo que vuele, aceptando un parámetro vector dos para la dirección a volar. Y otro para cuando
dejar de volar. Esto controlará la
variable está volando y establecerá la
dirección de vuelo al mismo tiempo. Recuerda adjuntar este guión enemigo
volador al nodo raíz del
enemigo en su propia escena. En la escena del contenido de la sala, igual que nuestros enemigos existentes tienen un nodo separado que les
dice cómo comportarse, haremos lo mismo
con nuestro nuevo enemigo volador. Eliminaré a este
enemigo de la escena y agregaré dos de estos
nuevos enemigos voladores. Después editaré el terreno
para encerrar a uno de ellos dentro de una caja de terreno para que podamos ver cómo se
comporta un Quiero que estos murciélagos vuelen en dirección diagonal y
reboten en cualquier pared, techo o piso con el que
entren en contacto. Entonces adjuntando un
nodo básico a ambos, lo
llamaré rebote Después, adjunte un script a este nodo y guárdalo en
la carpeta de scripts enemigos. Este script necesitará
una variable exportada para la dirección de vuelo inicial. Voy a usar el vector 21, que está abajo a la derecha. También necesitaremos una
referencia al enemigo cuyo comportamiento estamos
controlando establecido a estos nodos, padre usando la etiqueta on ready. Anulando la función ready, sería una buena idea
normalizar la dirección de la mosca La normalización de un vector
asegurará que tenga una
longitud de exactamente uno Dado que un vector con un valor
de 11 es más largo que uno, esto daría como resultado que el murciélago volara más rápido que
su velocidad de vuelo. Pero si normalizamos el vector, solo
estamos usando la
dirección del vector, no su longitud. Al anular la función de proceso, podemos decirle al enemigo que vuele en la dirección de
vuelo deseada Pero antes de hacer eso,
tendremos que verificar si este enemigo está actualmente en contacto con
alguna pared, techo o piso. Entonces podemos establecer el punto de dirección de
vuelo X o punto e Y al
valor apropiado en cualquiera de estos casos. Para el techo,
el valor será el valor absoluto del punto Y de dirección de
vuelo, haciéndolo siempre
positivo, que es abajo. Y el piso es lo contrario, multiplicando el valor absoluto por uno negativo, que está arriba Para las paredes, podemos simplemente
multiplicar el valor absoluto del punto X en dirección de
vuelo por el
signo del punto X normal de pared, que apunta lejos de la pared. le adjuntaré el
guión de rebote al otro enemigo, También le adjuntaré el
guión de rebote al otro enemigo, luego le pegaré a play Cuando ejecutamos el juego, podemos ver que el bate rebota alrededor, rebotando en
cada pared, techo
y piso que toca, creando un obstáculo interesante
para que el jugador evite Ahora tenemos un
enemigo volador para luchar, pero al menos deberíamos tener un tipo de enemigo más para que nuestros
jugadores se enfrenten. Te veré en el
siguiente video.
54. Arrastrar de 7 a 5: Hola, amigos. En este video, haremos un enemigo que pueda
arrastrarse a lo largo de cualquier superficie, incluyendo paredes y techos Empecemos importando una hoja de
sprites para este enemigo. Después duplique al enemigo volador. Después de abrir la
nueva escena enemiga, voy a renombrar el nodo raíz. Luego intercambia el atlas de la textura
del atlas de dos
nodos D de Sprite por la hoja de
Sprite apropiada En el Jugador de Animación del enemigo, actualizaré la
animación ociosa para que tenga el número correcto
de fotogramas
que proporciona
la hoja de Sprite Actualización de los valores de
región con clave según sea necesario. Como queremos que este
enemigo se arrastre no solo por el suelo sino también por
las paredes y el techo, sería útil
que podamos rotar al enemigo Con el
origen del enemigo a sus pies, la forma en que hemos hecho a
todos los demás enemigos, girándolos girará
todo sobre este punto. Para facilitar un poco las cosas, sería mejor hacer que el punto de
origen de los enemigos que se arrastran esté en su centro para que
estas rotaciones se vean Entonces
centraré el
sprite y todas las formas de colisión para que se centren en el punto de origen Ahora cuando rotemos a este enemigo, éste permanecerá en la
misma posición relativa. Ajustaré rápidamente
la caja de daño y la caja golpes para que se ajuste mejor a
la forma de este enemigo. Para la forma de colisión del
cuerpo del personaje, sin embargo, usaré un círculo
en lugar de una cápsula. Dado que este enemigo puede rotar, la forma de colisión al ser un círculo significa que
las rotaciones
no darán lugar a ningún cambio
en lo que este enemigo
está colisionando con Si estás usando rotaciones estrictas de
90 grados, una
forma de colisión cuadrada también funcionaría, pero requeriría
algunos pasos adicionales cuando se trata de esquinas convexas Entonces me apegaré a usar un círculo. En la escena del contenido de la habitación, retiraré los murciélagos y los
reemplazaré por dos caracoles El objetivo es que estos
caracoles se arrastren por la
superficie interior y exterior de esta Al igual que creamos
un nuevo guión heredado del personaje
para enemigos voladores, escribiremos otro para rastrear enemigos y lo guardaremos en
la carpeta de scripts enemigos Después reemplace el guión adjunto al enemigo
por este nuevo guión. Voy a reducir la velocidad de mi
caracol ajustando su velocidad de caminata a solo
32 píxeles por segundo Primero, necesitamos saber la dirección hacia la superficie en
la que este enemigo se
arrastra actualmente como vector dos Entonces también la
dirección de rastreo hacia adelante como otro vector dos También tendremos que manejar nuestras propias colisiones aquí en
lugar de confiar en la función de
movimiento y deslizamiento del cuerpo del personaje para hacer toda la física por nosotros. Entonces podemos almacenar
datos de colisión en otra variable de tipo colisión cinemática dos D. Anulando el proceso de
física, verificaremos si este enemigo está actualmente pegado a una superficie,
y si es así, llamaremos al
proceso de física para gatear Si no están
pegados a una superficie, podemos llamar al proceso de
física de superclase Esto funciona porque un vector dos con sus valores predeterminados de cero, cero será tratado
por la sentencia if como falso y cualquier
otro valor como verdadero. Si no están
pegados a una superficie, también
vamos a querer comprobar si este enemigo puede
pegarse a una superficie. Llamando a una
función ligeramente diferente a move y slide, llamaremos move y colisionaremos Esta función acepta el movimiento del personaje como
primer parámetro, que es su velocidad
multiplicada por Delta. La función devuelve una colisión
cinemática dos D, que podemos asignar
a nuestra variable la misma manera que nuestro vector dos se puede usar en
una declaración if, también lo pueden hacer estos datos de colisión. Si no se produjo ninguna colisión, se considerará como falsa. Y si se produjo una colisión, se considerará verdadera. Si este enemigo
chocó con algo, entonces asumiremos
que quieren atenerse a él y establecer el valor
de pegado a la superficie Podemos acceder a las colisiones normales llamando a la función
get normal Este es un vector que apunta
lejos de la superficie con
la que el personaje colisionó
en el punto de colisión Como queremos que el valor de esta variable esté
hacia la superficie, no lejos de ella, simplemente
podemos girarla 180 grados llamando a
la función girada. Pero las rotaciones en Godot
no usan grados. Utilizan radianes, y 180 grados es
lo mismo que los radianes Pi Oh, si el enemigo no
colisionó con ninguna superficie, entonces llamaremos al proceso de física de
superclase Pero el proceso de
física de la superclase también está aplicando la velocidad del
personaje cuando llama mover y deslizar Siguiendo este código, la velocidad del
personaje se está
aplicando dos veces cada fotograma siempre y cuando no
toquen ninguna superficie. Podemos arreglar esto pasando un segundo parámetro opcional a la función move and
collide, que es una prueba con nombre booleano Si es true, esta función solo
verificará colisiones pero
en realidad no moverá al personaje Ahora que nuestro enemigo se adherirá automáticamente
a cualquier superficie, podemos adentrarnos en la física de arrastrarnos por esa superficie Primero, aplicaremos gravedad hacia la superficie a
la que está pegado el enemigo, ya que no lo hicimos antes para la prueba de colisiones, y esto también ayudará a mantener al enemigo en
la superficie por la
que se arrastran Llamando a mover y colisionar, pasando la dirección
hacia la superficie, multiplicado por gravedad,
multiplicado por Delta, nuestros datos de colisión ahora
mantendrán la colisión
con la superficie Entonces podemos ramificarnos en base si ocurrió o no una
colisión. En caso de que
el ángulo de la superficie cambie, podemos actualizar la dirección
hacia la superficie de rastreo, luego calcular la dirección
hacia adelante, que es solo la
dirección hacia la superficie girada 90 grados Si Pi es 180 grados, entonces Pi dividido por
dos es 90 grados. No obstante, el sentido
de rotación
dependerá de si el enemigo
está mirando hacia la izquierda o hacia la derecha. Si están orientados hacia la izquierda, entonces tenemos que
rotar en el sentido de las agujas del reloj. Si están orientados hacia la
derecha, giramos sentido antihorario para obtener su
dirección orientada hacia adelante como un vector dos Y si estos valores han cambiado desde el fotograma
anterior, también necesitaremos actualizar la rotación del enemigo
para dibujarlos de la manera correcta. Dado que el enemigo está mirando hacia la derecha en su escena
con una rotación de cero, todo lo que tenemos que hacer es usar la dirección hacia adelante y luego
llamar a la función de ángulo. La función ángulo
devuelve el ángulo entre cualquier vector dos y
el eje X positivo. Pero como estamos usando una escala X
negativa para voltear al personaje
cuando mira hacia la izquierda, también
tendremos que corregir
esto en la rotación, girando otros 180 grados o radianes Pi si el
enemigo está mirando hacia la izquierda Ahora que tenemos al enemigo
pegado a la superficie, y sabemos en qué dirección
quieren gatear,
entonces si se le dice al enemigo que
se mueva, finalmente
podremos usar la función
mover y colisionar nuevamente para moverlos en
su dirección hacia adelante, multiplicada por la
velocidad de movimiento, multiplicada por Delta Si hay alguna colisión como
resultado de este movimiento, eso significa que han chocado
con una esquina cóncava Todo lo que tenemos que hacer aquí es recalcular la dirección
hacia la nueva superficie El siguiente marco de física
se encargará del resto. Si no hubo colisión, entonces el enemigo se arrastra
suavemente a lo largo de una superficie plana o convexa Si no se dio
dirección de movimiento, se quedarán quietos. Volviendo todo el camino de regreso a
la primera declaración if, si la gravedad hacia la superficie no
resultó en una colisión, eso significa que el enemigo de alguna manera ha perdido el contacto con la superficie sobre la
que se arrastraban Entonces deberíamos llamar a una
función que los
restablecerá de nuevo a una orientación
normal. Lo llamaré unstick
y lo haré público para que
otros guiones puedan llamarlo. Esta función restablecerá la dirección a
la superficie de nuevo al vector 20 y la
rotación a cero, devolviéndolos a un estado de comportamiento que es
igual que cualquier otro enemigo. todavía falta una cosa Sin embargo, todavía falta una cosa en nuestra
física
de rastreo, que es decirle al enemigo que se
enfrente a la dirección
en la que se mueve, ya que eso se estaba haciendo en el proceso de física de la superclase En lugar de copiar y
pegar el mismo código aquí, movamos esto a una función privada en
la clase de caracteres Entonces podemos llamar a esta función tanto
en este guión de personaje, también en el guión
enemigo que se arrastra En lugar de crear
un nodo
y un script separados para decirle a
este enemigo que se arrastre, exportaré una variable entera
para la dirección Krall Luego anule la
función de proceso y hágalo aquí. Para fines de prueba,
también anularé la función de
entrada para que la flecha hacia abajo los fuerce a despegarse de cualquier
superficie en la que se estén arrastrando Cuando corremos el juego, el
caracol se arrastra alrededor de esta caja, girando tanto en las esquinas cóncavas como convexas para trepar por
las paredes y nuevamente para
arrastrarse por el techo Al presionar la flecha hacia abajo, los
hace desprenderse de la superficie y caer a la gravedad
como lo haría cualquier otro enemigo Ahora tenemos nuestro tipo de enemigo
final, uno que puede arrastrarse por
paredes y techos Pero nuestros enemigos deberían ser más agresivos hacia
el personaje jugador. Te veré en el siguiente video.
55. Vista de 7-6: Hola, amigos. En este video, daremos a algunos de nuestros
enemigos la capacidad de
percibir y reaccionar ante la presencia del personaje
jugador. En la escena del contenido de la habitación, voy a quitar los caracoles
y la caja de terreno Reemplácelo por un
bloque en dos lados, luego ponga una nota del ratón en su interior que vaya a caminar de un
lado a otro entre ellos. Añadiré el nodo temporizador, adjuntaré el script de ritmo y estableceré su
propiedad one shot en true. Para que este enemigo actúe agresivamente hacia
el personaje jugador, necesita una forma de detectarlo. Tendremos que usar múltiples
herramientas para lograrlo. Primero, agregaremos un nodo D de área
dos a nuestro enemigo. Y un
nodo de forma de colisión para el área. Esta zona representará todo
el alcance del campo de visión del
enemigo. Es posible que desee usar
un cuadrado girado 45 grados una cápsula o un círculo. Si usa un nodo D de polígono de colisión dos en lugar de un nodo D de forma de
colisión dos, en realidad
puede crear
un polígono personalizado en lugar de usar formas preestablecidas Simplemente haga clic en el editor para dibujar cada vértice de
la forma que desee Esto nos permite hacer
un triángulo o un abanico, que es una mejor representación
de un campo de visión. Ampliando la
propiedad del polígono en el inspector, podemos ver las posiciones
de cada vértice, editarlas y
reorganizarlas Sea cual sea la forma que
elijas usar, asegúrate de que tu forma solo
tenga ángulos convexos. Si tu polígono es cóncavo, Godot lo dividirá en múltiples formas
convexas más pequeñas y como resultado,
duplicará el costo de
los cálculos de colisión si decides usar , si decides usar
una forma de
colisión simétrica normal, Sin embargo, si decides usar
una forma de
colisión simétrica normal, voltear al enemigo izquierda y derecha es mucho más fácil, ya que solo puedes
usar el mismo método que
usamos con el lanzamiento del detector de
bordes, estableciendo su propiedad de posición el enemigo
cambie de dirección Con el
polígono de colisión dos nodos D, sin embargo, el proceso es un
poco más complicado No podemos simplemente mover su posición, y tampoco debemos cambiar
su propiedad de escala. Si abrimos la documentación
para este nodo, específicamente advierte contra esto afirmando que
probablemente no se comportará como se esperaba. Si decidimos usar estos polígonos de colisión para formas
no simétricas
que necesitamos voltear, tendremos que editar manualmente las posiciones de cada uno de
los vértices en , el campo de visión no
será suficiente por sí solo Sin embargo, el campo de visión no
será suficiente por sí solo, ya que
no hay nada que le impida
atravesar muros. Si queremos que el enemigo detecte
al jugador con una línea de visión
despejada, necesitaremos otro nodo para verificar que un rayo arroje dos nodos D. Querrás
posicionar esto cerca de los ojos del enemigo desde donde realmente
estarían observando, pero mantenlo centrado
horizontalmente. Voy a cambiar el nombre de esto
a la línea de visión. La línea de visión
estará colisionando
tanto con el terreno como con el cuerpo del personaje del
jugador, siendo
ambos cuerpos Esto permitirá que el terreno
bloquee su línea de visión, incluso si el personaje del jugador está dentro de su campo de visión. Con el campo de visión seleccionado, solo
necesitaremos esto
para estar
monitoreando, enmascarando el cuerpo del jugador. Eliminaré el nodo de forma y solo usaré el polígono
como mi área de colisión Entonces dale tanto a él como
al elenco nombres únicos. Adjuntando un script al área de
campo de visión para dende, lo guardaremos en
la carpeta de scripts enemigos Tomemos referencias
al nodo de forma o polígono y al nodo de línea de visión usando la etiqueta ready Lo que me gustaría de esta
configuración es que el enemigo reaccione ante el
personaje del jugador después de que ambos
hayan entrado
al campo de visión y el enemigo tenga una
línea de visión directa con el jugador. Si el
personaje jugador sale del campo de visión y se rompe la
línea de visión, entonces me gustaría que el enemigo
volviera a su comportamiento normal. Consideremos cómo
queremos que este nodo se comunique con otros
nodos a través de señales. Vamos a necesitar este nodo
para reportar dos cosas cuando el enemigo haya adquirido un objetivo y cuando
haya perdido su objetivo. Estos serán los
momentos exactos en los que queremos cambiar
su comportamiento de su ritmo predeterminado de ida
y vuelta y en
su lugar
decirles que comiencen a actuar de manera más
agresiva o viceversa Podemos conectar las señales de
cuerpo ingresado y de
salida del cuerpo desde el
campo de visión al guión Y esto nos
dice con bastante facilidad cuando el personaje
jugador entra y sale del campo de visión. Tendremos que almacenar esto en
una variable llamada target. Como el parámetro
es un no dos D, también
estableceremos el tipo de variable como un no dos D para
mantener las cosas simples. También necesitamos una variable
booleana para saber si el enemigo
está actualmente apuntando o no, si el objetivo se encuentra
actualmente dentro del campo de visión y si el enemigo tiene
actualmente línea de
visión hacia el Cuando un cuerpo entra en
el campo de visión, entonces set is in field of view a true y establece target to be body. Cuando el cuerpo abandona
el campo de visión, podemos ponerlo de nuevo en falso. Recuerda que solo estamos
enmascarando al personaje jugador, así que ya sabemos que este cuerpo es el personaje
jugador. Anulando el proceso de física, si todavía no hay un objetivo, simplemente
podemos regresar ya que no
hay nada que hacer Ahora podemos suponer que
el personaje jugador ha entrado al campo
de visión al menos una vez. A continuación, apuntaremos la línea
de visión al objetivo. Podemos crear un vector
apuntando de A a B restando A de B. Así que la posición objetivo
del raycast será la global
del objetivo
menos nuestra posición global Entonces el valor de está en línea
de visión va a ser cierto si lo que
está golpeando el colisionador es lo
mismo que el objetivo Si el lanzamiento del rayo golpea el
terreno o no golpea nada en absoluto,
esto será falso. Tenga en cuenta que cuando ocurre el proceso de
física, las colisiones ya han
sido calculadas por Godot Entonces, cuando apuntemos la línea de visión al
personaje del jugador en la línea de arriba, los datos de colisión que resulten no
estarán disponibles
hasta el siguiente fotograma. Lo que estamos comprobando aquí son los resultados
de colisión del cuadro anterior. Si por alguna razón
necesitas absolutamente un elenco para
actualizarlo de inmediato, puedes llamar a su función force
RycaStudate Pero con el juego funcionando
a 60 cuadros por segundo, el retraso no se notará y esto funcionará bien
tal y como está. Ahora todo lo que tenemos que hacer es emitir nuestras señales en los momentos
correctos. Si el enemigo no está apuntando
actualmente, pero el objetivo está en
su campo de visión, y tiene línea de
visión hacia el objetivo, entonces el objetivo
ha sido adquirido. Así que vamos a establecer está apuntando a true y emitir la señal adquirida
objetivo, pasando el objetivo
como argumento. Y en el escenario completamente
opuesto, si actualmente están apuntando, pero el objetivo no está
en su campo de visión y no
tienen línea de visión, entonces hemos perdido el objetivo. En este caso,
también sería una buena idea volver
a establecer el valor de
target en Nulo, lo que impedirá que el
proceso de física revise algo más hasta que
vuelvan a ingresar al campo de visión. También vamos a imprimir cuándo suceden
estos eventos para que
podamos probarlos. Lo último que
tenemos que hacer es voltear nuestro polígono de colisión cuando
el enemigo cambia de dirección, lo que podemos hacer conectando la
señal de dirección cambiada a nuestro script Si estás usando una forma
simétrica, todo lo que necesitas hacer es
reposicionarla al otro lado
del personaje Pero estoy usando un polígono, lo que significa que voy a necesitar editar
los vértices individuales Comenzaré por obtener
la matriz existente del polígono y
almacenarla en una variable El tipo es una matriz de dos
vectores empaquetados. Entonces puedo iterar a través de
cada uno de los vértices y usar la misma estrategia para
voltear su exposición al otro lado del personaje si
están orientados hacia
la La matriz de
vértices proporcionada por el polígono aquí es solo una copia, no la matriz real en sí Entonces, cuando editamos sus valores, en
realidad no afecta
al polígono de colisión Para que los cambios
realmente funcionen, necesitamos sobrescribir la matriz existente
con la copia editada Vamos a activar formas de
colisión visibles desde el menú de depuración
y probarlo. Podemos ver a nuestro enemigo paseando de un lado
a otro entre las dos paredes y
el polígono de colisión se voltea
cuando se dan Al entrar al campo de visión, el nodo de lanzamiento de rayos comienza a
rastrear nuestra posición, pero el enemigo aún
no ha visto ya que su línea de visión está
bloqueada por el terreno. Si saltamos hacia arriba, la línea
de visión ya no se obstruye y obtenemos la salida del mensaje
objetivo adquirido Dejando el campo de
visión del enemigo y también su
línea de visión, el
mensaje del objetivo perdido aparece y el elenco ya no está
rastreando nuestra posición. Ahora tenemos a nuestro enemigo capaz detectar la presencia del
personaje jugador, pero aún así
necesita reaccionar ante ella. Te veré en el siguiente video.
56. 7-7 Agresión: Hola, amigos. En este video, tendremos al enemigo persiguiendo
y atacando al jugador. Comenzando en la escena del enemigo, tendremos que agregar un
ataque para este enemigo. Duplicando la animación inactiva, rápidamente
fotografearé
los sprites adecuados para la animación de ataque del enemigo. Esta animación de ataque realmente
no comunica la
cantidad de área que va a golpear el
ataque. Sólo muestra el propio movimiento del
enemigo. Necesitaremos un
sprite separado para eso. Haré una nueva carpeta de Sprite para los
sprites de
efecto e importaré una hoja de sprites para el efecto de ataque de este
enemigo. Añadiremos un Sprite Animado para denodar como hijo del Sprite
del enemigo, por lo que automáticamente volteará
horizontalmente cuando el
enemigo se dé la vuelta horizontalmente cuando el
enemigo se dé la Luego crea un nuevo
recurso de marcos de Sprite y agrega los sprites de la hoja
de Sprite Como siempre, agregaré un sprite en blanco al
final de la animación, estableceré su velocidad de fotogramas en 12 fotogramas por segundo y no en un ciclo. Pondré esta animación
en su primer sprite, que muestra con precisión el
tamaño y la forma del ataque Después, colóquelo
frente al enemigo. Esto hace que sea mucho más fácil agregar un hit box a este ataque. Así que vamos a duplicar
el hit box existente. Cambiaré el nombre de la caja de acierto
original para que contacte con daños y dejaré
esta nueva como caja de acierto. Ahora podemos hacer que esta caja de golpes como forma de
colisión coincida con
el efecto de ataque. A diferencia del Sprite Animado, no
deberíamos usar el truco de escalado
negativo para voltear nuestro hit box Así que tendremos que conectar la señal de cambio de
dirección del enemigo
al guión de hit boox y
reposicionarlo manualmente Como hemos hecho antes, solo
tomaremos una referencia a
la forma de colisión. Y establecer su posición a su valor
absoluto multiplicado por uno
negativo si la dirección es menor que cero o
positiva en caso contrario. En el estado predeterminado de este enemigo, no estará atacando, por lo que este hit box no
estará activo. Entonces, apaguemos su
propiedad de monitoreo y visibilidad. Luego, vuelve a
la animación de ataque donde podemos fotogramas clave estas propiedades para
activarlas durante la animación de ataque
y retroceder nuevamente. Esto también agregará
ambos a la pista de reinicio con
sus valores predeterminados. Y también podemos decirle al efecto de ataque que
juegue al mismo tiempo. En la escena del contenido de la sala, actualmente
tenemos el comportamiento
normal de este enemigo caminando de un lado a otro y una forma para que el enemigo vea al personaje
del jugador Cuando este nodo emita la señal adquirida por el
objetivo, vamos a querer cambiar el comportamiento del enemigo de
ritmo a ser más agresivo Y cuando pierdan la
pista de su objetivo, deberían retomar
su ritmo original Pero puede que no necesariamente
queramos que esto se aplique a todos los enemigos u otros personajes que estén usando el guión de ritmo. Entonces deberíamos crear
un nodo separado para un comportamiento agresivo. Usaré otro nodo temporizador
y lo nombraré agresión. Después, adjunte un
script a este nodo y guárdalo en la carpeta de scripts
enemigos. Al igual que con el guión de ritmo, necesitaremos una referencia
al enemigo que este script está controlando usando
la etiqueta ready. También tendremos que almacenar una
referencia al objetivo en
una variable hacia la que este enemigo está
actuando de manera agresiva. Y también necesitaremos conocer la dirección hacia el
objetivo como vector dos, así
como la distancia
al objetivo como flotador. Conocer estos valores
permitirá que el enemigo se
acerque a su objetivo para
entrar al alcance de ataque
antes de atacar. Pero también tendremos que especificar el rango de ataque de
este enemigo como una variable exportada,
que sería un flotador. Si quieres, también
puedes especificar un rango mínimo de ataque también. Si cambiamos el tipo
del rango de ataque
a un vector dos, podemos usar el valor X como rango mínimo y
el Y como máximo. Voy a establecer su valor predeterminado
para que esté al menos
a 32 píxeles del reproductor y
hasta un máximo de 64 píxeles. Entonces, si el enemigo está a más de 64 píxeles del personaje
jugador, quiero que el enemigo
corra hacia ellos. O si el enemigo está a menos de 32 píxeles del personaje
jugador, quiero que el enemigo
huya de ellos. Pero dentro de ese rango,
el enemigo atacará. Anulando la función de proceso, podemos ignorar a Delta, y si no hay objetivo para
este enemigo, podemos regresar Esto no debería suceder, pero
nunca es mala idea
tener un failsafe Podemos calcular
la dirección hacia el objetivo restando la posición de
nuestro enemigo de la posición
del objetivo
y luego obtener la distancia tomando ese mismo vector y
calculando su longitud Si la distancia al objetivo es mayor que nuestro rango
máximo de ataque, entonces este enemigo debe moverse
hacia el objetivo estableciendo su dirección de movimiento al signo de dirección al punto X objetivo Si la distancia al objetivo es menor que nuestro rango mínimo de
ataque, entonces este enemigo debe
alejarse del objetivo, haciendo exactamente lo contrario. Si ambas
condiciones fueran falsas, entonces el objetivo está
dentro del alcance de ataque. Entonces el enemigo debe
prepararse para atacar. Me aseguraré de que el enemigo deje moverse estableciendo su dirección de movimiento a cero y también de cara hacia el objetivo por
si acaso no lo están ya. No quiero que el enemigo
ataque enseguida, ya que mi animación de ataque es muy corta,
no está telegrafiada Entonces arrancaré el temporizador aquí y esperaré a que se
agote el tiempo antes de atacar. La propiedad
de un solo disparo de este temporizador debe establecerse en true para que
solo cuente atrás una vez. La propiedad de tiempo de espera
será el tiempo que el enemigo permanezca dentro
del rango de ataque
antes de atacar. Conectando la
señal de tiempo de espera al guión, aquí es donde le diré a
mi enemigo que ataque También es una buena idea volver a
mirar hacia el objetivo en caso de que algo haya cambiado desde que se inició el temporizador. Solo quiero iniciar el temporizador si actualmente está parado. También detendré el temporizador cada vez que el objetivo esté
fuera del alcance de ataque. Esto debería ser suficiente
para nuestro comportamiento. Ahora solo necesitamos cambiar
de un lado a otro entre nuestros dos scripts de comportamiento
en los momentos apropiados. No queremos que nuestro
script de agresión esté activo cuando el
enemigo genere por primera vez, así que configuraremos su
modo de proceso en deshabilitado Seleccionando el campo de
visión en el árbol de escenas, conectaremos la señal de destino adquirida al script de
agresión, y podremos renombrar esta
función si queremos. Para mantener las cosas consistentes entre mis diferentes scripts de
comportamiento, lo
llamaré zoom. Esta función establecerá
el valor de objetivo, cambiará el
modo de proceso para heredar, y también le dirá al enemigo que corra, lo
que hará que
comiencen a actuar agresivamente hacia el objetivo Pero también necesitamos
pausar el guión de ritmo. Entonces también conectaremos la
misma señal al nodo de ritmo. Y esta vez llamamos a una
función llamada pausa, pero esta señal
proporciona un argumento, y no lo necesitamos
para pausar este comportamiento. También podemos imaginar un escenario que quisiéramos
pausar este comportamiento en otras circunstancias
y no quisiéramos proporcionar un argumento arbitrario e
innecesario para llamar a la función de pausa. Entonces desvincularemos el argumento
proporcionado por la señal, lo que la función conectada no
tiene argumentos Aquí, todo lo que tenemos que hacer es establecer el modo de proceso en deshabilitado. Cuando el enemigo vea un objetivo, detendrá su comportamiento de
ritmo y reanudará su comportamiento
agresivo Entonces cuando pierden su objetivo, podemos hacer lo contrario, conectando la señal a los scripts y llamando a
las funciones opuestas. Configurando su modo de proceso
para heredar para
activarlos o deshabilitados para
desactivarlos Al activar el comportamiento
de ritmo, también
vamos a querer
decirle al enemigo que camine Ahora en el guión del personaje, tendremos que activar
la animación de ataque cuando le digamos al
enemigo que ataque. Para ello,
necesitaremos una referencia a la reproducción de la máquina de
estado del árbol de animación. Pero esto provocará un error en el
guión del personaje del jugador si
tenemos otra variable
del mismo nombre, ya que el personaje jugador
hereda del personaje Entonces habría una variable de
animación heredada del personaje, pero también otra declarada
en el personaje del jugador, que no está permitida, pero estamos usando para
el mismo propósito, así que en realidad podemos simplemente eliminar esta del guión del
personaje del jugador. De vuelta en el
guión del personaje, cuando se le dice que ataque, solo
necesitamos
decirle a esta reproducción que viaje a la animación de
ataque. En el Árbol de Animación, agregaremos la animación de ataque
y la transición a ella desde Inactivo con Avance Habilitado y volveremos a inactivo al
final de la animación. Si no quieres que
el enemigo pueda
moverse o cambiar de
dirección mientras atacas, entonces podemos agregar
verificaciones rápidas para ver si el nodo
actual de la reproducción de animación es ataque. Y o bien establece la dirección de movimiento a cero o regresa fuera de
la función por completo. Ahora, cuando ejecutamos el juego, una vez que el enemigo nos tiene
tanto en su campo de visión
como en su línea de visión, su comportamiento cambia de ritmo a ser más agresivo Nos perseguirán y
atacarán tras una breve pausa. Ahora tenemos un enemigo mucho
más agresivo con
el
que enfrentará nuestro personaje jugador, pero nuestro personaje de jugador realmente no
puede defenderse Te veré en
la siguiente sección.
57. Combinación 8-1: Hola, amigos. En este video, le
daremos al
personaje del jugador ataques
propios para que puedan
luchar contra nuestros enemigos. Ya le hemos dado un ataque al Caballero
ratón, y el proceso
será muy similar. Sin embargo, nuestro personaje jugador
tiene dos ataques diferentes. Podemos copiar algunos
de los nodos de
la escena nocturna del ratón
para ahorrar algo de tiempo, el hit box y el nodo
animado Sprite dos D. Cambiando a
la escena del personaje, podemos pegar estos
nodos en la escena, luego reorganizarlos según sea necesario El nodo animado Sprite dos D se
puede ordenar bajo el Sprite del
personaje, lo que se volteará automáticamente para que
coincida con
la dirección en la que se enfrenta el personaje Voy a renombrarlo para atacar efecto. Sé qué sprite
animado específico es este. El hit box, generalmente me mantendré ordenado al lado de la Caja
Hurtada como hermano Para que los
personajes del jugador golpeen la caja inflijan daño a la Caja de daño del
enemigo, tendremos que asegurarnos de que las capas de colisión y las
máscaras estén establecidas en consecuencia. Como mi personaje jugador
está en la capa de colisión nueve y su Caja de Daño está
en la capa de colisión diez, entonces
tendré a mis enemigos
en la capa de colisión 17 y sus cajas Hurt
estarán en la capa de colisión 18. abrir la configuración del proyecto, agregaré la caja de daño enemiga a mis dos
nombres de capa física D como capa 18. Entonces recuerda editar
todas mis
escenas enemigas existentes para poner sus
cajas Hurt en esta capa también. El
cuadro de golpe de los personajes del jugador se puede configurar entonces para enmascarar la capa 18 con el
fin de causarles daño. Para darle la vuelta al hit box, necesitaremos reconectar
la señal en esta escena, ya que esa
conexión de señal
no habrá copiado
de la otra escena Pero la función que escribimos antes en el
guión Hit box a la que queremos conectar esta señal se nombra en enemigo
cambió de dirección. Esto no importará,
pero si quieres ser consistente con la forma en que
nombra las cosas en tu juego, es posible que quieras cambiar el nombre
de
esta función el personaje
cambiado de dirección. Esto agregará otra
función al script, y podemos fácilmente simplemente mover el código a esta nueva función
y eliminar la anterior, ya que simplemente
hará lo mismo. Sin embargo, ahora tenemos que
entrar en la escena de los enemigos y editar su conexión de señal para conectarnos a la nueva función. Cuanto antes en tu proyecto puedas identificar estos problemas, menos tiempo y
esfuerzo
necesitarás dedicar más tarde a
refactorizar. De vuelta en la escena del
personaje del jugador, seleccionaremos el nodo Animation
Player de la jerarquía de escenas y
agregaremos una nueva animación. Nombraremos a este ataque
uno ya que hay dos animaciones de ataque diferentes y tendremos que
diferenciarlas. Después de agregar los marcos Sprite del
personaje. Voy a copiar los fotogramas clave a las otras pistas para la ropa del
personaje También podemos encender la propiedad de monitoreo del hit
box. Y la visibilidad, también, si te gusta verla
encendida y apagada en modo de depuración. Echando un vistazo
al efecto de ataque, esto no coincide con
la animación de ataque. Entonces voy a importar los sprites de
efecto adecuados para este ataque. Luego agrega una nueva animación
al recurso Sprite frames. Lo nombraré ataque uno, apagaré el ciclo,
estableceré la velocidad de fotogramas y agregaré un
fotograma vacío al final Ahora la animación de ataque
puede decirle al efecto de ataque, Sprite
Animado dos nodos D para
reproducir el ataque un efecto La
llamada a la función keyframed es solo play, que ha estado funcionando
bien siempre nuestro nodo Animated Sprite two D solo tenga una animación para Pero ahora tenemos dos animaciones
diferentes, y necesitamos especificar
cuál queremos jugar. Al hacer clic en el fotograma clave, podemos editarlo en el inspector Ampliando la sección de argumentos, podemos ver que
la función play en realidad tiene tres argumentos, todos los cuales son opcionales. Sólo nos preocupa
el primer argumento, el nombre de la animación, que podemos escribir
en el campo de texto. Si tienes curiosidad, los otros
argumentos son para ajustar la velocidad de la animación o reproducir
la animación hacia atrás. La ortografía debe coincidir exactamente con el nombre de la
animación. Voy a cambiar el nombre de la animación
predeterminada para atacar dos para que coincida con lo
que puse en la animación. Duplicando la animación de
ataque uno, también
podemos hacer una animación de
ataque dos Después de cambiar los fotogramas de sprite del
personaje, voy a copiar los fotogramas clave
a las otras pistas Después cambiar el argumento
pasando
al efecto ataque para jugar ataque dos en lugar
de atacar uno. Seleccionando Seleccionando el nodo Árbol de Animación, podemos agregar el ataque uno
y atacar dos animaciones. Después agrega una transición de
movimiento a ataque uno, luego de ataque
uno a ataque dos. Ambos tendrán su modo
avanzado establecido en habilitado, lo que significa que activaremos estas transiciones desde nuestro script. Al agregar transiciones,
dejando cualquiera de las animaciones de ataque
volviendo al movimiento, estas tendrán sus modos de
cambio establecidos al final. La transición del
ataque uno al ataque dos también
tendrá su
modo de conmutación configurado al final. Esto nos permitirá hacer la transición
a atacar uno si se presiona el
botón de ataque, y luego del ataque
uno al ataque dos si el botón de ataque
se presionó una segunda vez durante la primera animación de
ataque. Para agregar un
botón de ataque a nuestro juego, tendremos que entrar en
la configuración del proyecto, la pestaña Mapa de entrada y agregar un nuevo
evento de entrada para atacar. Usaré la tecla X
en el teclado y el botón de la cara izquierda en mi
mando, que también es X. Luego en el script del reproductor, podemos agregar otro
bloque I para ataques, amortiguando la entrada de la misma manera que tenemos con
cada otra acción Dado que el botón para activar el primer ataque y el
segundo ataque es el mismo, el guión de los jugadores solo
debe preocuparse de decirle
al personaje que ataque, no qué
ataque específico realizar. En el script del personaje del jugador, podemos agregar esta función de ataque, devolviendo un booleano igual que
cualquier otra entrada en búfer Esto no se bloqueará y
no tiene ningún costo, a diferencia de la función cast. Si la reproducción de la
animación del personaje se encuentra actualmente en estado de
movimiento, entonces voy a permitir que ataquen. Si tiene éxito, entonces podemos decirle a la
reproducción de animación que viaje
al ataque una
animación y que devuelva true o return false si el personaje estaba ocupado
haciendo otra cosa. Hay un error porque
la función de ataque está anulando la función
de ataque de la clase de personaje, pero la firma
no coincide Esto significa que o bien
los parámetros o el tipo de retorno son diferentes,
lo que no está permitido. mantener el control o comando y hacer clic en la
función nos lleva a la definición
de superclase de esta función donde podemos ver que
devuelve void, no un booleano Para poder usar esta estructura de
herencia con nuestros enemigos y
nuestro personaje jugador, sin
dejar de permitir entradas en
búfer, necesitaremos que la función de ataque de
superclase también devuelva un booleano Simplemente volveremos true para
satisfacer este requisito, y volviendo al guión del personaje
del jugador, se soluciona
el error. Pero, ¿qué pasa con el
segundo ataque? Podemos agregar un else if
block y verificar si la reproducción de la animación está actualmente en la animación
attack one. Entonces dile que viaje
al ataque dos
animación en su lugar. Activemos
las formas de colisión visibles en el menú Depurar, luego presionemos Reproducir y probarlo. Al presionar el botón de ataque, nuestro personaje reproduce el
ataque One Animation. activa el cuadro de aciertos
y se reproduce la animación del efecto. Al presionar nuevamente el
botón de ataque durante el primer ataque, también se
juega el segundo ataque. Volviendo al editor, podemos abrir el árbol remoto para ver nuestro juego actual funcionando. Explorando el árbol de escena hasta que
encontremos la noche del ratón, podemos seleccionar su caja de daño y ver sus propiedades
en el inspector, incluyendo su estado de salud actual. De vuelta al juego, podemos
atacar a nuestro enemigo y ver como cada ataque le golpea por una salud cada vez
hasta que lleguen a cero. Vamos. Ahora tenemos a nuestro personaje capaz de atacar
a los enemigos, pero nuestros personajes y enemigos
no reaccionan al ser golpeados. Te veré en el siguiente video.
58. 8-2 hits: Hola, amigos. En este video, haremos que nuestros personajes
reaccionen ante ser golpeados por ataques. Comenzando en la escena del
personaje del jugador, seleccionando el nodo
Animation Player, necesitaremos agregar una nueva
animación para ser golpeados. Para facilitar las cosas, duplicaré la animación de
guión para crear la animación de éxito. Después de actualizar los fotogramas clave de
Sprite, copiaré y pegaré en las otras pistas para animar también
la ropa del personaje Debido a que dupliqué
la animación de guión, esta animación de éxito ahora también incluye fotogramas de
invencibilidad Esto es muy útil para
evitar que los personajes daño de múltiples cajas de
golpe en rápida sucesión, lo que a menudo se siente injusto
para el jugador y también hace que el personaje
asuma repetidamente daños de cajas de golpe
persistentes, como
peligros ambientales, por ejemplo, porque se
activará una nueva colisión cuando se reactive
la Caja Hurt
al final de la
animación, si la Caja de Daño todavía se
superpone con la caja de impacto. También tenemos el
método track llamando a la función end dash,
que si recuerda, la forma en que se implementó
en la sección anterior, debe llamarse si se interrumpió el
guión. Sería una buena idea mover esta llamada de función al
inicio de la animación hit. Echemos un
vistazo a esta función en el guión del personaje del jugador. Dependiendo de los fotogramas que actives o desconectes la caja de daño, es posible que el
personaje sea golpeado mientras se reproduce la animación
del guión y, por lo tanto, interrumpa
la animación del guión. Lo que significa que nunca se llamaría a la
función de tablero final, la gravedad
del personaje nunca se restablecerá y el enfriamiento del guión
nunca comenzó Obviamente, esto es problemático, pero podemos arreglarlo fácilmente. Todo lo que realmente necesitamos
hacer es rastrear cuando el personaje está flotando
con una variable booleana Cuando empiece el guión, lo
pondremos en true. Entonces, cuando se llame a la
función end dash, comprobaremos si el personaje
está flotando primero y si es así, haremos todas las mismas cosas Entonces el conjunto se corre
a falso después. Ahora podemos llamar a esta
función en cualquier momento
que necesitemos independientemente de si el personaje es o
no gallinero. Si el personaje no es rápido, la función simplemente
no hará nada Seleccionando el nodo Árbol de
Animación y echando un vistazo a
la máquina de estado, me gustaría que la
animación hit pudiera
interrumpir cualquiera de estas animaciones de acción
existentes, así
como cualquier animación de salto o
movimiento, también. Por lo tanto,
sería una buena idea usar otra máquina de estado. Entonces voy a guardar esta máquina estatal como hice con
las anteriores. Le nombraré acciones y la guardaré en la carpeta de mi personaje
junto con las demás. Luego reemplace esta máquina de
estado una nueva y cargue la máquina de
estado de acciones como nodo. Bien. A continuación, puede agregar la animación de hit a
esta máquina de estado. Agregar una transición de inicio a acciones lo convierte
en el estado predeterminado. Luego una transición
de acciones a golpear con su
modo avanzado configurado a habilitado, y otro de volver a golpear a acciones con su
modo de cambio configurado al final. Esto nos permite activar la animación desde
cualquier estado existente, jugar a la vez, luego
regresar a nuestros otros estados. En el guión de caracteres, ya que quiero que esto
se aplique a todos los personajes, no solo a mi personaje jugador, necesitaremos hacer
una nueva variable para mantener la reproducción de
esta nueva máquina de estado. Podemos duplicar la variable
existente y cambiarle el nombre a algo así
como animaciones Hurt. La ruta a esta propiedad de
reproducción es parámetros Playback, ya que es la raíz
del Árbol de Animación. Si seleccionamos el Árbol de
Animación en el árbol de escenas y expandimos
su sección de parámetros, podremos ver las reproducciones para
cada una de nuestras máquinas de estado Así que la ruta de propiedad de
reproducción de la máquina de estado de acción ha cambiado, y
necesitamos actualizarla. Para aclarar mejor el uso de esta reproducción en relación con las animaciones Hurt,
voy
a nombrar estas animaciones de
acción de reproducción. Luego use la
función de reemplazo para cambiar todas las instancias de esta
variable con su nuevo nombre. Dado que el
script del personaje del jugador hereda esta variable, también
necesitaré
reemplazar todas las instancias del nombre
antiguo por el nuevo nombre en ese script, también Esto funcionará para
el personaje jugador, pero para que
funcione para los enemigos, también
necesitaremos actualizar sus máquinas de estado del
Árbol de Animación para que coincidan con este nuevo formato. Sólo actualizaré mi noche de ratón ya que ese enemigo está
en mi sala de inicio, y el proceso será
el mismo para cada enemigo. Haré la animación hit
en el nodo Animation Player. A continuación, guarde la máquina de estado del
árbol de animación como recurso del proyecto. Reemplácelo con una
nueva máquina de estado. Agrega la vieja
máquina de estado como nodo, agrega la animación de golpe, agrega las transiciones con los mismos modos de avance
y cambia. Renombrarlo acciones para que
coincidan con lo que
buscará el script. Ahora este enemigo tiene la
misma estructura de animación que el personaje del jugador, por lo que los guiones
funcionarán igual, teniendo dos
playbacks separados para reproducir la animación hit y
otra para acciones Una vez que se configura
la máquina de estado, puede eliminar
la máquina de estado guardada. Esto hará que la
máquina de estado se localice la escena en lugar de
un recurso compartido entre múltiples escenas. Ahora que tenemos acceso a la reproducción de
nuestra máquina de estado, necesitamos activar
la animación. Empezaremos en el guión de
Hurt Box. Tenemos una señal que se emite cuando cambia la salud del
personaje, cual estamos utilizando para
actualizar el elemento HUD Pero esta señal
también se emite cuando inicializamos la
salud del personaje al inicio, así
como cada vez que el
personaje recuperaría la salud Por lo que no es la mejor señal
para usar para recibir daños. Declararemos una nueva
señal para eso. Si quieres que
el personaje reaccione
ante diferentes cantidades
o tipos de daño, es posible que quieras darle parámetros a
esta señal. Voy a añadir un parámetro
para la dirección de
la que proviene el daño, como factor dos. Pero no podemos obtener esa
información de aquí. Solo tenemos acceso
a la Caja de Heridos y no a la caja de impacto
que causó los daños. Entonces cambiando
al guión de Hit box, aquí tenemos acceso tanto
al hit box como al Hurt Box. Entonces agregaremos esto como otro argumento pasado por
la función take damage. Podemos calcular la
dirección de A a B restando A de B, luego normalizar el resultado Normalizando ignoraremos
la distancia entre A y B estableciendo la
longitud del vector en uno De vuelta en el script de Hurt Box, agregaremos el parámetro
direction. Cuando nuestra caja de Rebaño
reciba daño, emitiremos la señal y pasaremos por la
dirección con ella. Nuestro guión de personajes
ahora puede reaccionar a esta señal. Cambiaré el nombre de la función
conectada a on damage received
for simplicity. Bien. Primero le diremos a la reproducción de animación Hurt que viaje
al estado hit. Después también agrega una fuerza
al cuerpo del personaje en la
dirección del daño. Dado que la dirección
está normalizada, tendrá una
longitud de un píxel. Podemos multiplicar esto
por cualquier número que queramos para alterar cuán impactante se sentirá la fuerza
knockbck Incluso es posible que
desee exportar esto como una nueva variable para que se pueda ajustar para cada carácter
individual También tendremos que hacer esta conexión de señal en
todas nuestras escenas de personajes. Et lo prueban.
Mi personaje ahora puede atacar al enemigo y el
enemigo reacciona al ser golpeado
tanto por el juego como por la animación
y también
se aplica una fuerza de retroceso. Lo mismo le sucede también a mi personaje cuando el
enemigo me ataca. Ahora tenemos a nuestros personajes
reaccionando al recibir daño, pero nuestro combate no
se siente muy jugoso. Te veré en el siguiente video.
59. 8-3 jugos: Hola, amigos. En este video, agregaremos algunos efectos de
partículas a nuestro combate para que se
sienta más impactante. Comenzando en nuestra escena de
personajes de jugador, agregaremos un nuevo tipo
de nodo a nuestra escena, un nodo emisor de partículas Godot tiene dos
tipos diferentes, CPU y GPU. El nodo de partículas de la CPU
renderizará las partículas de la misma manera que estamos dibujando nuestros sprites de personajes usando el procesador
central del dispositivo, que es menos eficiente pero más compatible con dispositivos más antiguos Mientras que un
nodo de partículas GPU delegará dibujo de estas partículas por completo a la tarjeta gráfica del dispositivo, que es más eficiente pero
solo en dispositivos modernos. El nodo de partículas GPU puede manejar número
mucho mayor de partículas sin sacrificar el rendimiento Solo recomendaría
usar partículas de CPU si estás apuntando específicamente a teléfono o tableta para tu juego. De lo contrario, deberías
usar partículas GPU. Añadiendo un
nodo GPU Partículas dos D a nuestra escena de personajes, solo lo
nombraré partículas, lo
moveré hacia arriba para estar
en
el centro del personaje y echar un
vistazo a sus propiedades
en el inspector. Antes de que un emisor
de partículas dibuje algo, necesita un material de proceso Este es un recurso que le dice
al emisor cómo generar partículas y cómo
deben comportarse las partículas después de
haber Hay dos opciones diferentes
para nuestro material de proceso,
un material de proceso de partículas
o un material Shadum El
material de proceso de partículas se creará como un recurso de proyecto que
podemos editar aquí mismo
en el inspector, mientras que un
material de sombreado nos permitirá escribir un script de Shader
para hacer lo mismo Los scripts de sombreado
no están escritos en GDScript como todos
nuestros scripts hasta ahora Están escritos en shader GD, que no serán
cubiertos en este curso Entonces usaremos un
recurso material de
proceso de partículas en su lugar. Haga clic en el recurso para ver
y editar sus propiedades. Ahora que nuestro nodo
emisor de partículas tiene un material de proceso, genera píxeles
blancos individuales desde su punto de origen
que caen debido a Para que las partículas sean
más fáciles de ver, esconderé mi sprite de personaje Antes de entrar en cada propiedad
individual, ayuda a
apagar primero la gravedad, que está debajo de la sección de
aceleración. Y como estas
partículas van a ser utilizadas para impactar
durante el combate, pondré su
explosividad en una Tengo una hoja de sprites que me gustaría usar
para mis partículas, así que
la importaré a mi carpeta de efectos, luego la asignaré como propiedad de textura de mis
emisores de partículas Pero esto solo dibuja
toda la hoja de sprites
para cada partícula Para animar una partícula, tenemos que darle
un material personalizado bajo las propiedades
heredadas del elemento Canvas Haremos un nuevo material de elemento
Canvas y luego activaremos su propiedad de
animación de partículas. Ahora podemos cambiar el número de fotogramas de animación
horizontal y verticalmente en la hoja de sprites Las partículas ahora están dibujando
solo el primer fotograma. Ampliando la sección
de animación del material de
proceso de partículas, podemos establecer la
velocidad de animación para las partículas. Quiero que mis partículas
tengan una velocidad consistente, así que estableceré tanto la
mínima como la máxima en una. También se puede
usar una curva para alterar la aleatorización de la velocidad de animación de cada
partícula Y
también se pueden proporcionar los mismos valores para
dar a cada partícula su
propio desplazamiento de animación. Ampliando la sección span, podemos editar la posición donde van a desovar
las partículas, su ángulo de rotación y
su velocidad inicial Podemos cambiar la forma
de emisión de un solo punto a ser una variedad de otras formas y cambiar el tamaño de
la forma si queremos. Las formas de emisión puntual suelen ser las más adecuadas
para las partículas de combate. El ángulo permite la aleatorización de la rotación de las partículas Para que sea completamente aleatorio, simplemente establezca max en 360. Ya que estoy usando pixel art, no
quiero que mis
partículas roten. La velocidad inicial hará que nuestras partículas se sientan
más explosivas. La cantidad de fuerza se
aleatorizará para cada partícula
entre min y max, haciendo que las partículas
se sientan menos uniformes El spread
creará una forma de abanico. Al máximo a 180 grados, la dirección será
completamente aleatoria La sección de velocidad animada contiene variables
que puede usar para aplicar una variedad de diferentes velocidades constantes a sus partículas a lo largo de
su vida útil Angular los hará rotar. Direccional
continuará
moviéndolos en cualquier dirección en la que ya
se estén moviendo. Orbital los hará orbitar
alrededor del punto de desove. La radio los alejará
del punto de generación. Y el límite de velocidad utiliza una curva para limitar la
velocidad de cada partícula. La
sección de aceleraciones contiene variables
similares que
puedes usar para afectar la velocidad de cada
partícula gradualmente a lo largo de su vida útil, lo que las hará
sentir más realistas La gravedad es una fuerza constante en una dirección para todas las partículas. Lineal es la dirección en la
que ya
se mueve la partícula. Radial está lejos
del punto de desove. Y tangencial es
similar a orbital. La amortiguación es una
fuerza útil que hará que las partículas se desaceleren a
lo largo de su vida útil, lo cual es útil para partículas explosivas
o de impacto
como las que estamos fabricando actualmente Los atractores de partículas
no están disponibles para dos D, por lo que este ajuste
no hará nada Ampliando la sección de visualización, podemos cambiar la forma en que se dibuja
cada partícula. La escala hará que las partículas
aleatoriicen su propio tamaño. Si agregamos una curva de escala, esto cambiará la
forma en que cada partícula cambia su escala a
lo largo de su vida útil. Pronto repasaremos el editor de
curvas. escala sobre la velocidad hará
que la escala de las partículas sea relativa a su velocidad en lugar de
su vida útil. Esto es particularmente útil para hacer nubes de polvo
que se disipan Las curvas de color tienen múltiples propiedades
diferentes, comenzando con un
color base para todas las partículas. La rampa de color nos permitirá hacer un gradiente con cada partícula progresando desde el
color a la izquierda hasta el color de la
derecha
a lo largo de su vida útil Este color se multiplica por el color base para
producir el resultado. La rampa inicial de color
aleatorizará el color inicial de cada
partícula a través del La curva de emisión se
puede utilizar para hacer que tres partículas D emitan diferentes cantidades de luz a
lo largo de su vida útil, que no se usa en dos D. La curva Alfa es
útil solo para editar el Alfa de sus
partículas a lo largo de su vida útil. Vamos a crear un nuevo recurso de
textura curva aquí. Este recurso de textura curva requiere otro
recurso de curva propio. Al hacer clic sobre esto se abre
un editor de curvas que
podemos usar fácilmente para crear una
amplia variedad de efectos. El eje X de esta gráfica es tiempo siendo cero
cuando se
genera la partícula y uno es el final de
la vida útil de la
partícula. No 1 segundo. El eje Y es el
valor que estamos editando, que son los
colores de partículas Alfa, siendo
uno opaco y
cero siendo invisible. Podemos editar los valores mínimo y
máximo para nuestro eje, pero no necesitamos
hacerlo en este contexto. Simplemente haciendo clic en
la gráfica agregará un punto que podremos
arrastrar según sea necesario. Quiero que mis partículas comiencen opacas y se desvanezcan a invisibles a
lo largo de su vida. Esto es genial para
hacer que las partículas se
desvanezcan en lugar de
simplemente desaparecer tangentes se aplican
automáticamente a los puntos para crear una curva Seleccionando cualquier punto
de la gráfica, podemos editar las tangentes para crear cualquier tipo de
curva que necesitemos También podemos
editar manualmente los puntos y tangentes expandiendo la sección de
puntos en la parte inferior variación de tonalidad se puede usar para aleatorizar el tono de
tus colores de partículas, lo que hace que se
vean menos uniformes El resto de las
propiedades no son muy aplicables a nuestro proyecto tot, pero te daré un breve
resumen de para qué sirven La turbulencia se puede aplicar para simular cómo las corrientes de aire
afectarían a tus partículas Puede editar el patrón de
ruido utilizado para calcular la turbulencia
cuando se enciende Las partículas se pueden detener
o matar por colisiones. Las colisiones aquí no son lo
mismo que las colisiones que hemos estado usando hasta
ahora porque las partículas están siendo manejadas por
la tarjeta gráfica Solo pueden colisionar con oclusores de
luz, no con objetos de
física Y si tus partículas escalan, entonces su radio de colisión también se
puede escalar con ellas. Y se puede
usar un sub emisor para crear efectos
como fuegos artificiales,
generando omisiones de
partículas adicionales Para que mis partículas coincidan con las otras velocidades de fotogramas de
mi juego, estableceré la
vida útil de las partículas ocho fotogramas divididos por
12 cuadros por segundo. Ahora que el
emisor de partículas está configurado, deberíamos establecer su propiedad one
shot en true Ahora solo emitirá
partículas en una sola ráfaga, que podemos desencadenar
a través de nuestro script. Volveré a encender mi
sprite de personaje,
luego abriré el guión de mi personaje Dando un nombre único al
nodo particles, podemos almacenarlo en una variable
con la etiqueta on ready. Entonces, cuando el personaje
recibe daños, podemos decirle a la nieve que emita partículas estableciendo su propiedad
emisora en true. Tenga en cuenta que esto no funcionará
si se usa en rápida sucesión, ya que el emisor de partículas ya
estará
emitiendo partículas Así que solo establecer la emisión a true no
generará más partículas Para momentos como este,
querrás generar un nuevo nodo de partículas de GPU por cada golpe o llamar a la función de
reinicio en su lugar reinicio obligará al emisor de
partículas a detener su emisión actual y comenzar de nuevo con un nuevo
conjunto de partículas Recuerda copiar este nodo en tus
escenas enemigas según sea necesario. Et lo prueban.
Atacando al enemigo, ahora
emiten partículas
cuando son golpeados. Y el personaje jugador también emite partículas
cuando recibe daño. Ahora tenemos efectos de partículas
desencadenados por nuestros ataques, pero hay más
que podemos hacer para que combate se sienta aún más crujiente Te veré en el siguiente video.
60. 8-4 Agitar: Hola, amigos. En este video, agregaremos un
batido de cámara que puede
hacer que el combate se sienta
aún más impactante. Comenzando en el script de la cámara, necesitaremos una variable que
podamos usar para sacudirla, que será un vector dos. Si bien hay una variedad de formas
diferentes en las que podemos crear
un efecto de sacudida de cámara, creo que
tiene sentido usar una pregeneración,
ya que es un cambio de propiedad
que ocurre a lo largo de
un tiempo específico Así que vamos a declarar una nueva
variable de tween llamada shake tween. Entonces también declaramos una
nueva función que
será de acceso público
que pueda sacudir la cámara. Primero, comprobando si la cámara ya
está temblando comprobando si el shake tween ya
existe y si es así, mátalo Entonces podemos crear una nueva premamá. No hay necesidad real de tipos especiales
de transición o flexibilización para esto No queremos interponer
una propiedad de manera uniforme de
un valor a otro, sino simplemente llamar un método varias veces a
lo largo de una corta duración Tendremos que declarar la
función a la que vamos a llamar, pero voy a llamarla set shake
como una función privada. Entonces necesitamos
proporcionar un argumento para
pasar a la función desde el principio hasta el
final de la tween Esta será la intensidad
del efecto temblor
medido en píxeles. Podemos aceptar esto
como un parámetro de la función shake para que cualquier script que
desee activar una sacudida de cámara pueda
especificar la intensidad. Luego a lo largo de la duración
de la cámara, el temblor reduce
gradualmente la
intensidad hasta cero. Opcionalmente, es posible
que
desee convertir este otro
parámetro si desea
permitir batidos de cámara que tengan una intensidad consistente o
creciente El argumento final es
la duración de entre, que también podemos
convertir en otro parámetro. A continuación, escribiremos la función
set shake, que acepta la
intensidad como parámetro. Esta función se llamará a cada fotograma durante la
duración de la sacudida con la intensidad
cambiando gradualmente desde el valor proporcionado en la llamada a la
función original a cero. Entonces todo lo que tenemos que hacer es establecer el valor de shake
en un nuevo vector dos. Si empezamos con el
vector dos punto a la derecha, entonces rotarlo a una dirección
aleatoria. Un ángulo de rotación aleatorio puede ser un flotador aleatorio
entre cero y tau. Entonces podemos multiplicar los
resultados por intensidad. Si por alguna razón tu tween de
shake no concluye estableciendo el
valor de shake
en cero, entonces tendrás que hacerlo al final de la tween Podemos conectar la señal de shake
tweens terminada a la función set shake y
enlazar cero como intensidad Esto asegurará que el
valor de la sacudida en cualquier momento después la cámara haya terminado temblar se
restablecerá a cero. Para que el vector shake
realmente mueva la cámara, todo lo que tenemos que hacer es agregarla a la posición de la cámara en
nuestra función de proceso. A en nuestra escena de juegos, ahora
podemos conectar cualquier
señal que queramos para activar un movimiento de cámara a la función shake de nuestra
cámara. Como, por ejemplo, cuando
el personaje del jugador ataca a un enemigo o
cuando recibe daño. En el guión del personaje del jugador, podemos agregar señales
para estos eventos. Luego, de vuelta a la escena del juego, podemos conectar estas señales a la función shake de la cámara. Para agregar argumentos
a una conexión de señal, necesitamos ampliar la sección
avanzada. Luego podemos seleccionar
float de la lista de tipos de argumentos ya que
el parámetro intensity es un float en nuestro script. Después haga clic en el botón Agregar. El batido también necesita una duración, que también es de tipo flotador. Para que podamos
volver a hacer clic en el botón Agregar para agregar otro flotador. Los valores que proporcionamos
para el Argumento uno
cambiarán la intensidad de la
sacudida medida en píxeles, y el Argumento dos será la duración del
batido en segundos. Voy a hacer que mis personajes de jugador ataquen a causa de un movimiento de cámara con una intensidad de cuatro píxeles en un
cuarto de segundo. Pero cuando reciban daños, sacudiré la cámara
con una intensidad de ocho píxeles en
medio segundo. Cambiando a la escena
del personaje del jugador, necesitamos emitir estas señales
en los momentos apropiados, comenzando con nuestra señal Hurt boxes
damage received signal, que ya está
conectada a una función nombrada en el daño recibido
en el guión del personaje. Si anulamos esta función en el guión del personaje del jugador, podemos llamar a la función de
superclase, luego emitir la señal A continuación, podemos seleccionar
el hit box y agregar otra conexión de señal
a la señal
ingresada en el área on y hacer
que llame a una nueva función. Vamos a nombrar esto al
ataque aterrizado. Esto no necesita
preocuparse por el otro nodo de área, por lo que podemos usar la sección
avanzada para desvincular este argumento
de la conexión de señal Como desvinculamos
el argumento area, la función no tiene parámetros Todo lo que esta función tiene que hacer es emitir la señal para
provocar el temblor de la cámara. No, vamos a probarlo. Si ataco al ratón Caballero, esto desencadena las
casillas de golpe se ingresan señal, lo que burbujeará a través
del personaje del jugador hasta la escena del juego y
activará un temblor de cámara. Dejar que el ratón Caballero
golpee al personaje del jugador activa la señal recibida
dañada de la caja Hurt, lo que provoca un temblor de cámara más
intenso. Ahora tenemos nuestra cámara
temblando en respuesta a que el personaje del jugador ataca los enemigos y recibe daño, pero nuestros personajes no mueren
cuando se les acaba la salud. Te veré en
el siguiente video.
61. 8-5 Muerte: Hola, amigos. En este video, haremos que nuestros personajes mueran cuando se les acabe la salud. Comenzando en la escena nocturna del
ratón, seleccionando el nodo
Animation Player, rápidamente
haré una
nueva animación muerta duplicando la animación de
éxito Después de cambiar el sprite
al marco correcto en
la hoja de Sprite, es una buena idea apagar
la Caja de Daño para que
ya no puedan recibir daños y
no volver a encenderla Lo mismo se puede hacer para toda la otra área a los nodos Di, desactivando el daño de contacto
y el cuadro de golpe dos, por lo que el enemigo muerto
ya no puede infligir daño al personaje
del jugador. Seleccionando el nodo Árbol de
Animación, podemos agregar esta animación muerta
a la máquina de estado y automáticamente hacer la transición a ella si este personaje está muerto. A diferencia de otras animaciones,
no hay necesidad de una transición
fuera del estado muerto. Ahora solo necesitamos agregar esta variable Is dead al script de
caracteres. Lo pondré en la parte superior
del guión como booleano. Y también declaramos una señal de
muerte dos, si acaso
alguna vez queremos que algo reaccione ante la muerte de ciertos
personajes. Después escribe una función pública
llamada die que establecerá el valor de esta variable
en true y emitirá la señal. En cualquier lugar de este script
donde un personaje pueda realizar cualquier acción que no se
deba permitir
después de morir, solo
podemos verificar primero el valor de la variable is dead. Entonces, si se
le dice al personaje que se enfrente a una dirección, pero están muertos,
deben ignorar esa petición. De la misma manera lo ignoramos
si están atacando. De manera similar, si a este personaje
se le dice que salte, pero están muertos,
no deberían saltar. Lo mismo con atacar. Y en el proceso de física, también
estableceré su dirección de
movimiento a cero si están muertos, por lo que nunca se
moverán mientras estén muertos, sino que se verán afectados por la física. En el guión de Hurt Box, ya
creamos la
señal teñida y la emitimos cuando el personaje
se queda sin salud cuando
escribimos el guión en
la sección anterior. Pero para reproducir
una animación de muerte y no una animación de golpe
cuando el personaje recibe daño y
muere como resultado, necesitamos asegurarnos de que solo
emitimos la señal teñida
en ese momento. Entonces moveremos la señal de daño recibido
a un bloque se, dando prioridad a la señal teñida. Todo lo que tenemos que hacer es conectar la señal teñida de la Caja Hurt a la función de morir del enemigo
para activar la animación. Ya sea en la escena del enemigo o en la escena del contenido de la sala, donde sea que tengas los nodos de IA de tu
enemigo, también
puedes querer
conectar la
señal did del enemigo a la
función libre de estos nodos. Alternativamente, puedes hacer esto
en los propios guiones. Al anular la función de listo, enemigo muerto se puede
conectar a ure Esto le ahorrará
tener que conectar la señal manualmente cientos de veces
a lo largo de todo el proyecto. Vamos a probarlo. ataco al
Caballero ratón cinco veces, su salud llega a
cero, y muere, que reproduce la animación de la muerte, y detiene todas las acciones. También puedo tocarlo
sin sufrir ningún daño. Ahora para el personaje jugador, en realidad no
tengo sprites de
animación de muerte para este personaje Lo que voy a hacer en cambio es
reutilizar la animación hit, duplicándola para crear
una animación de muerte, ya que sé que cuando
este personaje muere, la escena del juego se
desvanecerá y restablecerá de todos modos Al igual que el enemigo,
es una buena idea apagar
también todas las
cajas lastimadas y las cajas de golpes. El único cambio real que voy a hacer aquí es tener el loop de
animación. En el Árbol de Animación, agregaré la animación muerta, la misma que antes, con una transición automática
si el personaje está muerto. Pero esta vez, añadir también
una transición fuera
del estado muerto bajo la condición de que ya no
estén muertos,
ya que el personaje jugador será revivido después de morir Después de conectar la señal de
muerte de Hurt Box al guión del
personaje, cambiaré al guión del personaje
del jugador. Tendremos que escribir una función
de reactivación que pueda ser utilizada para devolver la vida al
personaje del jugador, estableciendo la
variable I dead de nuevo en false. También podemos decirle a la Caja de Hurtos que recupere la salud completa
al mismo tiempo. Para agregar más a la animación de muerte del
personaje del jugador, anularé la función die en el guión del personaje del jugador. Comenzaré llamando a
la función de superclase, luego haré algunas otras cosas específicas para el personaje del
jugador Reutilizando el nodo de
efectos de partículas, estableceré su
propiedad one shot en false, su explosividad Y está emitiendo
propiedad a verdad, convirtiendo el estallido instantáneo de partículas en
un flujo constante Además de eso, también entretendré el color de modulación
del personaje para que tenga una mayor intensidad Después de crear una nueva tween,
interpelaré el color de
modulación de este nodo a un nuevo color con
valores RGB de 255 Luego en la función de revivir, volveré a poner todos estos
a sus valores normales. A en la escena del juego, la cámara también puede reaccionar ante la muerte del jugador con otro temblor de cámara
aún más intenso. El manager del juego
también tendrá que reaccionar ante la muerte
del personaje del jugador para restablecerlo todo. Así podremos conectar la señal dD del
personaje del jugador al guión del manager del juego. Nombremos esta
función en Player DD. Cuando el jugador muere, primero, podemos desactivar el manejador de entrada ya no
puedan
controlar al personaje Esperaré 1 segundo primero para dejar que se reproduzca la animación de
muerte de mi personaje, lo que se puede hacer
diciéndole al árbol de escenas que
cree un temporizador. Podemos obtener el
árbol de escenas en cualquier momento usando la función get tree y llamar a
la función create timer, que acepta un argumento
para la duración del temporizador. Esto devuelve el temporizador ya iniciado para que podamos esperar
su señal de tiempo de espera. Esto detendrá la ejecución de esta función en esta línea
durante exactamente 1 segundo. Después de desvanecerse a negro, tendremos que reposicionar al personaje del jugador donde
queremos que responda. Como aún no tenemos los sistemas
adecuados para manejar esto, solo los
pondré en
el origen de la escena del juego y dejaré un comentario de que esto necesita
implementarse más tarde. Ahora podemos revivir al
personaje del jugador, volver a aparecer y volver a habilitar el controlador de entrada para que el jugador pueda
seguir jugando Si desea
mostrar algún texto, puede agregar un nodo de etiqueta
a la capa Canvas. Voy a nombrar Mind game
y darle un nombre único. Después poblarlo con
algo de texto, centrarlo. Dale un tamaño de fuente más grande. Y anclarlo al
centro de la pantalla. Antes de desvanecerse a negro, también
crearé
una preadolescente que
desvanecerá el
Alpha de la etiqueta hasta uno Modularé su Alfa a cero, lo que es invisible por defecto Sin ninguna espera,
esto sucederá al mismo tiempo que
la
pantalla se va desvaneciendo a negro La etiqueta deberá
dibujarse
frente al desvanecimiento
para que sea visible. Después de reposicionar
el personaje del jugador, luego
esperaré otro 1 segundo antes de desvanecerme en el texto Pero lo haré más rápido de lo
que se desvaneció. Después de revivir al personaje
del jugador, mostraré un mensaje diferente medida que el juego se desvanece de nuevo. Duplicaré el
juego existente sobre mensaje, nombraré a este revivir y cambiaré el texto. Antes del desvanecimiento para borrar, usaré otra preadolescente para
hacer que este texto se desvanezca Espera otro 1 segundo, luego vuelve a desvanecer el texto. Vamos a probarlo. Dejaré que la noche del Ratón mate a
mi personaje jugador. Ahora tenemos a nuestros
personajes muriendo y el manager del juego reaccionando a la muerte del personaje del jugador, pero nuestro juego aún no
tiene un jefe en él. Te veré en el siguiente video.
62. 8-6 Director 1: Hola, amigos. En este video, construiremos un jefe para nuestro juego que sea
más complejo que nuestros otros enemigos. Empezaré por crear una nueva carpeta de activos para contener
los activos para este jefe. Después importa los sprites. Luego crearé una
nueva escena en mi carpeta de
escenas enemigas llamada Mac Mouse
con un tipo de nodo raíz de CharacterBody dos D. Este jefe está compuesto por múltiples componentes de sprites
diferentes que necesitaré ensamblar
y superponer uno sobre otro Primero, agregaré una D
normal no dos que puedo usar para voltear todos los
componentes visuales
del jefe cuando se dan vuelta y lo nombran flip Luego agrega múltiples sprites
para los diversos componentes. Voy a necesitar un sprite para
el blindaje, que será una textura atlas Y después de poblar
la textura, seleccionaré la
región apropiada de la hoja de sprites Esto se compensará
hacia arriba en 48 píxeles. Duplicando este nodo de sprite, cambiaré el nombre de este para que sea engranajes y cambiaré su tipo
a Sprite animado dos D. Dando al nodo un recurso de fotogramas
Sprite,
agregaré los sprites de engranaje a la Después cambia su
velocidad de animación a 12 fotogramas por segundo. Esto debería dibujarse
detrás del blindaje, así que reordenaré los nodos Duplicando de nuevo el nodo de sprite de
blindaje, haré otro sprite para el fondo detrás de los engranajes Después de hacer que la
textura del atlas sea única para este nodo, entonces
puedo seleccionar una región
diferente para dibujar y reordenar este nodo para que se
dibuje detrás de los demás Este fondo también está
destinado a sujetar los engranajes para que no se dibuje nada fuera
del cuerpo. Podemos hacer esto
poniendo los engranajes como un hijo del nodo de
fondo. Después, seleccionando el fondo debajo de la sección de visibilidad, cambie los niños del clip de
deshabilitados a recortar y dibujar. Ahora los engranajes solo
dibujan dentro del cuerpo. También hay una
llave de viento que está animada. Entonces duplicaré mi nodo de
engranajes para hacer otro nodo de
tout de Sprite animado y nombrarlo clave. Después de hacer que el recurso de
marcos Sprite sea
único para este nodo, reemplazaré los marcos de Sprite de engranaje con los
marcos
clave de sprite Después volveré a colocar
la llave para estar en la posición apropiada en la parte posterior del cuerpo del ratón Mc Voy a necesitar más Sprite Animado dos nodos D para las ruedas, así duplicaré la clave
para hacer una rueda animada Después de hacer que el recurso de
marcos Sprite sea único, cambiaré los marcos
clave de Sprite
para los marcos de sprite de rueda Después coloca la rueda en una buena posición y
desplázala hacia arriba para estar en el suelo. O. Para dibujar las ruedas detrás del cuerpo, reordenaré para que estén por encima
del cuerpo en el árbol de escena Duplicaré la rueda
delantera para hacer una segunda rueda
y reposicionarla. El último componente visual de este jefe es un barril que
se extiende desde su boca, que solo será
un sprite ordinario Después de asignar la textura del
sprite, moveré para que esté alrededor boca del ratón Mc y
la colocaré detrás
de los sprites
del cuerpo I Cuando este barril dispara proyectiles, quiero que esté sobresaliendo de la boca
del ratón Mc, por lo que tendrá un desplazamiento
de 16 píxeles negativos Voy a añadir un área
nodo Tutti en esta posición, que será el proyectil Entonces dale un nodo Tutti
Sprite Animated con el recurso Sprite
frames y agrega los
dos fotogramas de sprite de bola de fuego Después de establecer la velocidad de fotogramas, también
tendré esta reproducción
automática por defecto. Esto necesitará una forma de
colisión, que solo será un círculo. Para funcionar
como proyectil, necesitará el
guión del proyectil adjunto El guión del proyectil espera que el proyectil tenga
una animación de impacto, así que agregaré uno usando los mismos sprites
de impacto que mi Esto tendrá que
estar
monitoreando y enmascarando la capa de
Hurt Box del jugador. Podemos conectar el área ingresada
y las señales de entrada del cuerpo al guión del proyectil para activar la
animación de impacto y el daño. O. Con la bola de fuego ensamblada, podemos guardarla como escena propia en la carpeta del proyectil. Voy a añadir un marcador de
nodo Toti como hijo de
la bola de fuego para que actúe como la ubicación donde van a generar los
proyectiles, al
igual que hicimos Después reordene el nodo
marcador Tutti para que sea hermano de la bola de fuego,
manteniendo su posición
relativa
y eliminar la bola manteniendo su posición
relativa y Luego reinicie el
desplazamiento de barriles a su posición
predeterminada. Además de voltear
el cuerpo a izquierda y derecha, también
quiero que el cuerpo
del mouse Mc rumble
pero no las ruedas Entonces voy a poner todo lo
que quiero retumbar como hijos de otro
no dos D llamado cuerpo Cada vez que el ratón Mc se mueve, quiero que el polvo y las
rocas sean levantadas del
suelo por las ruedas. Entonces voy a añadir una partícula GP
dos nodo D para las rocas. Luego asigne un sprite de roca como textura y haz un material de proceso de
partículas Bien. Hacer que las rocas
pateen desde el suelo, todo lo que realmente necesito hacer es cambiar la dirección de la velocidad hacia arriba y darle a cada roca una velocidad aleatoria 32-64
píxeles por segundo Para el polvo, comenzaré
duplicando el
emisor de partículas de roca y cambiarle el nombre Luego asigne la misma hoja de sprites de
partículas que utilicé para impactos de ataque como
la propiedad de textura Dado que se trata de una hoja de sprites que está destinada
a ser animada, este nodo necesitará un material de elemento de
lienzo con su
propiedad de animación de partículas
activada con el
número correcto de fotogramas Después de hacer que el material del
proceso de partículas sea único, mantendré la misma velocidad, pero eliminaré la gravedad y agregaré suficiente amortiguación para contrarrestar
la velocidad inicial Debajo de la pantalla, agregaré una velocidad
de animación de uno para animar las partículas y una curva Alfa para que se
desvanecen con el tiempo Quiero esto dibujado al frente, así que estableceré su
propiedad orden en uno. Esto debería ser suficiente, así que duplicaré los
dos nodos de partículas
y los agregaré a la otra rueda. No quiero que
emitan por defecto, así que agruparé los seleccionaré a todos y apagaré sus
propiedades emisoras. Al igual que cualquier otro enemigo, este necesitará una
forma de colisión para chocar con el medio ambiente además de herir
cajas y golpear cajas Como este enemigo tiene una forma
más única, usaré un polígono de colisión en lugar de una forma de colisión Al agregar algunos vértices
al polígono para obtener la forma general del cuerpo
del jefe, tendré que asegurarme de que
el polígono de colisión haga contacto con el Tampoco realmente quiero
molestarme en voltear
este polígono, así que lo haré simétrico. Esto será suficiente para colisiones
con el entorno, pero también permitirá que el personaje del jugador se ponga
encima del enemigo, Para el Hurt Box,
me
preocupa un poco menos igualar la forma del enemigo tan de cerca, así que usaré una cápsula ordinaria. Si desea combinar múltiples formas estándar para
hacer una caja de daños más compleja, simplemente
puede agregar más nodos de forma de
colisión. Voy a añadir una segunda cápsula por encima de la primera para
cubrir más del cuerpo. Tampoco quiero
molestarme en voltear
estas cajas Hurt, así que ayuda que
sean simétricas El nodo D del área dos
emitirá sus señales como si todas las formas se
combinaran en una sola forma. Pero ten en cuenta que si
las formas están muy separadas, es posible que algo
entre en una forma de colisión, luego salga de ella, luego ingrese otra forma de colisión
causando múltiples colisiones También agregaré una
caja de daño separada para la llave de viento. Darle a esta llave su
propia Caja de Hurto
significa que no necesita estar
conectada a la salud del jefe, sino que puede emitir señales cuando
el jugador la ataca Esto solo puede tener una forma simple de colisión
circular, pero deberá voltearse Entonces me aseguraré de que
la exposición
del nodo shape sea lo que está
determinando de qué lado está
la Caja Hurt Y por último, este
enemigo necesita una caja de impacto. Esto se utilizará cuando el mouse
Mc cargue hacia adelante. Quiero que esto lastime al personaje
del jugador si están delante o
encima del jefe. Entonces usaré una cápsula girada
90 grados que se extiende más allá del polígono de
colisión del cuerpo frente a él y por encima de
él, pero no detrás de él Al seleccionar el nodo raíz
del cuerpo
del personaje, el enemigo deberá
considerarse terreno para que el
personaje del jugador pueda pararse sobre él, pero también existir en
la capa
enemiga y enmascarar solo el terreno. Ninguna de las cajas Hurt
o hit boxes
necesitará ser monitoreada o
monitoreable por defecto Los activaremos a
través de guiones o animaciones cuando
necesiten activarse. Pero las cajas de daño se pueden configurar la capa de
colisión de Caja de daño enemiga, y las cajas de impacto se pueden
configurar para enmascarar la capa de colisión de Caja de
daño del jugador capa de colisión de Caja de
daño para que cuando se
enciendan, funcionen. Ahora tenemos un jefe
ensamblado para nuestro juego, pero aún no tiene ningún
guion que lo controle. Te veré en el siguiente video.
63. 8-7 Jefe 2: Hola, amigos. En este video, le
daremos a nuestro jefe algunos comportamientos
más complejos que a nuestros enemigos normales. mecánica de progresión real
se cubrirá en la siguiente sección. Pero por ahora,
ayudará a pensar en cómo debería existir
nuestro jefe en
relación a su arena. Entonces, pongamos a este jefe enemigo en una arena sencilla con una
pared a cada lado. En términos generales, los jefes en Metroidvania atrapan al
jugador en una arena, y una vez que el jugador entra, deben derrotar al jefe antes de que se Este es un evento que
deberá ser activado por el personaje del jugador entrando en
el nodo Área dos D, lo que agregaremos uno a la escena
y lo nombraremos Jefe Encuentro. Entonces dale una forma de colisión. Usaré un rectángulo y haré que cubra un área muy
grande para que el jugador no pueda sortearlo y hacer que monitoree el cuerpo del personaje del
jugador. Esto necesitará un
script adjunto, pero lo crearé desde
la pestaña del sistema de archivos en una nueva
carpeta de scripts enemigos para jefes, que podemos nombrar
Boss Encounter, extendiendo el Área dos D. Este script
se encargará controlar el
flujo general del encuentro con jefes, incluso cuando
comienza, cuando termina, y cualquier transición de fase, cosas como tarjetas de título, cambiando la música, etcétera. Tendremos que darle a
esto un nombre de clase para que podamos extenderlo más tarde. Para reaccionar ante el personaje jugador entrando en este encuentro con jefes, podemos seguir adelante y escribir la función
en el cuerpo ingresado, que aceptará
un parámetro llamado body de tipo no dos D
y no devolverá nada. El personaje jugador entra en
este encuentro con jefes, primero, debemos desactivar
todas las colisiones futuras con esta área
usando set deferred para establecer la
propiedad de monitoreo Recuerda que cuando una función es llamada por un evento de colisión, no
debemos alterar nuestros
objetos de colisión al mismo tiempo, por lo que aplazamos eso hasta
después de que se
hayan manejado las colisiones Entonces podemos cerrar la arena, atrapando al jugador dentro y realizar cualquier
inicialización requerida Pero llegaremos a eso más tarde. Por ahora, declararemos una variable
exportada que tiene al enemigo jefe como objetivo al enemigo jefe
y otra para el
personaje del jugador. Cuando el personaje jugador
entra en el encuentro con el jefe, podemos establecer el valor de
target para que sea el cuerpo, así
como una
variable de fase local como un entero. Luego agrega una función de inicio,
una función de fin, y también una función de
transición de fase, aceptando la fase
como parámetro y actualizando la variable
a su nuevo valor. En la función de inicio,
podemos establecer fase a uno y llamar a nuestra función de toma de
decisiones para
iniciar la pelea. También necesitaremos una función que le diga al jefe
qué hacer a continuación. Por ahora, llamaré a la función Inicio cuando el personaje
del jugador
entre a la arena jefe. Asegúrese de guardar este script para que el nombre de la clase esté registrado. Ahora que tenemos la estructura
básica en su lugar, adjuntemos un nuevo script
a nuestro nodo de encuentro con jefes. Voy a nombrar esto después de mi jefe, Neck mouse encounter extend boss encounter and save it
in the appropriate folder. Con el guión adjunto, podemos asignar al enemigo jefe
a la variable exportada, establecer la máscara de colisión a
la capa del personaje del jugador y conectar la señal
ingresada al cuerpo. Dado que la función on
body entering ya existe en la superclase de
encuentro con jefes, no
necesitamos
preocuparnos por ello en este guión Sin embargo, anularemos la
función de toma de decisiones y le daremos a este encuentro con jefes en particular su propio algoritmo para decidir
qué hará a continuación. Estructurar el encuentro con
el jefe de esta manera
facilita alterar el comportamiento de un
jefe
en función de qué fase
se encuentra actualmente o agregar peligros ambientales
a la arena en reacción a las acciones del jefe
o sincronizar el comportamiento de múltiples
jefes en un Cualquier encuentro con nuevos jefes que queramos crear también puede
extender la clase de
encuentro con jefes y proporcionar sus propias implementaciones únicas
para cada jefe específico. Primero, es una buena idea
verificar si el jefe está muerto antes de dejar que
decida qué hacer a continuación. Entonces, si ya están muertos, entonces sólo podemos regresar. También es una buena idea
espaciar las acciones de un jefe con una breve pausa esperando la señal de tiempo de espera de un
temporizador Podemos hacerlo menos predecible aleatorizando la duración del
temporizador e incluso hacer que la cadencia de
la pelea aumente
con cada fase dividiendo
por el número de fase Y no importa lo que decida hacer el
jefe, probablemente
deberían
enfrentar hacia el objetivo. Entonces podemos llamar a una función para
decirle al jefe que mire a la izquierda si la exposición global del objetivo
es menor que la suya Usando una declaración de coincidencia
en la variable de fase, podemos proporcionar fácilmente diferentes opciones de acción
para diferentes fases. Como mi jefe es tan sencillo, optaré por aumentar
la intensidad de las acciones por fase en
lugar de introducir otras nuevas. Con otra declaración de coincidencia
en un entero aleatorio 0-1, voy a crear una oportunidad par para decidir entre dos acciones
diferentes O el jefe se moverá a una posición aleatoria en la arena, que será la posición
global de este nodo de encuentro con jefes más un número aleatorio entre 300 negativo
y 300 positivo, o bien el jefe disparará
bolas de fuego al jugador Aleatorizaré el número de
bolas de fuego en función de
la También quiero que el jefe
tenga una tercera acción, que es cargar al personaje del jugador
a mayor velocidad, pero sólo bajo
ciertas condiciones. Entonces, si el mouse Mc está listo para cargarse, entonces se cargará. Si no se cobra, entonces la
acción será aleatorizada. Y le voy a dar la señal de la
posición global del objetivo menos la
posición global del Mc Mouse como dirección. Planear qué
acciones quieres que use
tu jefe
y cuándo te da exactamente qué
variables y
funciones públicas necesitarás
escribir en sus guiones. Entonces podemos ver en este guión, el guión de nuestro jefe necesita
una variable is dead,
una variable lista para cargar, y también funciones de cara izquierda,
cargar, mover a la posición y disparar bolas de fuego Esta es una manera fácil de abordar la encapsulación al
escribir scripts complejos Podemos escribir
primero el script que
necesita interactuar con él para que ya sepamos
exactamente lo que necesitamos. La encapsulación también nos ayuda a
lograr la abstracción, también. Ya que solo nos enfocamos en lo que necesita ser de acceso público, también
podemos asumir que todo lo demás
debe ser privado. A continuación, adjuntemos un script al nodo raíz
de McMus y lo guardemos en la carpeta de scripts
enemigos Podemos declarar todas las
variables y funciones aceptando los parámetros
coincidentes del script Boss encounter. Si declaramos una señal y la nombramos
como terminada, entonces podemos emitir esta
señal de todas
las acciones que fueron seleccionadas de la función de toma de
decisiones. Por ahora, vamos a imprimir
lo que esperábamos que hiciera
el jefe. Primero podemos verificar si este
enemigo está muerto, y si es así, emitir la señal terminada inmediato y regresar
para que no pase nada. Después espere 1 segundo antes de emitir la señal
terminada. Después seleccionando el nodo jefe enemigos en
la escena de contenido, que podemos hijo para que el jefe se
encuentre si queremos y conectar la señal
terminada a la función de toma de decisiones. Ahora, cada vez que este jefe enemigo complete alguna de las acciones, automáticamente
decidirá qué hacer a continuación. Esto debería ser suficiente
para demostrar el flujo de nuestra batalla de jefes.
Entonces probémoslo. Podemos ver por la salida
cada segundo o dos, el enemigo está tomando una decisión
sobre qué hacer a continuación. Ahora tenemos a nuestro enemigo jefe
controlado por un guión de
encuentro con jefes, pero aún necesitamos implementar
cómo funciona
todo internamente
dentro de la escena del jefe. Te veré en el
siguiente video.
64. 8-8 Jefe 3: Hola, amigos. En este video, voy a repasar cómo escribí las funciones de
mi jefe para que puedas comparar mis métodos la forma en que
implementaste los tuyos. Primero, adjunté
los guiones de Hit box y Hurt Box a los hit boox y
Hurt Boxes del jefe respectivamente. Entonces comenzó en los guiones
jefe enemigo. Declaré señales para cualquier cosa que
se usara para iniciar o terminar la pelea de jefes o
causar una transición de fase. Otro para cuando
el jefe cambia dirección así sé cuándo darle la vuelta
a las cosas, y un par más por saber
cuándo el jefe ha llegado a su destino previsto
o se estrelló contra una pared Luego también está la señal, que se omitirá cuando se complete
la
acción decidida actual del patrón, y necesita decidir
qué hará a continuación Conecté la señal de cambio de
dirección a la caja Hit y las
llaves enrolladas Hurt Box para que
puedan ser volteadas El script de Hurt Box
en realidad no tenía esta función, así que lo copié
del script de Hit boox No obstante, las llaves de viento
Hurt Box está detrás del jefe, así que necesitaba agregar
una variable exportada para invertir la dirección
para este caso específico. De vuelta al guión de Mac Mouse, necesitaba una referencia
al cuerpo del jefe
para que retumbara. Entonces esto se almacena
en una variable, ya que la estaré usando
muy frecuentemente. Y, claro,
voy a necesitar saber si el jefe está vivo o muerto. Me gustaría que mi pelea de jefes
comenzara con el Mcmuse
apagado y que el jugador ataque la llave de viento varias
veces para ponerlo en marcha Por lo que declaré una variable para
si el motor está
actualmente arrancado o no más una
velocidad para la llave de viento,
arrancándolo a una
octava parte de la velocidad normal, y una tween que puedo usar para alterar la velocidad
gradualmente con el tiempo Para crear este efecto, tuve la animación wind up keys
reproduciendo automáticamente, pero con una escala de velocidad de cero y su caja de daño
monitoreable por defecto Luego conecté su
señal dañada al guión de mi jefe, llamando a una función
llamada en ataque clave. Para asegurar que la caja de
daño de la llave nunca muera, llamo su función de recuperación, ya que esto no es un reflejo
de la salud del jefe, simplemente otro objetivo para que ataque el personaje
del jugador Después de configurar la
escala de velocidad de animación de
teclas de viento al doble, utilicé la preadolescentes para reducirla
gradualmente nuevo a su valor esperado en el
transcurso de 1 segundo Si el motor
ya se ha arrancado, entonces atacar la
tecla de viento hará que el mouse de Mac cargue
hacia el personaje
del jugador como su siguiente acción. De lo contrario, dupliqué
la velocidad de la llave y verifiqué si había alcanzado
un valor de al menos uno. Con el
valor predeterminado de un octavo, esto sucederá
después de la tercera vez que se ataca la llave de viento. Cuando eso sucede, llamé una función para arrancar
el motor del mouse Mc. Todo lo que hace esta función es decirle la animación de engranajes que comiencen
a reproducirse, comiencen un temporizador de rumble, que se establece en una
12 de segundo, por lo que el motor se
arranca variable a true y emita la señal Cada 12 de segundo, cuando el temporizador de estruendo se agota, moví la posición Y
del cuerpo a un entero aleatorio entre uno negativo
y uno positivo que el cuerpo retumbara hacia arriba y hacia abajo Hacer la cara de jefe izquierda fue muy similar
a como se hizo con el personaje jugador
con la excepción de que este jefe enemigo se
enfrenta a la izquierda por defecto. Para hacer que el jefe
conduzca y cargue hacia
el personaje del jugador, utilicé muchas de las mismas variables de
locomoción en el guión del personaje
solo con diferentes nombres, y también incluí el destino del
jefe y la distancia a su
destino como carrozas, así puedo usarlas
para determinar a dónde necesita ir
el jefe en
el proceso También incluí gravedad por si
acaso y establecí la velocidad de movimiento para que fuera la velocidad de conducción por defecto. Guardé las ruedas en una matriz para poder
sincronizarlas fácilmente. Si bien esto puede parecer innecesario
para solo dos ruedas, escribirlo de esta manera funcionará
para cualquier número de ruedas. Usé una
variable pública para decir si este mouse Mc
ha tenido
atacada
o no su llave de viento y está listo para
realizar un ataque de carga y un entero para
contar el número de veces que se han
estrellado contra una pared Cuando el script de encuentro con jefe decide que el
mouse Mc debe moverse a una posición dentro de
la arena de jefe y proporciona la posición a la que
moverse como parámetro, verificando
rápidamente si el jefe está muerto para que la
solicitud pueda ser ignorada, almacené el destino, establecí la dirección de movimiento, la velocidad de movimiento y
se está moviendo a true. Llamé a una función privada
para animar todas las ruedas, luego esperar mi señal llegada antes de emitir la señal
terminada La señal llegada se
emitirá desde el proceso de
física posteriormente. El argumento pasado a hacer girar las ruedas controla qué
tan rápido se animarán, así
como si la animación se reproducirá hacia adelante o hacia atrás Entonces, si el mouse del Mac
está orientado hacia la izquierda y mueve hacia la izquierda o hacia la
derecha y moviéndose a la derecha, voy a reproducir la animación
con una velocidad de uno. De lo contrario, una velocidad de negativo reproduce las
animaciones al revés. Cargar al personaje del jugador hace casi todas las mismas cosas. No obstante, quiero que el mouse
Mc siempre orientado
hacia la dirección en la que se está cargando y haga girar
las ruedas a doble velocidad. Usando una breve pausa, esto telegrafiará
la carga al jugador para que pueda reaccionar
y salirse del camino. Dado que la carga es un ataque, el hit box tiene su
propiedad de monitoreo establecida en true. Después de que el ajuste se esté
cargando a true, espero la señal que se
emitirá después de que el
Mcmuse se haya
estrellado contra una pared y uso otra breve pausa para mantener
al jefe aturdido
por Recuerda conectar
la señal
ingresada en el área de cajas de impacto para
realmente infligir daño. Girando las ruedas
y aceptando la dirección del
giro como parámetro,
iteré a través de
cada una de las ruedas en mi matriz de ruedas y
le dije a cada una que reproduzca su animación predeterminada usando el valor absoluto
de dirección como velocidad de animación
y si la dirección
era negativa o no para determinar si la animación
debía reproducirse en reversa También inicié los
emisores de partículas de roca y polvo unidos a cada rueda al mismo tiempo si el valor de dirección era
algo más que cero De lo contrario, se
apagarán. Ahora para el proceso de física, que hará posibles
ambas acciones, si el jefe ya está muerto, entonces no puede moverse voluntariamente, por lo que su dirección de movimiento se
establecerá en cero Luego apliqué aceleración o desaceleración a la velocidad X del
jefe, así
como la gravedad a
su velocidad Y antes llamar a la función de movimiento y
deslizamiento para aplicar la velocidad al cuerpo
del personaje Si el jefe está manejando
actualmente, tendré que verificar si ha
llegado a su destino, o si está cargando y
actualmente está tocando una pared, entonces sé que se ha estrellado Para saber si el jefe ha llegado a su destino
previsto, primero
necesito saber la
distancia a su destino, que es el valor absoluto del destino menos la exposición
global actual del jefe invertir la fórmula de
altura de salto, podemos determinar si
el jefe está
lo suficientemente cerca del destino
para comenzar a desacelerar Si la distancia es
menor que la velocidad al cuadrado dividida por
la desaceleración, dividida por dos Cuando esto es cierto, dejo de
hacer girar las ruedas, establecer la dirección de movimiento
a cero está conduciendo a falso y emito
la señal llegada. Cuando el jefe
choca contra una pared, hice la mayoría de las mismas cosas, pero también agregué velocidad
lejos de la pared para
que reboten de ella. Y apagó la caja de aciertos. También conté el número
de veces que esto sucede, y en el tercer choque, dañé el
blindaje del ratón Mc por lo que
entrarán en la segunda fase. Cuando la armadura se daña
por chocar demasiadas veces, aumenté la velocidad de
la llave de viento hasta dos Para dañar el blindaje, todo lo que necesitaba hacer era
cambiar la región de
la hoja de sprites que estaba
dibujando el nodo de sprite de armadura También dupliqué la velocidad
tanto de la tecla de bobinado como de
las animaciones de engranajes, así como del temporizador de rumble para hacer que la escena del jefe sea aún
más inestable Y volví verdadera la propiedad
monitoreable de la Caja Hurtada para que el personaje del jugador ahora
pueda atacar el cuerpo del mouse Mc
para hacerle daño Luego emitió la señal para
activar la transición de fase. Para disparar las bolas de fuego, necesitaba una escena llena
para las bolas de fuego, así
como las nuevas bolas de fuego, estaría instanciando
el marcador de dónde
instanciarlas ,
más el cañón y una preadolescentes para más el cañón Cuando se le dice al jefe que
disparara varias bolas de fuego, primero
esperé
extender el cañón,
luego giré varias veces, haciendo una
pausa de cuarto de
segundo antes de cada disparo, luego disparando una luego Después de disparar todas las bolas
de fuego, esperaba retraer el cañón
antes de emitir la antes de emitir la Extender o
retraer el barril fue una simple preadolescentes que
interpela los barriles compensaron X
al número deseado durante
un cuarto de segundo Disparar una sola
bola de fuego es casi lo mismo que con los proyectiles del
personaje del jugador Simplemente agregándolo como un hermano poniéndolo en la posición
correcta y disparando en la dirección
orientada hacia adelante En mi guión de proyectil, al decirle a una
Caja Hurtada
que reciba daño, también necesitaré proporcionar
la dirección del daño. Por último, cuando el jefe
se queda sin salud, uso set deferred para
apagar el hit box y
ambos cuadros Hurt y detener todas las animaciones antes de emitir
la señal teñida para terminar
el encuentro con
el jefe En la escena del contenido de la sala, conecté la
señal de arranque del motor al jefe
encuentra la
función de arranque y la señal de muerto
para terminar el encuentro dos. También conecté la señal dañada de
armadura a la función set phase, vinculando dos como argumento para desencadenar la
transición a la fase dos. Comenté la llamada
a la función de arranque para poder activar el
arranque de la batalla para que ocurra después de arrancar el
motor. Sí. Oh. Ahora
tenemos a nuestro jefe realizando
una compleja secuencia de acciones con
intensidad creciente en múltiples fases Pero nuestro juego carece de algún tipo
de progresión significativa. Te veré en la
siguiente sección.
65. 9-1 Punto de ahorro: Hola, amigos. En esta sección, convertiremos esta plataforma dos
D en una Metroidvania
siguiendo correctamente el progreso del jugador Empezaremos añadiendo un punto de
guardado a nuestro juego. He trasladado mi
encuentro con el jefe su propia habitación y lo
moví al lado de mi mapa en una región volcánica separada y también hice un nuevo espacio guardado para mi
región forestal a la izquierda. Dejé a mi
personaje jugador aquí arriba. Yo sólo restableceré su
posición de nuevo al origen. Comencemos en los jugadores
guardar datos donde necesitaremos almacenar la ubicación donde
el jugador
guardó su juego por última vez. forma en que almacenas esta información variará en función de la
estructura de tu juego. Pero para mi juego,
usaré una matriz de cuerdas. Si bien podría ser
más eficiente
almacenar puntos de guardado como números, esta es solo una variable única, por lo que el impacto
será insignificante También ayuda a mantener el archivo guardado legible por humanos
para fines de depuración El primer elemento de la matriz será el
nombre de la región, y el segundo será
el nombre de la habitación. Este patrón sigue la
estructura de mi árbol de escena. Cuando cargo los
jugadores guardan datos, todo lo que tengo que hacer es encontrar la región que coincida con
la primera cuerda, luego buscar la habitación que
coincida con la segunda cuerda y colocar
al personaje del
jugador en el punto de guardado de esa sala. Tenga en cuenta que este punto de guardado debe existir en el juego
en
el momento en
que se cargan los datos guardados y aún
no se
ha cargado el contenido de la habitación. Por lo tanto, el
objeto Guardar punto debe estar en la escena de la habitación en lugar de en
la escena del contenido de las habitaciones. Voy a añadir un nodo dos D a mi escena de guardar habitación y
nombrarlo savepoint Para que las cosas sean simples, colocaré este nodo para que esté en la posición en la que quiero
engendrar al personaje Ya que necesitaremos
tener múltiples de estos
puntos de guardado en nuestro juego, éste debería guardarse
como su propia escena. Entonces podemos
editarlo de forma aislada. La forma en que quieras activar tu punto de
guardado depende de ti. Solo usaré un simple evento de
colisión. Entonces, cada vez que el jugador
toque un punto de guardado, su progreso se guardará. Entonces agregaré un nodo D de área dos
a la escena y lo
desplazaré del suelo 96 píxeles para que el jugador tenga que saltar
para tocarlo. He importado algunos activos
para mi punto de guardado, que es un libro y también un sprite de efecto que
dibujaré detrás del libro
para que brille Voy a añadir un Sprite dos D no al nodo
de área para
dibujar primero el resplandor Después agrega un
Sprite Animado dos D para el libro. Dale un recurso de marcos de Sprite y llénalo con
los sprites del libro Reproduciendo la animación hacia adelante
y luego nuevamente hacia atrás. El área necesita una forma de
colisión, así que le daré un círculo y
usaré el radio del resplandor, que es de 32 píxeles. Dado que esto está en la escena de la habitación, no en la escena del contenido de la habitación, deberá ordenarse
frente al contenido de la habitación. Tendrá que vigilar el cuerpo
del personaje del jugador. A adjuntando un guión al punto de guardado, entonces
podemos conectar
la señal
ingresada en el cuerpo del área al guión. Cuando el personaje jugador
toca el punto de guardado, estableceremos el valor
de last saved at en sus datos de guardado para
que sea una nueva matriz con el primer elemento de la
matriz siendo el nombre de la región y el segundo
elemento, el nombre de la sala. Podemos automatizar estos nombres
usando la etiqueta on ready, ya que el padre
del punto de guardado siempre
será la
habitación en la que se encuentre, y el padre de la habitación siempre
será la región. La naturaleza del árbol de escena que requiere que
los hermanos tengan nombres únicos asegurará que esto
sea suficiente para determinar exactamente en qué
habitación guardaron por última vez. También podemos tomar una referencia
al nodo Animated Sprite two D y decirle que
reproduzca su animación
cuando esto suceda No olvides decirle
al nodo global de archivos que guarde el juego cada vez que quieras hacer
algo permanente. Cambiando al guión del administrador del
juego, tendremos que cargar la última posición guardada del
jugador. Después de que se haya realizado toda la
inicialización, llamaremos a una función para
posicionar al personaje del jugador Si los datos guardados del jugador tienen
un valor para el último guardado en, entonces podemos obtener la región por su nombre ya que sabemos que es
un hijo del nodo mundial. Y luego hacer lo mismo
para recuperar la habitación, sabiendo que la habitación es
un niño de la región. Luego podemos posicionar
al personaje del jugador en la posición global del punto de
guardado en esa sala. Esto provocará que el
jugador entre a esa sala, cargue su contenido y
se desvanezca como esperamos. Si el jugador aún no ha
llegado a un punto seguro, los
pondré en el
origen para iniciar el juego. Un problema surge cuando el
jugador muere, sin embargo, ya que también vamos a querer poner al personaje
del jugador en la última posición
guardada en ese momento. Tanto la secuencia
de eventos de muerte como el jugador que entra en una habitación estarán manipulando
el desvanecimiento al mismo tiempo Hay múltiples formas de
resolver este problema, pero para mantener las cosas simples, voy a comprobar si el personaje
del jugador es vestuarios cuando muere. Si mueren y reaparecen
en la misma habitación,
entonces el jugador que ingresó a la
habitación no se activará, por lo que la secuencia de muerte
puede manejar el De lo contrario, lo reemplazaré con una simple pausa
por 1 segundo. Para saber si reposicionar el personaje jugador
ha cambiado de habitación, haré que esa función
devuelva un booleano Y regresa si la
nueva habitación es la
misma que la habitación actual o
falsa por defecto. Et lo prueban. Cuando
cargo mi juego por primera vez, mi personaje comienza en la posición predeterminada
en mi sala de inicio. Si voy por la izquierda, encontraré el punto de guardado. Saltar a los
gatillos del punto de guardado salvando mi juego. Si cierro el juego
y vuelvo a jugar, ahora mi personaje jugador
empieza en el punto de guardado. Para que mi punto de guardado sea
un poco más mágico, haré que flote arriba y abajo. Exportaré un par de variables para el rango de
oscilación y velocidad con un valor predeterminado de 16 píxeles y una
oscilación por segundo Lo que se va a
mover es el nodo de área, que también moverá los
sprites como son hijos Voy a necesitar saber su posición
inicial Y y cuánto tiempo ha pasado. Anulando la función de proceso, configuraré T para que sea
él mismo más Delta multiplicado por la velocidad de oscilación envuelta entre cero y tau Esto permitirá que la oscilación
se repita infinitamente sin llegar nunca
al máximo de un número de punto flotante La posición Y del área
puede entonces establecerse su posición inicial
más seno de T multiplicado por el rango de
oscilación Para dibujar el
punto de guardado en el mapa, simplemente
podemos agregar
un Sprite dos D a la escena del punto de guardado y darle la textura
que queremos dibujar Escalarlo realmente grande para que sea visible
para la cámara del mapa, luego escóndalo para que no esté en el camino y adjunte
el script del icono del mapa. Tendrá que estar
en la capa de visibilidad dos, no en la capa uno, y todos sus antepasados
en el árbol de escenas deben ser visibles tanto en la
capa uno como en la capa dos. También quiero probar el problema de la
muerte, así que agregaré una función de
entrada simple al guión de mi personaje de jugador. Entonces cuando presiono la
barra espaciadora, el personaje muere. Ahora cuando ejecuto el juego, el punto de guardado está
flotando arriba y abajo, y lo puedo ver en el mapa. Cuando presiono la barra espaciadora, el personaje muere y
responde en el punto de guardado. Si me mudo a otra habitación, puedo hacerlo de nuevo y responder una vez más en el punto de
guardado. Ahora tenemos un punto de guardado
que recordará la última posición guardada del jugador y la cargará en la ubicación
correcta. En el siguiente video,
agregaremos la habilidad desbloquear elementos que
definen una Metroidvania Te veré en el siguiente video.
66. 9-2 Metroidvania: Hola, amigos. En este video, agregaremos elementos para que
el jugador los recoja
que desbloquearán sus habilidades
Metroidvania Comenzaré creando una nueva carpeta de escenas
llamada Upgrade. Luego duplique mi escena de punto
guardado, asígnale el nombre Gem y póngala en
la nueva carpeta Upgrade. Después ábrelo para editarlo. A diferencia del punto de guardado, no
quiero que esto
se dibuje en mi mapa, así que eliminaré el icono del mapa. No hay necesidad de que esto
se desvíe de su origen, así que restableceré la posición de los nodos de
área. Después hacer el área dos nodo
D, el nodo raíz, renombrarlo GEM y eliminar
el antiguo nodo Save Point dos D. Voy a sustituir el libro Sprite frames por otros nuevos
dibujando una gema giratoria Luego tener esta
animación reproducción automática y bucle a 12
fotogramas por segundo Luego podemos adjuntar un nuevo
script para nuestras actualizaciones. Reconectando el Área
dos nodos D cuerpo señal
ingresada al guión, podremos desbloquear los personajes del
jugador nueva habilidad cuando
toquen esta actualización Para ello,
exportaremos una variable de tipo Enums dot abilities, haciendo referencia al
script Enums que Esto crea un conveniente menú
desplegable en el inspector que nos
permitirá seleccionar una de nuestras habilidades para que se desbloquee este elemento de
actualización. Pero recuerda que una enumeración es solo un entero con un nombre En mi juego, la gema desbloqueará la capacidad del personaje
jugador para disparar proyectiles De vuelta en el guión, cuando el
cuerpo del personaje jugador entra en esta área, podemos establecer el valor del archivo dot data dot Habilidades desbloqueadas indexadas a
la habilidad a true Después guarda el juego para que
esta actualización sea permanente. Para que esto se sienta
más impactante, probablemente
querremos
hacer muchas cosas
elegantes antes
y después de esto, luego eventualmente eliminar
este nodo cuando hayamos terminado Podemos asegurarnos de que solo
ocurra
un solo evento de colisión con este nodo usando set
deferred para desactivar su propiedad de monitoreo
después de la primera colisión En mi escena de contenido de guardar habitaciones, pondré esto en alguna parte
para que pueda probarlo. A sin embargo, quería flotar arriba y abajo
como lo hace el punto guardado. En lugar de copiar y pegar
al código de un
script a otro,
deberíamos convertirlo en un componente que se
pueda adjuntar a
cualquier nodo dos D, igual que los scripts de
comportamiento enemigo. De vuelta en la escena de gemas, agregaré solo un nodo normal
y lo nombraré float. A continuación, copie y pegue en el código desde el
script de punto guardado en este script. En lugar de un tote de área, este solo será el padre del nodo
flotante, aunque debe
ser un no tutti o algún antepasado de un no tutti
para tener Luego podemos copiar este nodo en la escena Save Point y eliminar el código
del script Save Point. Estos tres scripts
son mucho más reutilizables cuando se escriben para que solo sirvan para un solo propósito, además de ser más fáciles de
entender y depurar. Otra cosa que
debemos hacer es no tener aquí
este ítem de mejora B si el jugador ya ha
desbloqueado esta habilidad. Anulando la función ready, verificaremos el valor de las habilidades desbloqueadas en los datos de guardado de
los jugadores para ver si esta habilidad ya está desbloqueada y pondremos en cola este
nodo para ser liberado
si tiene . Ahora vamos a probarlo. Cuando ejecuto el juego, puedo ver mi elemento de actualización
flotando allí. Presionar el botón para
disparar proyectiles
no funciona ya que aún no he
desbloqueado esta habilidad Al saltar para agarrar
el objeto de actualización, desaparece y
ahora puedo disparar proyectiles Cerrando el juego
y luego jugando de nuevo, el elemento de actualización no está ahí ya que
ya lo he recogido, y aún puedo
disparar proyectiles porque la habilidad estaba
permanentemente desbloqueada Ahora queremos que
coleccionar este artículo se sienta mucho más
impactante para el jugador Para probar esto, tendremos que eliminar
nuestros datos guardados. En el menú del proyecto, seleccione Abrir carpeta de datos de usuario para abrir esta carpeta en
su administrador de archivos, donde podemos ver guardar
los puntos, y podemos eliminarlo. Ahora cuando ejecutamos el juego, el jugador no tiene la
última posición guardada y no tiene habilidades desbloqueadas. Solo volveré a
la sala de guardado y golpearé mi Save Point,
luego cerraré el juego. Si quieres intentar
hacer la secuencia de eventos para recolectar el
ítem por ti mismo, probablemente quieras agregar efectos de
partículas u otros
nodos para lograr tu resultado. Pausa el video aquí, y luego
repasaremos lo que hice. Después de implementar
mi secuencia de eventos, es como se ven mis
resultados. Primero, declaré un
color constante blanco brillante. Esto no es solo blanco sino que
tiene una intensidad máxima, lo que
significa que hará otros
colores cercanos al blanco, también. Cuando el personaje del jugador
toca el ítem, detengo inmediatamente
la flotación hacia arriba y hacia abajo y congelo al personaje
del jugador deshabilitando el procesamiento Entonces comencé un
emisor de partículas que emitía las partículas de alrededor
del artículo moviéndose hacia adentro Luego, preteje el elemento a
la posición del personaje del jugador
más a mitad de camino para estar alrededor del centro de
su cuerpo mientras
también se interpelan los colores
tanto del elemento como del
personaje a blanco brillante la posición del personaje del jugador más a mitad de camino para estar alrededor del centro de
su cuerpo mientras también se interpelan los colores
tanto del elemento como del
personaje a Agregar paralelo a
una función de preadolescentes significa que todas estas sucederán al mismo tiempo en
lugar de
esperar a que una termine antes de
comenzar la siguiente Después desbloqueo la habilidad
y guardo el juego
igual que antes. Y después de desbloquear la
habilidad, oculta todos los elementos visuales, detiene las partículas interiores, inicia una
ráfaga de partículas hacia afuera y actualiza el sprite del
personaje para incluir el nuevo elemento Después de
volver a ajustar el color del
personaje del jugador al blanco normal, luego
vuelvo a activar el procesamiento
del
personaje del jugador y elimino este
elemento del árbol de escenas Las partículas interiores están reutilizando los mismos sprites de las partículas de polvo del
jefe. Están emitiendo
desde una esfera con un radio de 32 píxeles. Las partículas tienen una velocidad radial
negativa para atraerlas hacia el punto
central, sin gravedad. Alfa curvo 1-0 y animado. Las partículas de explosión hacia afuera
son en su mayoría las mismas excepto que es una
explosión de un solo disparo con explosividad Emitiendo desde un punto con máxima dispersión y suficiente amortiguación para cancelar
la velocidad inicial. Ahora tenemos
objetos coleccionables en nuestro juego que le
darán al jugador nuevas
formas de explorar el mundo Pero nuestro juego
sería mucho más divertido explorar si tuviera atajos. Te veré en el siguiente video. Y
67. 9-3 Atajo: Amigos. En este video, agregaremos un atajo que el
jugador puede desbloquear para que la
exploración de nuestro juego sea más
fluida y gratificante. Voy a usar la segunda habitación a la derecha de mi sala de inicio para construir mi atajo en la escena de contenido de la
segunda sala. He dividido la sala
en dos mitades distintas, y colocaré mi atajo
en el medio para que el jugador no pueda pasar por esta habitación si
entraba por la izquierda. Comenzando con un cuerpo estático para denodar para proporcionar detección de
colisiones, y un
nodo Sprite Toti para Usaré una textura de atlas y poblaré mi
terreno forestal como el atlas, luego usaré las tres
baldosas verticales para dibujar un muro Al agregar una forma de colisión como una caja y cubrir la pared
con colisión de terreno, el jugador no
podrá atravesar. Luego podemos agregar otro nodo
Sprite tutti usando una textura de atlas, y ya he importado una nueva hoja de sprite
para un Usaré el primer sprite
intacto y lo colocaré en el lado
derecho de la Entonces, si el jugador entra a esta
habitación por el lado derecho, podrá
atacar este aparato ortopédico, dañarlo y destruir la
pared para abrir el atajo. El aparato ortopédico necesitará
un área de caja de daño dos nodos D con una
forma de colisión dos nodos D hijo. Usaré otra forma de caja
y haré que cubra el sprite. O. Sería una buena idea poner esto en una
capa de colisión diferente para que
podamos controlar cuidadosamente
qué puede dañarla. Usaré la capa dos
para mis atajos. No olvides nombrar
tus capas de física en la configuración del proyecto para
que puedas recordar para
qué sirven. Tendremos que tener a nuestros
personajes la
caja de golpe de ataque masculino enmascarar esta capa para que puedan
dañar el corsé. Así como cualquier proyectil
que puedan disparar. De vuelta a la escena del contenido de la sala, deberíamos hacer de este
atajo su propia escena, ya que probablemente tendremos
múltiples de ellos en nuestro juego. Este atajo se realizará específicamente solo
para la región forestal. Así que lo guardaré en esa carpeta, y tendré que hacer otras escenas de
atajos para
mis otras regiones. Al abrir esta escena, podemos adjuntar el script de
Hurt Box
al nodo Hurt Box y también adjuntar un nuevo script al nodo raíz para el comportamiento de
los atajos. El propósito principal de este script será guardar cuando
este atajo sea destruido y mantenerlo destruido al cargar el contenido de
esta sala. Para hacer eso, usaremos
algo comúnmente llamado flag
exportando
una variable de cadena
para el nombre de la bandera. En la escena de contenido de la habitación, necesitaremos especificar un nombre de
bandera para este acceso directo. Podemos nombrar a esta bandera
lo que queramos, pero debe ser única para
cada atajo en nuestro juego. Voy a nombrar al mío Bosque
segundo atajo de habitación. Cambiando
al script de datos, necesitaremos una nueva variable
exportada para mantener nuestras banderas
en un diccionario. Usando la cadena como clave y el valor
será un booleano De vuelta en el script de acceso directo, cuando se destruye este atajo, podemos establecer el valor de file dot data dot flags siendo la clave nuestro nombre de bandera
y establecer el valor en true. Después guarda el juego para que esto sea permanente y después de
hacer algunas cosas visuales, quita el atajo
del árbol de escenas. Anulando la función ready, podemos verificar el
valor de nuestra bandera para ver si el atajo ya
ha sido destruido y eliminarlo
del árbol de escenas si lo fue Sin embargo, si el atajo aún no
ha sido destruido, el diccionario aún no tendrá ningún valor para este nombre de
bandera. Así que en realidad necesitamos verificar si el valor existe primero
antes de intentar acceder a él. Conectemos la señal de
daño recibido de la caja Hurt a la función de
destrucción de atajos, desvinculando el argumento Voy a mover la segunda
habitación para que esté a la izquierda de la sala de ahorro
para poder probarla. Al entrar
a esta habitación por la derecha, la pared impide que mi personaje
pase por ella. Puedo atacar el
aparato ortopédico para destruirlo, lo que destruye el muro, y puedo atravesarlo Cerrando el juego y
ejecutándolo de nuevo, el atajo permanece abierto. Sin embargo, hay
un pequeño problema. Reorganizaré mis habitaciones para que la segunda habitación esté de
vuelta a la derecha, luego eliminaré mi archivo seguro
para restaurar el acceso directo Ejecutando el juego otra vez. El muro sí impide que mi personaje
proceda. No obstante, todavía puedo romper el atajo abierto
desde este lado. Así que tendremos que
evitar que nuestro personaje pueda
atacar a través de las paredes. Al abrir la escena del personaje, podemos agregar un nodo
D cast two al hit box. Usaremos la misma estrategia que usamos para la agresión enemiga para verificar si hay una línea clara desde la caja de impacto
hasta la Caja de daño. Para ello, el rayo debería estar originado desde el centro del
personaje, y tendremos que enmascarar
todo lo que este cuadro de impacto pueda golpear más cualquier cosa que pueda
obstruirlo como terreno, incluyendo tanto cuerpos como áreas El rayo también puede originarse dentro de algunos de
estos colisionadores, por lo que también necesitará
poder golpear áreas y cuerpos desde el interior de
sus formas. En el script Hit box, podemos tomar una referencia a este nodo de reparto con
una etiqueta on ready, pero voy a cambiar la ruta del nodo
para usar get node o null. De esta manera, no todos los hit box nuestro juego necesitan tener
un raycast adjunto Cuando ocurra una colisión, primero
verificaremos si el
rayo existe, luego le diremos que apunte a la Daño que fue golpeada por
la caja de impacto y la obligaremos
a actualizarse de inmediato. Si el elenco de rayos está
golpeando algo y ese algo es
otra cosa que no sea la zona, eso significa que hay
algo más en el camino. Regresar evitará que se produzcan los
daños. Si ejecutamos el juego ahora, atacar el atajo desde el lado equivocado será bloqueado
por el colisionador de muros Si muevo esta habitación hacia el lado izquierdo y
entro por la derecha, puedo atacar el corsé y
destruir la pared ya que
el rayo disparado desde
la caja de
impactos del personaje no está obstruido Si quieres, puedes hacer una pausa
aquí y agregar efectos de partículas, sacudir e incluso requerir múltiples ataques para romper el corsé antes de
destruir la pared. Ahora que he agregado mis efectos, es como se ven mis
resultados. Después de un ataque, la pared
emite partículas de polvo, sacude y el corsé
queda visiblemente Después de un segundo ataque, el corsé
se rompe en varios pedazos, se retira
la pared y se vuelven a emitir las
partículas Para lograr este efecto, agregué
partículas de GPU al nodo emitiendo las mismas
partículas de polvo utilizadas anteriormente, pero esta vez emitiendo
desde una forma de caja. Agregué un
nodo de escombros como carpeta que contenía tres
piezas diferentes como cuerpos rígidos. Y un temporizador de batido que
emitirá una señal 12
veces por segundo. Conectando la señal recibida
dañada de la caja Hurt a una función recibida dañada, reinicié el emisor de
partículas, luego verifiqué si es la primera vez que
se Si ya está dañado, apago detección de
colisiones en la Caja de
Daño y destruí la pared. De lo contrario, establezca el daño en
true, actualice el corsé, sprite para dibujar la versión
dañada, luego inicia el temporizador de sacudidas
y deténgalo 1 segundo después La señal de tiempo de espera del temporizador llama a esta función de sacudida, que solo desplaza la pared píxel en una dirección
aleatoria Cuando se destruye el muro, actualicé los
datos guardados como antes, pero también dispersé algunos escombros, escondí tanto la pared
como el corsé. Después espera a que las partículas terminen antes de retirar toda
la escena. Para dispersar los escombros, lo
hice visible, luego descongelé todas
las piezas y les
agregué fuerzas de impulso iguales a sus posiciones
relativas al padre Ahora tenemos un atajo que
el jugador puede abrir, haciendo que retroceder sea mucho más fácil medida que explora nuestro mundo Pero todo el mapa es claramente visible para que ellos lo vean
desde el inicio del juego Te veré en el siguiente video.
68. Mapa de 9-4: Hola, amigos. En este video, ocultaremos nuestro mapa
al jugador y solo revelaremos habitaciones a medida que
el jugador entre en ellas. Comenzando en nuestro script de
guardar datos, podemos usar la misma
estrategia que hicimos con el punto de guardado para rastrear qué salas ha ingresado el
jugador. Exportaremos una nueva variable
llamada map of type dictionary. Las claves de este diccionario
serán los nombres de las regiones, y los valores serán
otro diccionario. Las claves del
segundo diccionario serán los nombres de las
habitaciones de esa región, y los valores serán booleanos rastreando si el
jugador ha ingresado o no a esa sala Si miramos en alguna
de nuestras escenas de habitación, el mapa será dibujado por
alguna forma de nodo Tu Di. En mi juego, están siendo dibujados por un nodo de capa de Tile Map. Sea cual sea el nodo, cambiar su visibilidad es
bastante trivial Describiremos una referencia a este nodo en nuestro script de sala. Puedes usar la etiqueta ready si el nodo de mapa es uniforme
para todas las habitaciones de todo tu proyecto o una etiqueta de exportación si
quieres más flexibilidad, pero tendrás que
asignarlo manualmente para cada habitación. También necesitaremos cada habitación para saber el nombre de
la región en la que se encuentra, que podemos automatizar
con una etiqueta lista, obteniendo el nombre del nodo padre de la habitación
en el árbol de escenas. Entonces podemos escribir una función
para actualizar la visibilidad
del mapa en función de si el jugador ha
entrado o no a esta sala antes. Comprobando archivo
dot data dot Map indexado
al nombre de la región nos
da otro
diccionario para la región, que podemos indexar al
nombre de la habitación Esto será un booleano
para saber si el jugador ha entrado o no a
esta sala previamente Y si es cierto, estableceremos visibilidad
de los mapas en true. Sin embargo, al igual que con
el diccionario flag, debemos tener cuidado de
no intentar
acceder a las entradas del diccionario
que no existen. Pero esto brinda una
oportunidad extra en este caso, ya que podemos utilizar la ausencia de la entrada del diccionario como información
adicional. Por ejemplo, podemos
verificar si el
diccionario de mapas tiene una
entrada para esta región. Si no lo hace, eso significa que el jugador nunca ha
entrado en esta región antes. De igual manera, si la
entrada a la sala no existe, entonces el jugador no tiene conocimiento que esta sala siquiera existe. Primero tendremos que verificar si la entrada de región existe
en el diccionario de mapas. Si no es así el jugador no
debería
poder ver este mapa, y podemos simplemente regresar
fuera de esta función. Entonces haz lo mismo con la entrada de habitación en el diccionario de la
región. Si la entrada no
existe, voy a ocultar el mapa. Sin embargo, si existe, entonces podemos establecer
la visibilidad true y verificar el
valor del booleano Si el booleano es verdadero, entonces estableceré los mapas modulan
Alpha a Pero si es falso, lo configuraré para
que sea semitransparente. Esto significa que puedo diferenciar
las habitaciones en
el mapa que el jugador conoce de las que han ingresado
previamente. Alternativamente, es posible que
desee usar un nodo diferente para dibujar estos diferentes estados y alternar la visibilidad de
cada nodo individual. Podemos inicializar la visibilidad del mapa durante
la función ready Podemos escribir otra función para descubrir una habitación y
revelar su mapa. Para crear nuestros dos estados de mapa
diferentes, podemos aceptar un parámetro
booleano para saber si esta habitación está siendo
descubierta ingresándola Todo lo que esta función
tiene que hacer es establecer el valor del archivo
dot data dot Map, indexado en el nombre de la región, indexado en el nombre de la habitación
al valor de Introducido Pero si este valor ya existe y se ha establecido en true, no
queremos volver a
establecerlo en false. Podemos usar la
operación lógica o para establecerla en false solo si no
es ya cierta. Luego llame a la función Actualizar visibilidad del
mapa para comenzar a dibujarlo en consecuencia. Si la región aún no
existe en el diccionario de mapas, entonces esta es la primera sala que el jugador ha descubierto
en esta región. Esta sería una buena oportunidad para hacer algo interesante, como mostrar una carta de
título o jugar una escena de atajo para introducir al jugador a la nueva región. Voy a llamar a una función aún no escrita para la región
llamada Discover. Este se encargará de inicializar la
entrada del diccionario de mapas para la región Cambiando al guión del manager del
juego, cuando el personaje del jugador
entra en una nueva habitación, podemos descubrir esa habitación con un argumento de verdad para
dibujarla opaca en el mapa. En la escena principal del juego, podemos adjuntar un guión
a las regiones de nuestro juego. Al escribir la función de descubrimiento, esto se llamará
la primera vez un jugador entra en alguna
habitación de esta región. Así podemos comenzar creando la entrada del diccionario de mapas para esta región en el
reproductor guardar datos. También aprovecharé esta
oportunidad para agregar la región al mapa del jugador llamando a
una función de revelar Mapa. Esto simplemente iterará por cada habitación de esta
región y la descubrirá,
pero con un argumento de falso, por lo que se dibujará
semitransparente Este script deberá
adjuntarse a todas las regiones. En cada una de las escenas de mi región, también
agregaré un nodo de etiqueta para mostrar el nombre de
esa región en el mapa. Para que esto sea legible
en la cámara de mapas, necesitará tener un tamaño de fuente
muy grande. Voy a establecer el tamaño de fuente en 256. Luego establece el color de fuente para que
coincida con el color de las habitaciones. Para que destaque más, también
agregaré una sombra
y un contorno. Tendrá que estar
en la capa de visibilidad dos para que la
cámara del mapa la vea. Voy a copiar esta nota de etiqueta en mi región volcánica y cambiar su color de texto
para que coincida con esa región. Al agregar una capa de lienzo a
la escena de la región dos, podemos hacer una carta de
título simple para mostrar cuando el jugador ingresa por
primera vez a cada región. Con otro nodo de etiqueta, mostraré el nombre
de esta región en el centro de la pantalla
con un tamaño de fuente grande. Voy a hacer esto invisible
por defecto y solo lo
mostraré cuando el jugador entre a esta región
por primera vez. En el script de región, animaré esta
pantalla con una preadolescentes, tweening el Alpha del nodo
label hasta uno,
esperando 1 segundo, luego
tweening de nuevo a cero Se necesitará tener un Alfa de cero para comenzar y
hacerse visible. Esto se puede copiar en mis otras regiones y
actualizarse con sus nombres. Cuando se descubra la región, guardaré el juego y haré visible
la etiqueta del mapa. Esto también deberá
inicializarse en la función
ready en
función de si la entrada de región
existe o
no en el diccionario Map Ahora que las regiones tienen
niños que no son habitaciones, tendré que verificar
si los niños son realmente habitaciones
antes de llamar a sus funciones de descubrimiento.
Vamos a probarlo. Cuando comienza el juego, el jugador ingresa automáticamente a la
región del bosque. Por lo que se muestra la tarjeta de título para la región
forestal. Se revelan los datos del mapa, pero solo la
sala de inicio es opaca ya que esa es la única
habitación a la que he ingresado. Al entrar en cada habitación, las habitaciones cambian de
transparentes a opacas. He quitado el atajo de la otra habitación para
facilitar las cosas. Aún
no se ha ingresado a la región volcánica, por lo que no se
revela en el mapa. Y cuando entro a
la región volcánica, muestra su tarjeta de título y sus habitaciones
se agregan al mapa. Aunque todavía no he
construido nada apropiado para esta región. Al regresar a la región forestal, la región ya ha
sido descubierta, por lo que no
muestra su tarjeta de título. Ahora tenemos un sistema
para revelar el mapa de
nuestro juego gradualmente a medida que el jugador
explora nuestro mundo. Pero las regiones de
nuestro juego se sentirían
mucho más distintas con
algo de música de fondo. Te veré en el siguiente video.
69. Música de 9-5: Hola, amigos. En este video, agregaremos algo de música de fondo que cambiará con
cada región de nuestro juego. Esto no solo
ayudará a enfatizar la apariencia única de cada región, sino que también proporcionará una
sensación extra de progresión. Cuando importas
música de fondo a tu proyecto de juego, selecciona los archivos en
la pestaña Sistema de archivos, luego abre la pestaña Importar y
cambia el modo de bucle para reenviar. De lo contrario, tu música
sólo se reproducirá una vez y luego se detendrá. Esto requerirá una
reimportación de los activos. En cada una de nuestras escenas de la región, podríamos poner un nodo reproductor de
flujo de audio para reproducir estas pistas de música. Pero eso requeriría que
manejemos cuál está
jugando en un momento dado, lo cual es una especie de molestia. Por lo general, no vamos a querer tener más de una
pista de música de fondo sonando a la vez de todos modos. Por lo que sería más fácil
tener un solo nodo reproductor de
flujo de audio dedicado a reproducir música de
fondo al que podamos acceder desde
cualquier lugar de nuestro juego. Pero cada región
aún necesita saber qué música de fondo se
debe tocar para ello. En nuestro script de región, podemos exportar una variable para contener la música de fondo para esta
región como una transmisión de audio. Después, poblar la variable
exportada para cada región en sus escenas
individuales con diferentes archivos de música Luego podemos crear
un script global para administrar nuestra música de fondo, heredando de
Audio Stream Player Luego abra la configuración del proyecto, la pestaña Globales y agregue este script a la
lista de nodos globales Volviendo al guión, realmente solo necesitamos
dos funciones públicas, una que le diga
al guión que reproduzca una pista de música y acepte la transmisión de
audio como parámetro, y otra para dejar de
reproducir música. Pero detener la música de repente
sería un poco discortante. Es bastante común
desvanecer la música al reducir su volumen
gradualmente antes de detenerse. Comenzando con la función de
reproducción de pista, podemos establecer la transmisión
que se está reproduciendo al parámetro de pista y llamar la función de
reproducción de reproductores de flujo de audio para
comenzar a reproducirla. Pero si algo ya está jugando, tenemos
que detenerlo primero. Entonces, si este guión ya está reproduciendo algo y lo que está reproduciendo es lo mismo que lo
que queremos tocar,
podemos simplemente regresar. Si no es lo mismo, entonces
podemos esperar
a desvanecerse al volumen primero, y después de eso, podemos cambiar a la nueva pista
y volver a desvanecerse Para desvanecer el volumen gradualmente, necesitaremos una tween y una función para
tweening el volumen, aceptando el valor final para
el volumen como parámetro Después de verificar si la preadolescente ya existe y matarla, crearemos una nueva
preadolescente y el volumen hasta su
valor final durante Solo usaré 1 segundo. El volumen generalmente se
mide en decibelios, que no es una
unidad de medida lineal Por lo que no se recomienda ajustar el volumen en
decibelios. En su lugar, usamos el valor de volumen
lineal, que es un flotador simple
que va desde cero para el silencio hasta uno
para el volumen normal. Podemos devolver la señal de tween terminada para que
podamos esperarla. Para dejar de reproducir música, solo
tenemos que esperar a que
el volumen llegue a cero, luego llamar a stop y devolver
la señal terminada. Y después de cambiar de pista, deberíamos volver
a desvanecer el volumen a uno para que podamos
escuchar la nueva música. Ahora solo tenemos que decirle a este nodo qué
pista de música reproducir y cuándo. Por simplicidad, asumiré que cuando se carguen los
contenidos de una habitación, quiero reproducir la música que está
asociada a esa región. Así que llamando a la música play Track, voy a pasar por la región, que es el padre de
la habitación punto Música. Si se le dice que reproduzca la misma música
que ya se está reproduciendo, el nodo global de música
simplemente ignorará la solicitud. Entonces no hay necesidad de revisar
lo que ya se está reproduciendo. Vamos a probarlo.
Ejecutando el juego, empiezo en la región forestal, y así suena el tema de la
música forestal. Vestuarios, la música
no cambia mientras yo
siga en la región forestal. Pero si hago la transición a
la región volcánica, el tema de la región forestal se desvanece
y el
tema de la región
volcánica juega en su lugar Probablemente habrá
momentos en los que quieras
tocar temporalmente una
pista de música específica, como durante una
escena de corte o una pelea de jefes. Así que agreguemos dos
funciones más a nuestro guión musical. Uno para anular la pista de música
actual y otro para volver
a la pista de música anterior Necesitaremos una variable para mantener la música de
fondo de la región actual. Cuando se nos dice que anulemos la música de fondo
con una nueva pista de música, primero
almacenaremos la
música de fondo de la región en nuestra variable. Entonces espera el fade out
y toca nuestro nuevo tema. Después de que el evento haya terminado, podemos volver a música de fondo de
nuestra Región desvaneciéndonos luego tocando la
vieja pista de música En nuestro guión de encuentro con jefes, podemos exportar una variable para contener una pista de música especial
para nuestra música de jefe. Entonces en el encuentro con el
jefe de Mc Mouse, podemos darle a esta pelea de jefes
su propia pista musical especial. Se le puede decir al
nodo global de música que reproduzca esta música cuando comience el encuentro con el
jefe. Y vuelve a la música de fondo de la
región
cuando termina la pelea Y por último, a este nodo de música se le
debe decir a qué
bus pertenece en el Audio Bus para que podamos controlar su volumen en otras
configuraciones más fácilmente. Así que anulando la función
ready, podemos establecer manualmente el
valor del bus para que sea música Ahora tenemos un sistema de
música global que
podemos usar para reproducir cualquier música que
necesitemos para nuestro juego, pero nuestro encuentro con el jefe
todavía necesita algo de trabajo. Te veré en el siguiente video.
70. Jefe final de 9 a 6: Hola, amigos. En este video, completaremos el
encuentro con el jefe con una arena y impediremos que el jefe
reaparezca una vez que sea derrotado He reorganizado mis
habitaciones para que el jugador comience en la sala de guardado
justo al lado de la sala de jefes Al abrir el contenido de las salas de jefe, he seguido adelante y construí la escena de contenido de la sala Boss con múltiples capas de Parallax Para que el nodo D de la capa
dos de Tile Map pudiera
desplazarse por Parallax, tuve que crear un nuevo
script heredando de capa
Tile Map sin
el desplazamiento automático Dado que el nodo D de
capa dos de Tile Map no tiene la propiedad region
destrozada, no puede usar el mismo método si quisiéramos que se desplazara automáticamente Cada una de las
capas de Tile Map a Di nodos tienen una escala de desplazamiento diferente y modulan más hacia
el color de fondo Para hacer un seguimiento de qué jefes ha derrotado
el jugador, abramos el script de
datos y agreguemos una nueva variable llamada
Boss is derrotado Una alternativa al uso de un
diccionario es una matriz. Cada vez que un jefe es derrotado, podemos simplemente agregar su
nombre a esta matriz En el guión de encuentro con jefes, podemos anular la función
ready para verificar si este jefe
ya ha sido derrotado. Si file dot data dot boss es derrotado tiene una entrada
que coincide con el nombre del jefe, entonces el jugador
ya ha derrotado este jefe y podemos eliminar
este encuentro de jefe. Cuando el jefe es derrotado, podemos agregar el nombre del jefe a la serie de jefes Después guarda el juego para
que sea permanente. A diferencia de los diccionarios, las matrices
pueden tener duplicados. Entonces, cuando estés almacenando
información de esta manera, es posible que quieras verificar si la entrada ya existe
antes de agregarla. Quitar el
nodo de encuentro de jefe del
árbol de escenas en este momento también
eliminará al jefe en sí, lo que
no quiero hacer. Pero si el jugador
saliera de la habitación y volviera a entrar, el jefe será removido
por la función listo. Esto será suficiente para
que el jefe se quede derrotado, pero el encuentro en sí
podría usar algunas mejoras. Lo primero que quiero hacer
cuando comience la batalla de jefes es cerrar una puerta bloqueando al
jugador dentro de la arena. Al igual que con el atajo, utilicé un cuerpo estático para de nodo, reutilizando el mismo
sprite de pared que el terreno Y una forma de colisión rectangular. Sin embargo, el sprite y
la forma de colisión se colocan muy por encima del punto de origen de la
puerta, lo que la puerta está abierta por defecto Cuando se le dice que se cierre, la puerta reposiciona
la forma de colisión, luego preajusta la
posición de los sprites para que coincida, y al abrir la puerta se devuelve la forma de colisión
y el sprite a sus posiciones
originales Dando a esta puerta un nombre único, podemos cerrarla en el
guión de encuentro del jefe cuando
comience la batalla y abrirla
cuando termine la batalla Recuerda llamar a las funciones de
superclase para
hacer también todo lo demás en las funciones de
inicio y fin, también. También quiero hacer que
el jefe luche más duro al dejar caer
rocas llameantes desde el techo Entonces he hecho otra escena
para los cantos rodados llameantes, que son un
cuerpo rígido dos nodos D. Esto simplemente
manejará automáticamente la gravedad por mí. Están siendo
dibujados y animados por un
Sprite Animado dos nodos D, bucle a través de los sprites
importados a 12 fotogramas por
segundo automáticamente El cuerpo rígido está en una nueva capa de
colisión apartada específicamente para peligros y no
está enmascarando nada. Por lo que no chocarán con nada,
incluido el terreno Simplemente caerán desde arriba de la arena hasta debajo de la arena, y hay un hit box adjunto, monitoreando la Caja Hurtada del
personaje del jugador. No olvides conectarte a la
señal ingresada por el área para infligir daño. En mi script de encuentro con Mc mouse, he exportado una variable para sostener esta roca llameante
como una escena repleta, que puedo instanciar como un nuevo cuerpo rígido de roca
llameante Cuando me dijeron que engendrara cantos rodados en
llamas, hice un bucle varias veces
aleatoriamente entre el número de fase y
el número de fase por dos para que
el número de cantos rodados
aumente Instanciar una nueva roca, agregué a la escena
y la coloqué encima la arena en una posición aleatoria entre las paredes izquierda
y derecha Para que el evento de choque sea
aún más impactante, también
agregaré un movimiento de cámara. Godot hace que sea bastante fácil
acceder a la
cámara actual desde cualquier lugar Primero, solo necesitamos llamar a
la función Get Viewport, luego llamar a las ventanas gráficas
Get camera two D Entonces podemos llamar a nuestra
función de sacudir para sacudir la cámara. Le daré una intensidad de dos píxeles por
cuarto de segundo. Entonces puedo conectar la señal estrellada del
ratón Mc al guión de encuentro para desencadenar
el desove de
los cantos rodados en llamas en
respuesta Dado que los cantos rodados
son cuerpos rígidos, caerán naturalmente
debido a la gravedad Entonces puedo
limpiarlos después de que hayan caído por debajo
del fondo de la arena usando un área dos D. Esta área de recolección de
basura es solo un
área rectangular que cubre el
fondo de la arena, lo suficientemente
lejos por debajo de que
cualquier cosa que ingrese esta área no será
visible para la cámara. El nodo de área está monitoreando y enmascarando la capa de peligros. Su señal ingresada en el cuerpo
se conecta de nuevo
al script del contador del mouse Mc para eliminarlos
del árbol de escenas. Con los cambios realizados en el hit box de
nuestro personaje, requiriendo que el elenco
del hit box al Hurt
Box no estuviera obstruido, tuve que reorganizar la tecla del mouse de mi
Mac Entonces ahora la Caja Hurtada está
determinando la posición y la forma de colisión está en
su posición de origen local. Dado que el nodo Área dos D está determinando la
posición en sí, el script ya no necesita hacer
referencia a la
forma de colisión y en su lugar voltea su propia posición en respuesta a que el personaje
cambie de dirección Vamos a probarlo. Entraré a mi habitación de jefes y encontraré a mi
jefe enemigo ahí sentado. Puedo atacar la llave para
darle cuerda y comenzar el encuentro con el
jefe. Esto desencadena el inicio
de mi pelea de jefes, que cambia la música y cierra la puerta a la
arena, atrapándome Mientras lucho contra el jefe, cada vez que choca contra una pared, desencadena un movimiento de cámara y deja caer rocas llameantes
desde el techo Si bien no podemos ver
qué pasa con los cantos rodados en llamas ya
que caen por debajo de la cámara, están siendo limpiados por
el área de recolección de basura Cuando el jefe entra en
su segunda fase, aumenta
el número de
cantos rodados llameantes generados, y derrotar al jefe
termina el encuentro,
cambiando la música de nuevo a la música región volcánica
y abriendo
la puerta Al salir de la habitación
y regresar, el encuentro con el jefe ya no
está ahí. Ahora tenemos
todo lo que necesitamos para construir un juego completo de
Metroidvania En el siguiente video,
repasaremos nuestros próximos pasos. Te veré en el siguiente video.
71. 9-7 final: Hola, amigos. Enhorabuena
por completar el curso. Ahora tienes todas las
herramientas y habilidades necesarias para construir un juego
básico de Metroidvania, completo con
habilidades desbloqueables que poco le darán al
jugador acceso a más del mundo para explorar
un mapa que muestre
la ubicación actual
del jugador y guardar puntos para hacer Todo lo que queda por hacer
ahora es repetir muchas de las lecciones que se imparten a lo largo del curso para crear más de él. Más habitaciones,
llenando más regiones con más enemigos que luchar y
más atajos para desbloquear. Sigue estos pasos para sacar más provecho de este
curso y seguir aprendiendo más habilidades
que puedes usar para construir tu propio juego
Metroidvania Paso uno. Si este es tu primer
gran proyecto de juego, deberías poder
construir un juego siguiendo esta plantilla con al menos
tres regiones diferentes, cada una con múltiples salas que contengan diferentes tipos de
enemigos, desafíos de
plataformas, y estas regiones deberían sentirse
distintas entre sí Siguiendo los principios de diseño de
juegos de Metroidvania, tu juego debe demostrar
al jugador obstáculos
que no puede superar antes de desbloquear la
capacidad El camino crítico
a través del juego debería requerir
retroceder por áreas
anteriores y
darle al jugador múltiples oportunidades nuevas para explorar con sus
nuevas habilidades Intenta hacer un juego que tarde
al menos 10 minutos en
completarse de principio a fin sin ser
demasiado repetitivo Paso dos, después de que
hayas terminado con tu juego y
quieras más de un desafío, tal vez quieras pensar algo que
quieras cambiar. A lo mejor no te gusta
la forma en que funciona el salto de pared o quieres agregar fuerza de retroceso al ataque del
personaje del jugador Intenta idear una forma de ajustar la mecánica
para que funcione de la manera que prefieras y cambiar la forma en que se
implementa en el juego. Intenta evitar hacer
algo completamente nuevo todavía. Solo concéntrate en hacer ajustes
a lo que ya está ahí. Paso tres. Una vez que puedas
hacer cambios en la mecánica
que ya existe, tu siguiente paso debería ser agregar una nueva mecánica que utilice
las herramientas ya proporcionadas. Algunas cosas que
quizás quieras agregar
al juego pueden ser un objeto
coleccionable que aumente la salud
máxima del jugador o un nuevo hechizo que cure
al personaje del jugador Agregar estas mecánicas
al juego no requiere nuevas habilidades, pero requiere que
aprendas a integrar múltiples sistemas existentes
juntos de una manera nueva. También es posible que desee buscar algunos activos nuevos
para
usar para sus nuevas mecánicas
o intentar crear los suyos propios. Paso cuatro. Ahora que puedes hacer que los
mecánicos existentes funcionen de la manera que quieras e integrarlos
con nuevos sistemas, es hora de diseñar y construir una nueva mecánica
desde cero. Esta podría ser una habilidad de Metroidvania completamente
nueva que permite al jugador
acceder a más del mundo, agregando NPC para que el jugador hable con un sistema de
diálogo, haciendo que los enemigos dejen dinero
para que el jugador los recoja y permitiéndoles gastar ese dinero en una tienda para Antes de comenzar, asegúrese tomarse un tiempo para
pensar en todos
los sistemas existentes que
necesitarán comunicarse
con el nuevo mecánico. Considera qué partes de
tu diseño se deben abstraer o qué se puede heredar de los scripts existentes Paso cinco. Si puedes crear un sistema
completamente nuevo e
integrarlo con éxito en este juego, entonces deberías estar listo para
hacer un nuevo juego desde cero. O encuentra un paquete de activos
diferente en línea o crea tus
propios activos para usar mientras construyes un juego de Metroidvania completamente
nuevo desde cero y completamente
de tu Le invitamos a compartir su
trabajo en nuestro servidor de discordia mientras continúa aprendiendo y crecer sus habilidades
con este proyecto Paso seis. Una vez que tu juego esté listo, puedes compartirlo en
plataformas como Ich para obtener comentarios de los
jugadores e incluso vender el juego cuando
esté completo. Probablemente no ganarás
mucho dinero vendiendo juegos en IH, pero los comentarios serán invaluables para mejorar tus habilidades de desarrollo de
juegos Si tienes un juego que
ha funcionado bien en Ich, entonces podrías intentar venderlo en Steam para llegar a un público mucho
mayor. Pero el listón
de calidad para
que un juego tenga éxito en
Steam es mucho mayor. Y necesitarás
tener una estrategia de mercado si quieres que tu juego
sea notado por los jugadores. Buena suerte al completar
tu proyecto. Espero con ansias
ver su trabajo.