Creación del juego "Me gusta las monedas" en Godot Engine. Parte 1

Godot Engine se está desarrollando muy rápido y se está ganando los corazones de los desarrolladores de juegos de todo el mundo. Quizás esta sea la herramienta más amigable y fácil de aprender para crear juegos, y para asegurarse de esto, intente hacer un pequeño juego 2D. Para una buena comprensión del proceso de desarrollo del juego, debe comenzar con los juegos en 2D; esto reducirá el umbral para ingresar a un sistema de juego más serio. Aunque la transición a 3D en sí misma no es tan difícil como podría parecer, después de todo, la mayoría de las funciones en Godot Engine se pueden usar con éxito tanto en 2D como en 3D.


Introduccion


Lo más simple que se te ocurre es un juego en el que nuestro personaje principal recogerá monedas. Para complicarlo un poco, agregue un obstáculo y tiempo, como factor limitante. El juego tendrá 3 escenas: Player , Coin y HUD (este artículo no se considera), que se combinarán en una escena Main .



Configuración del proyecto


Antes de sumergirse en escribir guiones (guiones), que es aproximadamente el 80-90% del tiempo total dedicado a la creación del juego, lo primero que debe hacer es configurar nuestro proyecto futuro. En proyectos grandes, es útil crear carpetas separadas para almacenar guiones, escenas, imágenes y sonidos, y definitivamente deberíamos tener esto en cuenta, porque quién sabe cuál será el resultado final.


Quiero hacer una reserva de inmediato porque este artículo asume que está un poco familiarizado con Godot Engine y que tiene algunos conocimientos y habilidades para usar esta herramienta, aunque me centraré en el hecho de que se encuentra con Godot Engine por primera vez, todavía estoy Le aconsejo que primero se familiarice con el componente básico del motor, estudie la sintaxis de GDScript y comprenda la terminología utilizada (nodos, escenas, señales, etc.), y solo luego regrese aquí y continúe conociendo.

En el menú del programa, vaya a Project -> Project Settings .


Otra pequeña digresión. Siempre daré ejemplos basados ​​en el hecho de que el usuario final usa la interfaz en inglés del motor, a pesar de que el "Godot Engine" tiene soporte para el idioma ruso. Esto se hace para deshacerse de posibles malentendidos o vergüenzas asociadas con la traducción incorrecta / inexacta de ciertos elementos de la interfaz del programa.

Busque la sección Display/Window y establezca el ancho en 800 y la altura en 600 . También en esta sección, establezca Stretch/Mode en 2D y Aspect para Keep . Esto evitará el estiramiento y la deformación del contenido de la ventana al cambiar su tamaño, pero para evitar que el tamaño de la ventana cambie de tamaño, simplemente desmarque la casilla Resizable tamaño. Te aconsejo que juegues con estas opciones.


Ahora vaya a la sección Rendering/Quality y active Use Pixel Snap en el panel derecho. ¿Para qué es esto? Las coordenadas de los vectores en Godot Engine son números de coma flotante. Dado que los objetos no se pueden dibujar solo medio píxel, esta discrepancia puede causar defectos visuales en los juegos que usan pixelart . Y vale la pena señalar que en 3D esta opción es inútil. Ten esto en cuenta.


Escena del jugador


Comencemos a crear la primera escena: Player .


La ventaja de cualquier escena es que inicialmente son independientes de otras partes del juego y esto hace posible probarlas libremente y obtener el resultado que originalmente se estableció en ellas. En general, dividir los objetos del juego en escenas es una herramienta útil para crear juegos complejos: es más fácil detectar errores, realizar cambios en la escena misma, mientras que otras partes del juego no se verán afectadas, también pueden servir como plantillas para otros juegos y definitivamente funcionarán igual de bien. mientras trabajaban antes de la transferencia.

Crear una escena es una acción trivialmente simple: en la pestaña Scene , haga clic en + (Agregar / Crear) y seleccione el nodo Area2D e inmediatamente cambie su nombre para no confundirse. Este es nuestro nodo principal, y para expandir la funcionalidad necesita agregar nodos secundarios. En nuestro caso, estos son AnimatedSprite y CollisionShape2D , pero no nos apresuremos, empecemos en orden. A continuación, "bloquee" inmediatamente el nodo raíz:



Si la forma de colisión corporal (CollisionShape2D) o el sprite (AnimatedSprite) se desplazan, se estiran en relación con el nodo primario, esto definitivamente conducirá a errores imprevistos y más tarde será difícil corregirlos. Con esta opción habilitada, el "padre" y todos sus "hijos" siempre se moverán juntos. Suena divertido, pero usar esta función es extremadamente útil.


AnimatedSprite


