-
Notifications
You must be signed in to change notification settings - Fork 0
4. Mecánicas de Elementos
Hektor edited this page Jan 16, 2024
·
30 revisions
- Creación de la jerarquía de nodos y descripción de para qué usaremos cada parte

- Desactivamos la gravedad en el rigidbody

- Configuramos el Sprite, Carga Rápida -> Seleccionamos el Tileset, descentramos y recortamos región

- Configuramos la máscara de colisión

- Incrementamos el z-index de visibilidad del personaje

- Centramos el Raycast al centro

Implementación de la lógica y la funcionalidad.
- Si el jugador se mueve sobre una caja recuperaremos su dirección y ejecutaremos una función de la caja para moverla en esa misma dirección. Eso solo ocurrirá si el raycast de la caja no detecta ninguna colisión. Así que crearemos un script
Box.gdcon la función
extends StaticBody2D
@onready var _raycast = $RayCast2D
# Función para mover la caja
func move(dir : Vector2) -> void:
position += dir * Globals.TILE_SIZE
# Función que se llamará desde el jugador para empujar la caja
func push(dir: Vector2) -> bool:
# Si hay una colisión en la dirección del empuje, devolvemos falso
if check_collision(dir):
return false
# Si no hay colisión, movemos la caja en la dirección y retornamos true
move(dir)
return true
func check_collision(dir : Vector2) -> bool:
_raycast.set_target_position(dir * Globals.TILE_SIZE)
_raycast.force_raycast_update() # Forzamos la nueva dirección
return _raycast.is_colliding()- Para saber si chocamos contra una caja la añadiremos a un grupo de colisiones. Esto se puede hacer en el editor pero es mejor hacerlo en el código en la función
_enter_treedeBox.gd. Esta función tiene prioridad sobre los demás eventos
""" Box.gd """
func _enter_tree() -> void: # se ejecuta antes que _ready
add_to_group("boxes")- Si el
Playerrecibe una colisión, comprobaremos si es una caja y la empujaremos
""" Player.gd """
func _physics_process(_delta) -> void:
for action in movements:
if Input.is_action_just_pressed(action):
var dir = movements[action]["dir"]
# Si no ocurre una colisión movemos al personaje
if not check_collision(dir):
move(dir)
else:
# Si ocurre una colisión recuperamos el objeto de la colisión
var collider = _raycast.get_collider()
# Si es una caja y tiene el método "push" lo llamamos
if collider.is_in_group("boxes") and collider.has_method("push"):
# Si el método push devuelve true, luego movemos al personaje
if collider.push(dir):
move(dir)
- Guardamos el nodo como una escena
Box.tscnpara luego trabajar con ella

Creación de la jerarquía de nodos y descripción de para qué usaremos cada parte.
- Creamos la jerarquía de un nuevo Nodo hijo llamado
Targetde tipoArea2D

- Configuramos el sprite y desactivamos el centrado

- Configuramos la colisión, haremos un cuadro menor de 64x64, por ejemplo 5x5. Si hacemos la máscara 64x64, al tocar un extremo ya detectaría la colisión y no queremos eso, queremos detectarla cuando la caja esté completamente encima. No importa si el tamaño es 1x1 o 60x60, siempre que los extremos no tengan colisión funcionará.

- Desactivamos la colisión en la capa 1 pero conservamos la máscara. Esto permitirá que los demás no choquen contra el objetivo pero podamos detectar colisiones contra él igualmente.

- Si comprobamos las colisiones en el debug deberia verse algo así

- Cambiaremos la profundidad z-index del objetivo a 1 para que aparezca siempre por encima de la caja que es 0

Implementación de la lógica y la funcionalidad.
- Para detectar si una caja entra o sale del objetivo podemos crear unas señal
body_enteredybody_exited, ya que las cajas son de tipoRigidBodydeberia detectarlas (si fueran staticbody no las detectaria). Primero añadimos un scriptTarget.gdy dentro creamos la señal:


El código quedará asi
""" Target.gd """
extends Area2D
func _on_body_entered(body: Node2D) -> void:
print("ha entrado un objeto")
func _on_body_exited(body: Node2D) -> void:
print("ha salido un objeto")
- Para controlar si un objetivo está completo usaremos una variable booleana
completed. Además como tendremos más de uno los tendremos contados en el grupotargetsasi que los añadiremos ahí automáticamente al crearlos y de paso comprobaremos si el objeto que colisiona es una caja, aunque no es realmente necesario puede ser una buena práctica en caso de que extendiésemos el juego para permitir otro tipo de objetos interactivos
""" Target.gd """
extends Area2D
# Controlaremos si el objetivo se ha realizado o no
var completed : bool = false
# Añadimos los targets a un grupo para llevar un recuento
func _enter_tree() -> void:
add_to_group("targets")
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("boxes"):
completed = true
func _on_body_exited(body: Node2D) -> void:
if body.is_in_group("boxes"):
completed = false- Guardamos el nodo como una nueva escena
Target

- Podemos duplicar
Control+Dcajas y objetivos para hacer pruebas. Si todo funciona bien, como las cajas son cuerpos fisicas como las paredes, también deberian colisionar entre ellas
