A la caza del bug

 Cualquier software de cierta complejidad tendrá bugs. Con suerte, serán fáciles de encontrar, el problema es que la suerte es inversamente proporcional a lo complejo que sea. Un juego, aún en estado de prototipo, es casi un plato de espaguetis: hay muchos subsistemas en acción a la vez.

He tenido que dedicar tres días a resolver un bug bastante escurridizo, que había pasado desapercibido porque es muy difícil desarrollar y probar a fondo a la vez. Como casi todo, se produjo cuando solucioné un problema. Puede parecer tonto, pero manejar el estado de muerte de un personaje es... muy jodido. El personaje debe desaparecer del mapa (si es un NPC) o finalizar el juego (si es el del jugador), pero no puede ser de golpe. Hay que ejecutar una animación, y en dependencia de si es un NPC, hay que guardar su estado para que no vuelva a aparecer cuando restaures la partida o regreses a esa escena y dejar algún botín o no. 

Había logrado que todo esto funcionara bien, excepto en un lugar crítico. La primera pelea del jugador es una batalla grupal. Por desgracia, para probarla hay que iniciar la partida desde el principio y jugar unos dos minutos. Tampoco es una pelea que puedas ganar, es una batalla de equipo donde un NPC carga el peso de casi todo el combate. Justo ahí estaba el problema. Todos los combates funcionaban bien, pero en esta pelea específica, de los tres NPCs, dos morían y dejaban de reaccionar, pero no desaparecían. El último en morir siempre funcionaba como debe ser. Lo cual llevaba a un segundo problema: tu NPC acompañante se quedaba bloqueado ahí. A pesar de que la quest se registraba como cumplida, el NPC no salía del combate y era imposible continuar el juego. 

¿Por qué nunca llegaba a completarse la animación de muerte, y por tanto, no se disparaba la desaparición? ¿Por qué el sistema funcionaba bien cuando peleaba contra un solo oponente, e incluso, contra dos? Me tomó tres noches de trabajo (digamos que siete u ocho horas) rastrear todas las posibles causas. Algo estaba interrumpiendo la animación de muerte, y encima, estaba devolviendo el NPC al estado combate, a pesar de estar marcado como muerto. ¿Era el AnimationTree? ¿Acaso los tres NPCs era una misma instancia de la escena o algo así?

Bien, el error no estaba ahí. Se trataba de un bug en la IA, que solo podía darse en ese caso específico, porque era una batalla de grupo. En concreto: la IA al entrar en combate puede llamar a los miembros de su grupo para que acudan a pelear, pero esto no estaba verificando si el NPC estaba muerto, solo si no estaba ya en el estado combate. Por tanto, apenas morían, los NPCs eran llamados otra vez a la batalla, devolviéndolos al estado combate. Aunque, al estar marcados como muertos, no podían hacer nada salvo estar ahí parados.

La solución óptima y que cortaría de raíz el problema es que la máquina de estados del personaje no cambie si ya está muerto, porque hay muchas otras formas en que el estado combate se activa: al recibir un ataque de cualquier tipo, por ejemplo. De todas formas, he rastreado muchas de esas vías de entrada y agregado verificaciones. 

Por esa razón es que los equipos de beta testing son tan grandes: veinte personas, por lo menos, muchas más para proyectos grandes. En el caso de este proyecto, dos beta testers han encontrado una buena parte de los errores, pero no todos. Como siempre les digo, la fase de pruebas es más complicada de lo que parece.

Comentarios