Area2D nodo muy útil si necesita saber sobre un evento de superposición con otros objetos o sobre su colisión, pero por sí mismo es invisible a la vista y para que el objeto Player visible, agregue AnimatedSprite . El nombre del nodo nos dice que trataremos con animaciones y sprites. En la ventana del Inspector , vaya al parámetro Frames y cree un nuevo SpriteFrames . Trabajar con el panel SpriteFrames es crear las animaciones necesarias y SpriteFrames los sprites correspondientes. No analizaremos en detalle todas las etapas de creación de animaciones, dejando esto para un estudio independiente, solo diré que deberíamos tener tres animaciones: walk (animación para caminar), idle (estado de reposo) y die (animación de muerte o falla). No olvide que el valor de SPEED (FPS) debe ser 8 (aunque puede elegir un valor diferente, adecuado).



Collisionshape2d


Para que Area2D detecte colisiones, debe proporcionarle la forma de un objeto. Las formas están determinadas por el parámetro Shape2D e incluyen rectángulos, círculos, polígonos y otros tipos de formas más complejas, y los tamaños ya están editados en el editor, pero siempre puede usar el Inspector para un ajuste más preciso.


Escenarios


Ahora, para "revivir" nuestro objeto de juego, debes configurar un script para él, de acuerdo con el cual se realizarán las acciones establecidas por nosotros, que se prescriben en este escenario. En la pestaña Scene , cree un guión, deje la configuración predeterminada, elimine todos los comentarios (líneas que comienzan con el signo '#') y proceda a declarar las variables:


 export (int) var speed var velocity = Vector2() var window_size = Vector2(800, 600) 

El uso de la palabra clave export permite establecer el valor de la variable de speed en la ventana del panel Inspector . Este es un método muy útil si queremos obtener valores personalizados que sean convenientes para editar en la ventana del Inspector . Ajuste la Speed a 350 . El valor de la velocity determinará la dirección del movimiento, y window_size es el área que restringe el movimiento del jugador.


El orden adicional de nuestras acciones es el siguiente: utilizamos la función get_input() para verificar si se está ingresando el teclado. Luego moveremos el objeto, de acuerdo con las teclas presionadas, y luego reproduciremos la animación. El jugador se moverá en cuatro direcciones. De forma predeterminada, Godot Engine tiene eventos asignados a las teclas de flecha ( Project -> Project Settings -> Input Map ), por lo que podemos aplicarlos a nuestro proyecto. Para averiguar si se ha presionado una tecla, debe usar Input.is_action_pressed() deslizándole el nombre del evento que desea rastrear.


 func get_input(): velocity = Vector2() if Input.is_action_pressed("ui_left"): velocity.x -= 1 if Input.is_action_pressed("ui_right"): velocity.x += 1 if Input.is_action_pressed("ui_up"): velocity.y -= 1 if Input.is_action_pressed("ui_down"): velocity.y += 1 if velocity.length() > 0: velocity = velocity.normalized() * speed 

A primera vista, todo se ve bien, pero hay un pequeño matiz. La combinación de varias teclas presionadas (por ejemplo, hacia abajo y hacia la izquierda) provocará la adición de vectores y, en este caso, el jugador se moverá más rápido que si simplemente se moviera hacia abajo. Para evitar esto, usaremos el método normalized() : devolverá la longitud del vector a 1 .


Entonces, se rastrearon los eventos de pulsación de teclas, ahora debe mover el objeto Player . La función _process() nos ayudará con esto, que se llama cada vez que ocurre un cambio de marco, por lo que es aconsejable usarlo para aquellos objetos que a menudo cambian.


 func _process(delta): get_input() position += velocity * delta position.x = clamp(position.x, 0, window_size.x) position.y = clamp(position.y, 0, window_size.y) 

Espero que notes el parámetro delta , que a su vez se multiplica por la velocidad. Es necesario explicar de qué se trata. El motor del juego está configurado inicialmente para funcionar a una velocidad de 60 cuadros por segundo. Sin embargo, puede haber situaciones en las que la computadora o el motor Godot se desaceleran. Si la velocidad de fotogramas no es consistente (el tiempo que tardan en cambiar los fotogramas), esto afectará la "suavidad" del movimiento de los objetos del juego (como resultado, el movimiento es "desigual"). "Godot Engine" resuelve este problema (como la mayoría de los motores similares) mediante la introducción de la variable delta : da el valor por el que se cambiaron los marcos. Gracias a estos valores, puede "alinear" el movimiento. Presta atención a una función notable más: la clamp (devuelve el valor dentro de dos parámetros específicos), gracias a ella podemos limitar el área que el Player puede mover simplemente configurando el valor mínimo y máximo del área.


