Desarrollo guiado por pruebas para juegos complejos

8

Estoy codificando un juego en mi tiempo libre, pero aún soy un principiante en lo que respecta a la programación. Lo siento si esta pregunta está fuera de tema o si termina no siendo útil para nadie más, pero espero que lo sea.

He pasado mucho tiempo leyendo libros sobre el diseño de código, así como diferentes metodologías y enfoques de codificación. En el curso de esta investigación sigo topando con el concepto de Test Driven Development. Las personas que defienden esta idea generalmente parecen muy apasionadas. Creo que puede ayudar a la velocidad y eficiencia del software de escritura. El tiempo es un recurso muy valioso, por lo que preferiría aprender a hacer las cosas de la mejor manera en lugar de confundirme sin tratar de ampliar mi conocimiento de la programación.

De todos modos, posiblemente porque soy un principiante, no puedo imaginar cómo aplicar el desarrollo basado en pruebas a los juegos. Encontré un par de artículos sobre el tema pero no fueron de mucha ayuda. La mayoría de los ejemplos de pruebas unitarias que he visto son ejemplos muy simples, o ejemplos de software que no se parece en nada a un juego.

En mi propia codificación, trato de abordarlo con una mentalidad similar para probar el desarrollo impulsado, aunque estoy seguro de que en realidad no califica como TDD. Escribo la cantidad mínima de código para intentar implementar cualquier característica que agregue al juego, y luego pruebo inmediatamente el juego para ver si funciona. Si las cosas no suceden como pretendía, inmediatamente hago cambios para acercarme a lo que quiero. Si no funciona o no funciona, y si no puedo encontrar los errores leyendo el código, paso por los métodos en el depurador hasta que encuentre el comportamiento inesperado, y luego lo elimino. Lo que intento decir es que constantemente estoy probando el juego, más o menos después de cada cambio incremental. Las pruebas impulsan mi desarrollo. La "prueba unitaria" está en mi cabeza,

A mi pregunta real. ¿Cómo se pueden escribir pruebas unitarias para un juego complejo? Por complejo, quiero decir con muchos aspectos emergentes del juego, de modo que la esencia del juego surge de la interacción entre los diferentes elementos dentro del juego combinados con las elecciones del jugador. Por ejemplo, un RPG roguelike con un mundo procesal. ¿Qué tipo de pruebas unitarias escribiría para un juego como ese? ¿Cómo se podría aplicar el desarrollo impulsado por pruebas a un juego así?

bazola
fuente
2
Este rey de la pregunta podría ser más adecuado para la sección Game Dev: gamedev.stackexchange.com
glampert
1
Vale la pena señalar que el desarrollo impulsado por pruebas lo alienta a dividir su diseño en pequeñas unidades manejables. Utilizo pruebas unitarias para probar la lógica que puede o no usarse para la funcionalidad del proyecto, en cambio, a veces su propósito sirve para probar el concepto en sí. Busque juegos maduros de código abierto para obtener buenos ejemplos de trabajo de cómo se pueden usar las pruebas unitarias en el desarrollo de juegos
Keldon Alleyne

Respuestas:

12

Las pruebas unitarias no prueban el juego . No hay criterios programáticos para ver si un juego es divertido o si un nivel es la dificultad correcta. Las pruebas unitarias comprobarán que tu mapgen roguelike realmente produce un nivel con una escalera arriba y una escalera abajo. Pondrá a prueba que sus reglas de gravamen están configuradas para que su personaje realmente se mueva más lento cuando está ponderado. Se asegurará de que tu personaje no pueda usar 50 sombreros . Se asegurará de que todas las mecánicas se implementen correctamente en un relativo aislamiento.

