Tema 17. Godot Engine. Checkpoints
Recordemos hasta ahora, si el jugador cae en un agujero, la escena se reinicia. Pero siempre se reinicia desde el principio. ¿Qué ocurre si deseamos que el jugador no empiece otra vez la escena, sino que se restablezca su posición a partir de donde se ha quedado?
Para poder dar una solución a este problema, también emplearemos áreas2D
Para ello creamos una nueva Área2D con su CollisionShape2D. La llamaremos CheckArea2D0
Pero ahora guardaremos dicha área como si fuera una escena. Nos ponemos encima del Nodo CheckArea2D0 y guardamos como Guardar Rama como Escena, lo cual nos permite guardar dicho Nodo como si de una escena se tratara.
Si nos fijamos en los recursos, veremos que el Nodo se ha guardado como una Escena (CheckArea2D0.tscn)
Si nos fijamos, el CheckArea2D es tratado como una escena. Vemos el icono escena.
El área CheckArea2D la situamos delante del Player.
Ahora conectamos el CheckArea2D con el Player, igual que lo hicimos con las áreas anteriores.
func _on_CheckArea2D0_body_entered(body): pass # Replace with function body. |
Y procedemos a duplicar el área. Pero esta vez es importante que conectemos de forma manual la nueva área o áreas que dupliquemos con la misma área inicial:
Es decir:
- Duplicamos el área CheckArea2D0
- Conectamos el CheckÁrea2D0 con el Player.
- Duplicamos el CheckArea2D y obtendremos CheckArea2D1
- OJO: Conectamos el CheckArea2D1 con el CheckArea2D0:
Importante:
Al duplicar nos aparecerá el área _on_CheckArea2D1_body_entered… nosotros la renombraremos por _on_CheckArea2D0_body_entered:
y le damos al botón Conectar. Ahora ya tenemos conectado el CheckArea2D1 con la misma función que CheckArea2D0.
Lo que hemos hecho es que ambas áreas usen la misma función:
func _on_CheckArea2D0_body_entered(body): pass # Replace with function body. |
Ahora vamos a definir una nueva CheckArea2D y haremos los mismos pasos:
PUNTO DE GUARDADO |
Lo que haremos ahora será programar un punto de guardado. Haremos un CheckPoint cada vez que el jugador esté en cualquiera de esas áreas.
En Godot podemos obtener la posición global de un objeto accediendo al body desde la función
func _on_CheckArea2D0_body_entered(body):
pass # Replace with function body.
usando body.global_position
es decir:
func _on_CheckArea2D0_body_entered(body): print(body.global_position) |
Cada vez que el Player toque un CheckArea2D, obtendremos su posición en la pantalla:
Para asegurarnos que es el Player el que toca los CheckAreas, añadimos la condición
func _on_CheckArea2D0_body_entered(body): if body == self: print(body.global_position) |
Ahora ya conocemos la posición del jugador cuando toca un área. Entonces necesitaremos guardar esta información cuando el jugador caiga.
Por lo tanto tenemos que guardar dicha información independientemente de las veces que la escena se reinicie.
Por lo tanto vamos al área de recursos y creamos un Script. Antes crearemos una carpeta donde almacenaremos todos los scripts.
Creamos una carpeta Scripts en el área de recursos:
Y dentro creamos un nuevo Script con el nombre: DataManager
Nota: si tenemos otros Scripts los podemos arrastrar todos dentro de dicha carpeta para tenerlo todos mejor organizados.
En el Script hacemos los siguiente:
Creamos una variable para guardar la posición del personaje:
Ahora en Configuración del Proyecto tenemos que definir el Script como AutoLoad
Y hay que darle la ubicación del Script desde la carpeta Ruta. Seleccionamos el Script DataManager.gd
y botón Añadir (no olvidarse)
Una vez hecho esto podemos usar el AutoLoad desde cualquier Script:
Para hacer esto solo es necesario llamarlo por su nombre desde cualquier Script:
func _on_CheckArea2D0_body_entered(body): if body == self: DataManager.init_position = body.global_position |
Mediante este código, guardamos la posición del Player según el CheckArea que haya tocado. Y se guarda en la variable del Script AutoLoad que hemos definido.
Para recuperar la posición guardada la mejor forma de hacerlo es en la función func _ready():
que se ejecuta cada vez antes de que se inicie una escena.
Por lo tanto ahora recuperamos la última posición del Player (que es la última CheckArea2D que ha tocado) de tal forma que cuando caiga y vuelva a reiniciarse la escena, lo hará en la posición devuelta en la función ready:
func _ready(): global_position = DataManager.init_position |
La principal función de los AutoLoads es la de compartir información entre las escenas.
Nuestro código quedará así:
extends KinematicBody2D # Declare member variables here. Examples: # var a = 2 # var b = «text» export var Velocidad = 200 var velo = Vector2() # Called when the node enters the scene tree for the first time. func _ready(): global_position = DataManager.init_position # Called every frame. ‘delta’ is the elapsed time since the previous frame. func _process(delta): velo.y += Velocidad * delta if Input.is_action_pressed(«Jump») and is_on_floor(): velo.y = -Velocidad if Input.is_action_pressed(«Player_Left»): $AnimationPlayer.play(«Left») velo.x = -Velocidad if Input.is_action_pressed(«Player_Right»): $AnimationPlayer.play(«Right») velo.x = Velocidad if !Input.is_action_pressed(«Player_Left») and !Input.is_action_pressed(«Player_Right»): $AnimationPlayer.play(«Idle») velo.x = 0 if !is_on_floor(): $AnimationPlayer.play(«Animacion_JUMP») #Personaje saltando move_and_slide(velo,Vector2(0,-1)) func _on_Area2D_body_entered(body): if body == self: get_tree().reload_current_scene() func _on_CheckArea2D0_body_entered(body): if body == self: DataManager.init_position = body.global_position |
PUNTO DE INICIO EN EL JUEGO |
Si nos fijamos cuando el Jugador inicia la escena después de caer, este cae desde arriba debido a que las coordenadas iniciales son la 0,0
Podemos solucionar esto modificando el Script AutoLoad DataManager
así:
Ajustamos por defecto las coordenadas de inicio del personaje en el juego cada vez que entre en escena:
extends Node var init_position = Vector2(-75,200) |
Ahora podemos mejorar los tamaños de cada CheckPoint e insertar Tiles encima para indicar al jugador mediante gráficos si creemos oportuno. Por ejemplo un reloj o cualquier objeto que indique que continua a partir de ahí.