tutoriales.com

Creando un Sistema de Combate Hack and Slash en Godot 4: Combos y Golpes

En este tutorial completo aprenderás paso a paso cómo programar un sistema de combate tipo Hack and Slash en Godot 4. Implementaremos combos de ataques, detección de golpes por áreas, gestión de estados de animación y retroalimentación visual para tus enemigos.

Intermedio12 min de lectura6 views
Reportar error

Introducción al Sistema de Combate Hack and Slash

El género Hack and Slash se define por su acción vertiginosa, fluidez de movimientos y sistemas de combate cuerpo a cuerpo basados en cadenas de golpes (combos). En Godot 4, estructurar un sistema de combate robusto requiere una combinación limpia de máquinas de estados, áreas de colisión dinámicas (Area2D o Area3D) y una gestión precisa de las animaciones mediante AnimationPlayer.

A lo largo de este tutorial, construiremos desde cero la lógica necesaria para que tu personaje pueda realizar un combo de tres golpes, detectar impactos en enemigos cercanos, aplicar daño en tiempo real y mostrar efectos visuales impactantes.

📌 Nota: Este tutorial está diseñado para proyectos en 2D, pero los conceptos lógicos de áreas de impacto, estados y colisiones aplican exactamente igual para entornos 3D en Godot 4.

🛠️ Requisitos Previos y Configuración del Proyecto

Antes de escribir código, asegúrate de tener instalado Godot 4.x (se recomienda la versión 4.2 o superior). Necesitaremos la siguiente estructura básica en tu escena de personaje:

  • Un nodo raíz CharacterBody2D para el jugador.
  • Un nodo Sprite2D o AnimatedSprite2D para los gráficos.
  • Un nodo AnimationPlayer para gestionar las animaciones de movimiento y ataque.
  • Un nodo Area2D hijo del jugador llamado Hitbox que contendrá un CollisionShape2D.
CharacterBody2D Sprite2D AnimationPlayer Hitbox (Area2D) CollisionShape2D

⚔️ Paso 1: Configurando las Áreas de Daño (Hitboxes y Hurtboxes)

El pilar fundamental de cualquier juego de acción es la separación entre el área que inflige daño (Hitbox) y el área que lo recibe (Hurtbox).

  1. Selecciona tu nodo Hitbox (Area2D) y asegúrate de configurar sus capas de colisión (Collision Layers y Collision Masks) para que solo detecte a los enemigos.
  2. Posiciona el CollisionShape2D del Hitbox de manera que coincida con el arma o los puños del personaje durante los fotogramas clave de ataque.
  3. Desactiva la propiedad monitoring y monitorable por defecto en el inspector, o mantén el área desactivada mediante código hasta que el frame de ataque lo requiera.

📜 Paso 2: Programando la Cadena de Combos

Para lograr un sistema de combos responsivo, debemos rastrear el índice del ataque actual (combo_step) y verificar si el jugador presiona el botón de ataque antes de que termine la animación actual.

Crea un script llamado PlayerCombat.gd y añade el siguiente código:

extends CharacterBody2D

@export var speed: float = 300.0
@onready var animation_player: AnimationPlayer = $AnimationPlayer
@onready var hitbox_shape: CollisionShape2D = $Hitbox/CollisionShape2D

var is_attacking: bool = false
var combo_step: int = 1
var can_combo: bool = false

func _ready() -> void:
	hitbox_shape.disabled = true

func _physics_process(delta: float) -> void:
	read_input(delta)

func read_input(_delta: float) -> void:
	if Input.is_action_just_pressed("attack"): 
		if not is_attacking:
			start_attack()
		鈁elive_combo()

func start_attack() -> void:
	is_attacking = true
	combo_step = 1
	play_current_combo_animation()

func try_buffered_combo() -> void:
	if can_combo:
		combo_step += 1
		if combo_step > 3:
			combo_step = 1
		play_current_combo_animation()
		can_combo = false

func play_current_combo_animation() -> void:
	match combo_step:
		1:
			animation_player.play("attack_1")
		2:
			animation_player.play("attack_2")
		3:
			animation_player.play("attack_3")

func _on_animation_finished(anim_name: String) -> void:
	if anim_name.begins_with("attack"):
		is_attacking = false
		combo_step = 1
		can_combo = false
		hitbox_shape.disabled = true
💡 Consejo: Utiliza el sistema de Animation callbacks de Godot para activar funciones directamente desde la línea de tiempo de la animación, asegurando que el hitbox solo esté activo en el momento exacto del golpe.

🛡️ Paso 3: Sincronizando los Frames de Impacto

Para que el combate se sienta preciso, el hitbox del jugador debe activarse únicamente durante los frames activos de la animación de ataque. Podemos lograr esto añadiendo llamadas a métodos en el AnimationPlayer.

Crea dos funciones auxiliares en tu script para ser llamadas desde la animación:

func enable_hitbox() -> void:
	hitbox_shape.disabled = false

func disable_hitbox() -> void:
	hitbox_shape.disabled = true

func allow_combo_window() -> void:
	can_combo = true
Línea de Tiempo de Animación PREPARACIÓN Start-up Hitbox: Desactivado IMPACTO ACTIVO Active Frames HITBOX ACTIVADO VENTANA DE COMBO ABIERTA RECUPERACIÓN Recovery Hitbox: Desactivado Progreso de la Animación (Tiempo/Frames)

🎯 Paso 4: Implementando la Hurtbox en los Enemigos

Los enemigos deben contar con una zona receptora de daño conectada a una barra de vida o script de estadísticas. Veamos cómo procesar la señal cuando el Hitbox del jugador colisiona con el Hurtbox del enemigo.

Crea un script para el enemigo Enemy.gd:

extends CharacterBody2D

@export var max_health: int = 100
@onready var current_health: int = max_health

func take_damage(amount: int) -> void:
	current_health -= amount
	print("Enemigo recibió daño. Vida restante: ", current_health)
	
	# Efecto visual de retroceso o destello
	modulate = Color.RED
	await get_tree().create_timer(0.1).timeout
	modulate = Color.WHITE
	
	if current_health <= 0:
		die()

func die() -> void:
	queue_free()

Y conecta la señal area_entered de tu Hitbox:

# Dentro de PlayerCombat.gd

func _on_hitbox_area_entered(area: Area2D) -> void:
	if area.has_method("take_damage"):
		var damage_to_deal = 15 * combo_step
		area.take_damage(damage_to_deal)

📊 Comparativa de Tipos de Ataques en Combates 2D

Tipo de AtaqueVelocidadDaño BaseVentana de ComboAlcance
---------------
Golpe Ligero 1Rápido (0.3s)Bajo (15)AmpliaCorto
Golpe Ligero 2Medio (0.4s)Medio (25)MediaCorto-Medio
---------------
Golpe FinalizadorLento (0.7s)Alto (50)NulaAmplio

✨ Paso 5: Añadiendo Feedback Visual y Sonoro

Un sistema de combate excelente depende en gran medida del gamefeel. Para mejorar la experiencia del usuario, implementaremos pequeños efectos de sacudida de cámara (CameraShake) y partículas de impacto.

func trigger_hit_effects() -> void:
	# Sacudida de cámara simple
	var camera = get_viewport().get_camera_2d()
	if camera:
		camera.offset = Vector2(randf_range(-5, 5), randf_range(-5, 5))
		await get_tree().create_timer(0.05).timeout
		camera.offset = Vector2.ZERO
⚠️ Advertencia: Evita abusar de las sacudidas de cámara intensas, ya que pueden marear al jugador o restar legibilidad a la acción en pantalla.

🔍 Preguntas Frecuentes (FAQ)

¿Cómo evito que el jugador se mueva mientras ataca? Puedes bloquear la velocidad horizontal multiplicando la velocidad por cero o desactivando el procesamiento de movimiento dentro de la función start_attack() hasta que la animación finalice.
¿Cómo añado efectos de partículas al golpear? Instancia una escena precargada de partículas de tipo GPUParticles2D en la posición exacta donde ocurre la intersección entre el Hitbox y la Hurtbox, y libérala automáticamente al terminar su emisión.

🚀 Conclusión

¡Felicidades! Has implementado con éxito la base de un sistema de combate Hack and Slash en Godot 4. Ahora cuentas con una estructura modular que incluye gestión de estados de combo, áreas de impacto sincronizadas y retroalimentación visual para enemigos. A partir de aquí, puedes expandir este sistema añadiendo habilidades especiales, parry (contraataques) o esquivas con marcos de invulnerabilidad (i-frames).

Paso 1: Configuración de nodos y jerarquía.
Paso 2: Creación de la máquina de estados y lógica de combos.
Paso 3: Sincronización de Hitboxes con AnimationPlayer.
Paso 4: Gestión de daño en la Hurtbox del enemigo.
Paso 5: Pulido con efectos visuales y feedback de cámara.

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!