No te olvides de animar nuestro objeto. Tenga en cuenta que cuando el objeto se mueve hacia la derecha, debe voltear AnimatedSprite (usando flip_h ) y nuestro héroe mirará en la dirección donde se mueve directamente cuando se mueve. Asegúrese de que en AnimatedSprite el parámetro Playing esté habilitado para que la animación comience a reproducirse.


 if velocity.length() > 0: $AnimatedSprite.animation = "walk" $AnimatedSprite.flip_h = velocity.x < 0 else: $AnimatedSprite.animation = "idle" 

Nacimiento y muerte


Al iniciar el juego, la escena principal debe ser informada de las escenas clave sobre su preparación para comenzar un nuevo juego, en nuestro caso, debemos informar al objeto del Player sobre el inicio del juego y establecer los parámetros iniciales para él: posición de apariencia, animación predeterminada, ejecutar set_process .


 func start(pos): set_process(true) #     Vector2(x, y) position = pos $AnimatedSprite.animation = "idle" 

También proporcionamos el evento de muerte de un jugador cuando se acaba el tiempo o el jugador se encuentra con un obstáculo, y establecer set_process (false) hará que la función _process () ya no se ejecute para esta escena.


 func die(): $AnimatedSprite.animation = "die" set_process(false) 

Agregar colisiones


Era el turno de hacer que el jugador detectara colisiones con monedas y obstáculos. Esto se implementa más fácilmente usando señales. Las señales son una excelente manera de enviar un mensaje para que otros nodos puedan detectarlas y responder. La mayoría de los nodos ya tienen señales incorporadas, pero es posible definir señales de "usuario" para sus propios fines. Las señales se agregan si las declara al comienzo del script:


 signal pickup signal die 

Explore la lista de señales en la ventana Inspector (pestaña Node ) y preste atención a nuestras señales y a las señales que ya existen. Ahora estamos interesados ​​en area_entered () , se supone que los objetos con los que se producirá la colisión también son de tipo Area2D . Conectamos la señal area_entered () usando el botón Connect , y en la ventana Connect Signal , seleccionamos el nodo resaltado (Reproductor), dejamos el resto por defecto.


 func _on_Player_area_entered( area ): if area.is_in_group("coins"): #  emit_signal("pickup") area.pickup() 

Para que los objetos puedan detectarse e interactuar fácilmente, deben identificarse en los grupos apropiados. Ahora se omite la creación de los propios grupos, pero definitivamente volveremos a ellos más tarde. La función pickup() determina el comportamiento de la moneda (por ejemplo, puede reproducir una animación o sonido, eliminar un objeto, etc.).


Escena de la moneda


Al crear una escena con una moneda, debe hacer todo lo que hicimos con la escena "Jugador", excepto que solo habrá una animación (resaltado) en AnimatedSprite . Speed (FPS) se puede aumentar a 14 . También cambiaremos la escala de AnimatedSprite : 0,5, 0,5 . Y las dimensiones de CollisionShape2D deben corresponder a la imagen de la moneda, lo principal es no escalarla, es decir, cambiar el tamaño usando los marcadores apropiados en el formulario en el editor 2D, que
ajusta el radio del círculo.



Los grupos son un tipo de etiquetado de nodos que le permite identificar nodos similares. Para que el objeto Player reaccione al tocar con monedas, las monedas deben pertenecer al grupo, llamémoslas coins . Seleccione el nodo Area2D (con el nombre "Moneda") y asígnele una etiqueta en la pestaña Node -> Groups , creando el grupo correspondiente.



Para el nodo Coin , cree un script. La función pickup() será invocada por el script del objeto Player y le dirá a la moneda qué hacer cuando funcione. El método queue_free() eliminará de forma segura un nodo del árbol con todos sus nodos secundarios y borrará la memoria, pero la eliminación no funcionará de inmediato, primero se moverá a la cola que se eliminará al final del marco actual. Esto es mucho más seguro que eliminar un nodo de inmediato, porque otros "participantes" (nodos o escenas) en el juego aún pueden necesitar este nodo para existir.


 func pickup (): queue_free () 

Conclusión


Ahora podemos crear la escena Main , arrastrar ambas escenas: Player y Coin mouse al editor 2D, y comprobar cómo funciona el movimiento del jugador y su contacto con la moneda al comenzar la escena (F5). Bueno, tengo prisa por decir que la primera parte de la creación del juego "Like Coins" está terminada, déjenme despedirme y agradecer a todos por su atención. Si tiene algo que decir, complemente el material o si vio errores en el artículo, asegúrese de informarlo escribiendo un comentario a continuación. No tengas miedo de ser duro y crítico. Sus "comentarios" le dirán si me estoy moviendo en la dirección correcta y qué se puede arreglar para que el material sea aún más interesante y útil.

Source: https://habr.com/ru/post/es429234/


All Articles