Clases Godot
Clases Godot
3
1. Fundamentos: Clases y Objetos en Godot........................................................................3
1.1. Clases en Godot......................................................................................................3
1.2. Objetos en Godot...................................................................................................3
1.3. Tipos de objetos y su jerarquía...............................................................................3
1.4. Usar Escenas como Clases......................................................................................4
1.5. Organización en Escenas y Nodos...........................................................................4
1.6. Ejemplo Práctico: Nave Espacial (Ship)...................................................................4
1.7. Principios de la POO en el Proyecto de Naves Espaciales.......................................4
1.8. Herencia en Godot..................................................................................................5
1.9. Creación de la Clase Base (Nave.gd).......................................................................5
1.10. Creación de las Clases Derivadas............................................................................5
1.11. Ventajas de la Herencia en Godot..........................................................................6
2. Física Básica, Colisiones y Ciclos de Procesos en Godot...................................................7
2.1. Física Básica............................................................................................................7
2.2. Colisiones................................................................................................................7
2.3. Ciclos de Procesos: _process, _physics_process y _input.......................................8
2.4. Ejemplo Integrado en el Juego de Naves Espaciales...............................................9
3. Herencia y Polimorfismo con Nodos y Escenas en Godot...............................................10
3.1. Polimorfismo en Godot.........................................................................................10
3.2. Uso de Nodos y Escenas con Herencia y Polimorfismo.........................................10
3.3. Ejemplo en la Escena Principal..............................................................................10
3.4. Ventajas del Polimorfismo en el Juego de Naves..................................................11
4. Señales, Singletons y Variables Globales........................................................................12
4.1. Señales en Godot..................................................................................................12
4.2. Singletons.............................................................................................................12
4.3. Eventos (Mediante Señales).................................................................................13
4.4. Variables Globales................................................................................................13
4.5. Registros y Gravaciones en un Singleton..............................................................14
4.5.1. Creando un Singleton para Registros................................................................14
4.5.2. Grabaciones en Archivos..................................................................................15
5. Introducción a la Modularidad.......................................................................................16
5.1. Uso de Funciones para Reutilización de Código....................................................16
5.2. Encapsulamiento para Controlar el Acceso a los Datos........................................16
5.3. Código Limpio: Nombres Descriptivos y Comentarios..........................................16
5.4. Separación de Lógica en Clases Especializadas.....................................................17
5.5. Ejercicio Final: Aplicación de los Principios en el Código Completo de la Nave....17
6. Interfaz de Usuario: Registro de Puntuación y Configuraciones en el Juego de Naves
Espaciales...............................................................................................................................18
6.1. Tipos de Nodos Control........................................................................................18
6.2. Diferencias con Otros Nodos................................................................................18
6.3. Configuración Básica de Música y Efectos............................................................19
6.4. Menú Principal y Reinicio del Juego......................................................................19
6.5. Registro de Puntuación y Guardado de Variables.................................................19
6.6. Configuración Básica de Sonido (Música, Efectos, y Mute)...................................20
6.7. Menú Principal y Reinicio del Juego......................................................................21
7. Integración Final y Exportación del Juego de Naves Espaciales......................................23
7.1. Integración Final del Proyecto..............................................................................23
7.2. Exportación del Juego...........................................................................................24
7.3. Empaquetado y Publicación del Juego..................................................................24
Clase 1
1. Fundamentos: Clases y Objetos en Godot
En Godot, los conceptos de clases y objetos están representados de una forma única y
visual a través de nodos y escenas. Este enfoque permite a los desarrolladores
visualizar la estructura y organización del código mientras utilizan las ventajas de la
Programación Orientada a Objetos (POO). Explicaremos estos conceptos
fundamentales y cómo se aplican en Godot.
gdscript
o Creación de Instancias: En el juego, una clase no es útil por sí sola hasta que se
crea una instancia de ella, es decir, un objeto. Cada objeto creado a partir de
Ship.gd tendrá sus propios valores para velocidad, posición, etc., lo que
le permite funcionar de manera independiente en el juego.
Nodos 2D
o Sprite
o Area2D
o
o Crea un script Ship.gd para la nave del jugador, con propiedades como
velocidad y vida, y métodos como mover y disparar.
o Este script define la clase Ship que podemos usar en el juego.
gdscript
extends Node2D
Define un script para la clase base Nave con las propiedades y métodos
comunes:
gdscript
# Nave.gd
extends Node2D
func morir():
queue_free() # Elimina el nodo de la escena
# NaveJugador.gd
extends "res://Nave.gd"
func disparar():
# Código para instanciar y disparar proyectiles
var proyectil = Projectile.instance()
proyectil.position = position
get_parent().add_child(proyectil)
# NaveEnemiga.gd
extends "res://Nave.gd"
func mover_automatico():
# Código para definir un patrón de movimiento
específico para enemigos
position += Vector2(-1, 0) * velocidad * delta
Este enfoque ayuda a introducir a los estudiantes en el uso de POO, tanto desde el
punto de vista teórico como práctico, permitiéndoles visualizar el poder de las clases y
objetos a medida que avanzan en la construcción de su juego de naves espaciales en
Godot.
2. Física Básica, Colisiones y Ciclos de Procesos en
Godot
Este apartado cubre los fundamentos de física y detección de colisiones en Godot,
junto con el uso de los métodos especiales _process, _physics_process e _input para
controlar el flujo y la interacción del juego. Estos conceptos son esenciales para
gestionar el movimiento, la interacción entre objetos y las respuestas a la entrada del
jugador en el juego.
2.2. Colisiones
Las colisiones son una parte fundamental de la interacción entre objetos en Godot.
Para gestionar colisiones, necesitamos:
extends KinematicBody2D
if collision_info:
print("¡Colisión detectada!")
En este ejemplo, cada vez que el cuerpo colisiona con otro, se imprime un mensaje.
Este mecanismo es útil para la detección de colisiones en el juego de naves espaciales,
por ejemplo, al detectar cuando la nave colisiona con un asteroide.
_process(delta):
_physics_process(delta):
_input(event):
func _input(event):
if event.is_action_pressed("ui_right"):
position.x += 10
if event.is_action_pressed("ui_left"):
position.x -= 10
extends KinematicBody2D
func _physics_process(delta):
velocity = Vector2.ZERO
# Control de movimiento
if Input.is_action_pressed("move_right"):
velocity.x += 1
if Input.is_action_pressed("move_left"):
velocity.x -= 1
if Input.is_action_pressed("move_up"):
velocity.y -= 1
if Input.is_action_pressed("move_down"):
velocity.y += 1
if collision_info:
print("¡Colisión detectada!")
# Puedes agregar lógica de daño o respuesta a
la colisión
Este script permite que la nave responda a las teclas de dirección (arriba, abajo,
izquierda y derecha) y se detiene o reacciona al chocar con otro objeto en el juego.
3. Herencia y Polimorfismo con Nodos y Escenas en
Godot
La herencia y el polimorfismo son principios avanzados de la Programación Orientada
a Objetos (POO) que permiten crear estructuras de código reutilizables y flexibles. En
Godot, estos principios son especialmente útiles cuando se trabaja con nodos y
escenas, ya que permiten estructurar comportamientos comunes y específicos para
diferentes entidades dentro del juego. Aquí te explico cómo aplicar estos conceptos en
Godot y en nuestro proyecto de naves espaciales.
organizado.
# Ejemplo de polimorfismo
var naves = [NaveJugador.new(), NaveEnemiga.new()]
o Crea una escena Nave.tscn como plantilla base para las naves y
configúrala con nodos comunes, como una animación, un
CollisionShape2D y un sprite.
o Para NaveJugador.tscn y NaveEnemiga.tscn, hereda de
Nave.tscn y ajusta los valores específicos en cada escena.
# Escena principal
extends Node2D
func _ready():
# Instancia las naves y agrega a la lista
var nave_jugador =
load("res://NaveJugador.tscn").instance()
add_child(nave_jugador)
naves.append(nave_jugador)
var nave_enemiga =
load("res://NaveEnemiga.tscn").instance()
add_child(nave_enemiga)
naves.append(nave_enemiga)
func _process(delta):
for nave in naves:
nave.mover(Vector2(1, 0)) # Llama al método de
mover de cada clase específica
3.4. Ventajas del Polimorfismo en el Juego de Naves
Interacción Flexible entre Objetos: Puedes crear listas o grupos de objetos de
clase base Nave y hacer que cada uno responda según su implementación.
Código Limpio y Escalable: Puedes agregar nuevos tipos de naves o
variaciones sin modificar el código de la escena principal.
signal disparo_realizado
signal enemigo_destruido()
o Emitir la señal: Llama a la señal cuando ocurra el evento relevante,
como al disparar o destruir un enemigo:
gdscript
func disparar():
# Código para disparar un proyectil
emit_signal("disparo_realizado")
func destruir_enemigo():
# Código para destruir un enemigo
emit_signal("enemigo_destruido")
ship.connect("enemigo_destruido", self,
"_actualizar_puntaje")
func _actualizar_puntaje():
puntaje += 10
4.2. Singletons
Concepto: Los singletons, también conocidos como Autoloads en Godot, son
scripts que se cargan al iniciar el juego y están disponibles globalmente. Esto
permite almacenar variables y métodos accesibles desde cualquier lugar del
proyecto.
Ejemplo en el Juego: Crear un singleton GameManager que almacene la
puntuación del jugador, el estado de vida y otra información general del juego.
Cómo Usarlos:
o Crear el Singleton: Crea un script llamado GameManager.gd y define
las variables globales, como puntuacion y vida.
gdscript
# GameManager.gd
var puntuacion = 0
var vida = 3
func reiniciar_juego():
puntuacion = 0
vida = 3
gdscript
GameManager.puntuacion += 10
GameManager.reiniciar_juego()
signal vida_perdida
func _on_colision_con_enemigo():
GameManager.vida -= 1
emit_signal("vida_perdida")
gdscript
var nivel_actual = 1
var puntaje_total = 0
if GameManager.vidas <= 0:
cambiar_a_escena_game_over()
Los singletons (también conocidos como nodos globales) son nodos que se instancian
una sola vez y permanecen en la memoria durante toda la ejecución del juego. Se
utilizan comúnmente para gestionar datos globales, como configuraciones,
puntuaciones y estados del juego.
extends Node
var player_scores = []
var settings = {
"music_volume": 1.0,
"sfx_volume": 1.0,
"is_muted": false,
}
Configuración del Singleton:
func save_scores():
var file = File.new()
if file.open("user://scores.save", File.WRITE) == OK:
for score in player_scores:
file.store_line(str(score))
file.close()
4.5.2. Grabaciones en Archivos
Para guardar y cargar registros de puntuaciones, puedes utilizar archivos. En el
ejemplo anterior, se guarda la lista de puntuaciones en un archivo en el sistema del
usuario. Para cargar las puntuaciones al iniciar el juego, puedes hacer lo siguiente:
gdscript
Copiar código
func load_scores():
var file = File.new()
if file.open("user://scores.save", File.READ) ==
OK:
player_scores.clear()
while not file.eof_reached():
player_scores.append(int(file.get_line()))
file.close()
5. Introducción a la Modularidad
Objetivo: Explicar qué es la modularidad y por qué es crucial en desarrollo de
software.
Concepto: La modularidad implica dividir el código en partes pequeñas e
independientes (módulos) que realizan tareas específicas.
Ejemplo en el Juego: Crear una clase Ship que actúe como el "módulo base"
para las naves. Esta clase incluirá solo la lógica fundamental que comparten
todas las naves, como moverse, disparar, y recibir_daño.
Actividad: Implementar una clase Ship.gd con un método mover() que
permita cambiar la posición de la nave de acuerdo a una velocidad
predeterminada.
Las máquinas de estado son una herramienta poderosa en desarrollo de videojuegos, ya que
permiten organizar y gestionar el comportamiento de personajes, enemigos o cualquier
entidad que tenga múltiples "estados" posibles (por ejemplo, caminar, correr, atacar,
defender, etc.). En Godot, podemos implementar una máquina de estado utilizando scripts,
señales y nodos, y este enfoque modular facilita mantener el código organizado y limpio,
especialmente en proyectos complejos.
Una máquina de estado es una estructura de programación que permite a un objeto, como un
personaje o enemigo, alternar entre diferentes "estados" de comportamiento. Cada estado
tiene sus propias reglas y acciones, y la entidad puede cambiar de un estado a otro en función
de condiciones específicas o de la entrada del jugador.
gdscript
Copiar código
enum States {
IDLE,
PATROLLING,
CHASING,
ATTACKING,
FLEEING
gdscript
Copiar código
o Crea una función que cambie de un estado a otro. Esta función actualizará la
lógica del personaje para que responda según el estado.
gdscript
Copiar código
func change_state(new_state):
current_state = new_state
match current_state:
States.IDLE:
enter_idle()
States.PATROLLING:
enter_patrolling()
States.CHASING:
enter_chasing()
States.ATTACKING:
enter_attacking()
States.FLEEING:
enter_fleeing()
o Para cada estado, crea una función que defina las acciones específicas que el
personaje debe realizar. Por ejemplo:
gdscript
Copiar código
func enter_idle():
# Lógica de inactividad
func enter_patrolling():
print("Enemigo patrullando")
# Lógica de patrullaje
func enter_chasing():
print("Enemigo persiguiendo")
# Lógica de persecución
func enter_attacking():
print("Enemigo atacando")
# Lógica de ataque
func enter_fleeing():
print("Enemigo huyendo")
# Lógica de huida
gdscript
Copiar código
func _process(delta):
match current_state:
States.IDLE:
check_for_player()
States.PATROLLING:
patrol()
check_for_player()
States.CHASING:
chase_player()
if is_close_to_player():
change_state(States.ATTACKING)
States.ATTACKING:
attack_player()
if player_is_out_of_range():
change_state(States.CHASING)
States.FLEEING:
flee()
if is_safe():
change_state(States.IDLE)
Las transiciones se pueden condicionar según la situación del juego, como la distancia al
jugador o el nivel de salud. Cada transición debería ser lógica y predecible para evitar que el
personaje entre en un estado inesperado.
Para hacer que las transiciones sean más limpias y seguras, puedes utilizar una estructura
como un diagrama de estados antes de implementarla en código. Esto ayuda a definir todas
las reglas de cambio de un estado a otro.
Las señales son útiles para notificar cambios de estado o condiciones específicas. Por ejemplo,
podrías emitir una señal cuando el personaje ve al jugador o cuando el jugador se aleja.
gdscript
Copiar código
signal player_spotted
func check_for_player():
if is_player_in_range():
emit_signal("player_spotted")
change_state(States.CHASING)
En el nodo principal, conecta esta señal para que otros objetos puedan reaccionar al cambio
de estado si es necesario.
Conclusión
Control: Este es el nodo base para todos los nodos de control. No se renderiza,
pero proporciona funcionalidades comunes, como el manejo de entrada y la
disposición de otros nodos.
Button: Un botón interactivo que puede ser presionado por el usuario. Se
utiliza comúnmente para acciones como iniciar el juego o confirmar
selecciones.
Label: Un nodo que muestra texto en la interfaz. Ideal para mostrar
información al jugador, como puntuaciones o mensajes.
LineEdit: Un campo de entrada de texto donde el usuario puede escribir
información, como nombres de usuario o configuraciones.
TextureRect: Muestra una textura en la interfaz. Se utiliza para mostrar
imágenes, fondos o iconos.
ProgressBar: Representa visualmente el progreso de una acción, como la carga
de un nivel o la salud del jugador.
Panel: Un contenedor que puede tener un fondo y organizar otros nodos de
control dentro de él.
func mute():
settings["is_muted"] = true
# Silencia la música y efectos
func unmute():
settings["is_muted"] = false
# Restaura el volumen anterior
func restart_game():
get_tree().reload_current_scene() # Recarga la
escena actual
Global.load_scores() # Carga las puntuaciones
Creación del Registro de Puntuación: Crea una función para guardar y cargar
la puntuación en un archivo .save que registre el puntaje máximo (high
score).
gdscript
var puntuacion_maxima = 0
func guardar_puntuacion(puntuacion):
if puntuacion > puntuacion_maxima:
puntuacion_maxima = puntuacion
var file =
FileAccess.open("user://record.save", FileAccess.WRITE)
file.store_line(str(puntuacion_maxima))
file.close()
func cargar_puntuacion():
var file = FileAccess.open("user://record.save",
FileAccess.READ)
if file:
puntuacion_maxima = int(file.get_line())
file.close()
Nodos de Audio:
func cambiar_estado_musica():
musica_jugando = !musica_jugando
musica.volume_db = -80 if !musica_jugando else 0 #
-80dB para mute, 0 para volumen normal
func cambiar_estado_efectos():
efectos_jugando = !efectos_jugando
efectos.volume_db = -80 if !efectos_jugando else 0
Botones de Configuración:
Menú Principal:
# Menú Principal
func iniciar_juego():
# Código para iniciar el juego, como cargar la
escena de juego principal
get_tree().change_scene("res://NivelPrincipal.tscn")
func ir_a_configuracion():
# Cambiar a una escena de configuración o mostrar
un menú de configuración
pass
func salir_del_juego():
get_tree().quit()
# Menú de reinicio
func reiniciar_juego():
# Reinicia la partida actual
get_tree().reload_current_scene()
func regresar_menu_principal():
# Regresa al menú principal
get_tree().change_scene("res://MenuPrincipal.tscn")
7. Integración Final y Exportación del Juego de
Naves Espaciales
Este último módulo cubre la integración de todas las piezas del juego en un proyecto
cohesivo y profesional en Godot, seguido por el proceso de exportación para
diferentes plataformas. Aquí se desarrollan pasos para revisar el proyecto, optimizarlo
y finalmente configurarlo para su distribución, ya sea en escritorio, móvil o web.
Optimización de Recursos:
Distribución y Publicación: