Hit Reactions tipo Euphoria para Godot: código abierto en seis días
Las reacciones físicas de personajes de Euphoria llevan 18 años encerradas tras tecnología propietaria. Pasé seis días construyendo Kickback, un plugin de código abierto para Godot que lleva los mismos principios a los desarrolladores indie.
Todos los desarrolladores de juegos han visto ese momento en GTA IV. Le disparas a un NPC en una escalera y no reproduce una animación de muerte enlatada — tropieza, se agarra a la barandilla, pierde el agarre y cae rodando de una forma que nunca es exactamente igual. Eso es el motor Euphoria de NaturalMotion. Es propietario, lleva sin estar disponible para nadie fuera de un puñado de estudios AAA desde 2006, y no existe alternativa de código abierto.
Pasé seis días construyendo una para Godot. El resultado es Kickback — un plugin con licencia MIT que lleva reacciones físicas a impactos a cualquier personaje humanoide.
Qué hace realmente Euphoria
La mayoría de juegos manejan los impactos de dos formas: reproducir una animación enlatada (“hit_front”), o activar ragdoll completo al morir. Ninguna produce las reacciones emergentes que ves en GTA o Red Dead Redemption.
La clave de Euphoria es que los personajes son agentes activos intentando sobrevivir. No solo caen — se apoyan contra paredes, mueven los brazos para equilibrarse, dan pasos correctivos para evitar caer. Cada hueso del cuerpo está simulado por físicas, pero una capa de inteligencia lucha por mantener al personaje en pie.
El resultado es que cada impacto es único. Un personaje corriendo cae hacia adelante. Uno de pie se tambalea lateralmente. Disparos repetidos desgastan visiblemente al objetivo. La misma arma, el mismo blanco, el mismo ángulo — resultado diferente cada vez.
Ese es el listón. Kickback no lo alcanza del todo, pero implementa muchos de los mismos principios subyacentes.
El enfoque basado en springs
Kickback crea un rig de físicas invisible con 16 cuerpos RigidBody3D conectados por 15 joints, reflejando el esqueleto de animación del personaje. Cada frame de físicas, springs basados en velocidad tiran de cada cuerpo físico hacia la pose de animación. Cuando los springs están a máxima fuerza, el personaje sigue perfectamente su animación. Cuando un impacto reduce la fuerza de los springs, las físicas ganan y el cuerpo reacciona.
El núcleo es sorprendentemente compacto:
# For each of the 16 bones, every physics frame:
var target_rotation = get_animation_bone_pose(bone_index)
var current_rotation = physics_body.global_transform.basis
var rotation_error = (target_rotation * current_rotation.inverse()).get_euler()
var target_angular_velocity = rotation_error / delta
var blend = strength # 1.0 = animation, 0.0 = ragdoll
physics_body.angular_velocity = physics_body.angular_velocity.lerp(target_angular_velocity, blend)
Cuando una bala impacta, strength baja de 1.0 hacia cero en la región afectada. El cuerpo del personaje reacciona a la fuerza del impacto mientras los springs en áreas no afectadas mantienen el resto del cuerpo siguiendo la animación. Con el tiempo, la fuerza se recupera y la animación retoma el control.
Cinco perfiles de impacto vienen con el plugin — bala, escopeta, explosión, melee, flecha — cada uno produciendo una reacción distinta:
¿Por qué no PhysicalBone3D?
Godot tiene un nodo PhysicalBone3D integrado. Parece la opción obvia para un sistema de ragdoll. El problema: le faltan métodos críticos.
| Funcionalidad | PhysicalBone3D | Rig dual de RigidBody3D |
|---|---|---|
apply_force() | No | Sí |
apply_torque() | No | Sí |
| Señales de colisión | No | Sí |
center_of_mass | No | Sí |
contact_monitor | No | Sí |
Sin apply_force(), no puedes construir un sistema de springs que aplique fuerzas correctivas continuas. Sin señales de colisión, no puedes detectar impactos. Sin center_of_mass, no puedes rastrear el equilibrio.
Así que Kickback construye su propio rig: 16 cuerpos RigidBody3D con masas distribuidas anatómicamente (caderas a 15kg, cabeza a 5kg, manos a 1kg cada una), conectados por joints Generic6DOFJoint3D con límites angulares anatómicos. Cada frame de físicas, los transforms de estos cuerpos invisibles se escriben de vuelta al esqueleto visible como bone pose overrides.
Más infraestructura, pero desbloquea todo lo que el sistema necesita.
Las partes contraintuitivas
Tres cosas me sorprendieron durante el desarrollo:
La animación nunca se detiene. Incluso cuando un personaje está completamente ragdolleado en el suelo, su animación sigue reproduciéndose. Parece incorrecto — ¿para qué animar un cuerpo inerte? Pero el spring resolver necesita poses objetivo. Sin la animación proporcionando “aquí es donde está lo normal”, los springs no tienen hacia dónde tirar y la recuperación se vuelve imposible.
Los timers se ven falsos. El stagger inicial usaba un timer fijo: tambaleo durante N segundos, luego recuperación. El problema era visible — un personaje que ya había recuperado el equilibrio seguía tambaleándose, y uno claramente cayéndose se enderezaba de golpe cuando expiraba el timer. La solución fue rastreo de equilibrio basado en físicas. El sistema calcula el centro de masa (promedio ponderado por masa de las 16 posiciones de los cuerpos) y lo compara con el polígono de soporte entre los pies. ¿Recuperas el equilibrio antes? El stagger termina antes. ¿Pierdes el equilibrio sin importar el timer? Ragdoll.
El tambaleo no debe repetirse nunca. El balanceo del stagger usa ratios de frecuencia irracionales (1.73x, 2.17x) para que el patrón de oscilación matemáticamente nunca se repita. La deriva perpendicular crea movimiento en forma de 8. Cada stagger recibe un desfase de fase aleatorio. El resultado parece orgánico y animado a mano — pero es completamente procedural.
Seis días, 94 commits
| Día | Enfoque | Hito |
|---|---|---|
| 1-2 | Fundamentos | Esqueleto dual, springs basados en velocidad, 5 perfiles de arma, recuperación |
| 3 | Arquitectura + stagger | Configuración basada en Resources, auto-detección de esqueleto, estado de stagger, transferencia de momento, dolor acumulativo, lesiones regionales |
| 4 | Resistencia activa | Ajuste dinámico de springs por hueso, balanceo orgánico, 59 tests automatizados |
| 5 | Tests de integración | Probado con un FPS real, corregidos 8 problemas de integración |
| 6 | Lanzamiento público | v0.7.0 en GitHub, GIFs de demo, documentación |
Recuento final: 59 tests con 161 aserciones, 10 escenas de demo interactivas, más de 1.600 líneas de documentación, y más de 35 parámetros ajustables — todos expuestos como Resources de Godot sin ningún valor hardcodeado.
Lo que falta
Kickback implementa los músculos. Lo que falta es el cerebro.
Los personajes de Euphoria dan pasos correctivos cuando pierden el equilibrio. Mueven los brazos como aspas. Se agarran a paredes y barandillas cercanas. Generan poses completamente emergentes sin necesidad de animaciones objetivo. Los personajes de Kickback no hacen nada de eso — son sistemas de springs pasivos que las físicas empujan y los springs tiran de vuelta.
La hoja de ruta incluye pasos procedurales de tropiezo, apoyo con brazos y agarre al entorno. Pero son problemas difíciles — cada uno es un proyecto significativo por sí solo. Por ahora, el sistema de springs cubre el espectro desde estremecimientos sutiles hasta ragdoll completo, y el estado de stagger llena el hueco crítico entre “de pie” y “en el suelo”.
Lo que aprendí
Pelea contra el motor cuando la API no sirve. PhysicalBone3D existe, y construir un rig paralelo parecía un desperdicio. Pero los métodos que faltaban eran innegociables. A veces la herramienta integrada no es la herramienta correcta.
Los springs basados en velocidad superan a los parámetros de joints. Los springs integrados de Jolt están mal documentados, tienen problemas de espacios de coordenadas y ejes invertidos. El lerp manual de velocidad es más simple, depurable y escala uniformemente. La comunidad de V-Sekai y el creador de Jolt Physics recomiendan este enfoque.
Las físicas necesitan animación activa. La decisión contraintuitiva que lo desbloqueó todo. Ragdoll sin poses objetivo de animación es solo un esqueleto colapsándose.
El centro de masa supera a los timers. Las transiciones de estado basadas en timers se sienten arbitrarias. El rastreo de equilibrio basado en físicas responde a lo que realmente le está pasando al personaje, y los jugadores lo leen intuitivamente.
La documentación es el último 20% que lleva el 30% del tiempo. 1.600 líneas de documentación, 10 escenas de demo, 5 GIFs capturados — esto es lo que hace un plugin usable frente a simplemente funcional. Nadie va a adoptar un sistema de físicas que no puede ver funcionando.
Pruébalo
Kickback está en GitHub. Licencia MIT. Godot 4.6+ con Jolt Physics. Dos clics para añadirlo a cualquier personaje humanoide, una línea de código para enviar impactos.
Se aceptan pull requests — especialmente si tienes esqueletos que no sean Mixamo para probar.