Telastyn
fuente
1
Su respuesta me ayuda a entender las cosas un poco mejor, pero no completamente. Según tengo entendido, para que sea realmente un desarrollo impulsado por pruebas, las pruebas deben escribirse primero. Por lo tanto, escriba las pruebas fallidas, escriba el código para que pase, luego arregle el código. ¿Cómo podría aplicarse esto para probar si un mapgen produce un nivel con escaleras arriba y abajo? ¿Qué tipo de prueba unitaria cumpliría con los requisitos de TDD?
bazola
1
@bazola - ¿Me temo que no entiendo? Escribe una prueba para llamar al mapgen, luego verifica si el resultado tiene escaleras arriba y abajo. Eso no se compila ya que tienes un mapgen ni el concepto de escaleras. Entonces haces esos. Luego haces que el mapgen realmente cumpla con los criterios ...
Telastyn
Eso tiene sentido. ¡Muy apreciado!
bazola
44
Relevante: TDD no necesariamente significa que las pruebas unitarias son el único controlador en desarrollo. Puede iniciar la "unidad" escribiendo una prueba de "aceptación" y / o integración de fallas de alto nivel, a partir de la cual podría concebir una solución y escribir su primera prueba de unidad con fallas ... aunque, sinceramente, no estoy seguro de qué se necesita para escribir una prueba de aceptación significativa y automatizada para un juego no trivial.
svidgen
2

Es difícil escribir pruebas unitarias para código que no sea determinista. Si tiene un código que involucra números aleatorios, no podrá escribir una prueba unitaria que afirme un resultado esperado.

Entonces, las pruebas unitarias son más apropiadas para el código que es determinista. Cuando le doy a un método estas entradas, espero estas salidas. Como ejemplo: cuando un luchador con 15 puntos de fuerza usa su espada ancha de dos manos para golpear con éxito a un demonio no muerto con 10 armaduras, espero 8 daños. La parte no determinista (si el golpe fue exitoso o no) no necesariamente puede ser probada por unidad, pero lo que sucede después puede serlo. Incluso si se espera que la cantidad de daño esté dentro de cierto rango, puede probarlo.

Si tiene dificultades para encontrar código para escribir pruebas unitarias, debe refactorizar para que la lógica determinista esté aislada en métodos o clases. Tira los dados primero para determinar el éxito, luego pasa las entradas relevantes (clase, fuerza, armadura, etc.) a un método comprobable.

Para su comentario acerca de tener la prueba de la unidad en su cabeza, el punto de la prueba de la unidad no es solo el código recién escrito. También se trata de tener confianza en que el código aún funciona después de hacer cambios inevitables .

Sam Jones
fuente
3
Una forma de probar el código de la unidad que utiliza la aleatoriedad es ejecutarlo muchas veces y verificar si los resultados se ajustan estadísticamente a la distribución esperada. Entonces, cuando se supone que un ataque causa 10 + 2d6 de daño, ejecuta el código 1000 veces y verifica que no haya un resultado mayor que 22, no menor que 12 y que haya una distribución más o menos en forma de campana dentro de ese rango.
Philipp
1
También puedes aplicar este método a situaciones más complejas, como asegurarte de que un personaje de nivel 1 gane una pelea simulada contra un duende aproximadamente el 90% del tiempo.
Philipp
3
Normalmente, si parte de su código usa números aleatorios, abstrae su generador de números aleatorios en un servicio ( IRandomNumberGenerator) y cualquier cosa que necesite usar números aleatorios acepta una referencia a esa interfaz de servicio en su constructor. Luego, cuando su prueba crea ese objeto para ejecutar una prueba unitaria, inyecta un MockRandomNumberGeneratorque alimenta un flujo fijo de números conocidos. Entonces tienes una prueba repetible. La misma idea es útil para cualquier cosa que necesite obtener la fecha / hora actual o descargar información de un servicio web, simplemente inyecte un servicio simulado.
Scott Whitlock
... luego puede escribir una prueba separada que utilice métodos estadísticos para verificar el funcionamiento real de su implementación real RandomNumberGenerator.
Scott Whitlock
Votaría en contra si pudiera. Las características estadísticas del resultado deben probarse para el algoritmo aleatorio.
Riga