Esta charla se adentrará en cómo construir una IA para un juego de estrategia por turnos desde cero. Cuando comencé a construir Athena Crisis, no tenía idea de cómo construir una IA. Todos los recursos disponibles eran demasiado complejos o confusos, así que simplemente comencé a construirlo basándome en cómo jugaría el juego. ¡Si quieres aprender cómo construir una IA, no te pierdas esta charla!
Construyendo la IA para Athena Crisis
Video Summary and Transcription
Únete a Christoph de Nakazawa Tech en la construcción de la IA para Athena Crisis, un juego donde la IA realiza acciones como un jugador. Aprende sobre la importancia de las abstracciones, primitivas y algoritmos de búsqueda en la construcción de una IA para un videojuego. Explora la arquitectura de Athena Crisis, que utiliza estructuras de datos persistentes inmutables y actualizaciones optimistas. Descubre cómo implementar comportamientos de IA y crear una clase para la IA. Averigua cómo analizar unidades, asignar pesos y priorizar acciones basadas en el estado del juego. Considera los próximos pasos en la construcción de la IA y explora la posibilidad de construir una IA para un juego de estrategia en tiempo real.
1. Introducción a la construcción de IA para Athena Crisis
¡Hola! Únete a mí en mi charla sobre la construcción de la IA para Athena Crisis. Soy Christoph de Nakazawa Tech. Si no has oído hablar de Athena Crisis antes, te recomiendo ver mi charla anterior. Tengo experiencia en la gestión de equipos de infraestructura de React Native y JavaScript en Facebook. Ofrecemos coaching de liderazgo y resolución de problemas de JavaScript en Nakazawa Tech. Contáctanos en nakazawa.dev.
¡Oh, hola! Estoy jugando a Athena Crisis en mi Steam deck. Muchas gracias por unirte a mí en mi charla sobre la construcción de la IA para Athena Crisis. Soy Christoph y dirijo una pequeña startup en Tokio llamada Nakazawa Tech. Si no has oído hablar de Athena Crisis antes, recientemente en la React Summit hace unos meses, di una charla que explica cómo se está construyendo el juego, y todo está construido con JavaScript, React y CSS. Recomiendo encarecidamente que si no lo has visto, vuelvas y veas esa charla. Si retrocedemos aún más, si nunca has trabajado conmigo antes o si no me conoces, solía gestionar los equipos de infraestructura de React Native y JavaScript en Facebook, y construí un framework de pruebas llamado JustJavaScript. Hacemos muchas cosas en Nakazawa Tech, incluyendo la construcción de videojuegos, pero también ofrecemos coaching de liderazgo, y podemos ayudarte con tus problemas de JavaScript, con la velocidad de desarrollo, la productividad o ayudarte con cualquier problema que puedas encontrar al construir aplicaciones basadas en JavaScript. Por favor, trabaja con nosotros, contáctanos en nakazawa.dev.
2. Understanding Athena Crisis and Building an AI
Antes de sumergirnos en la construcción de una IA para Athena Crisis, comprendamos qué es Athena Crisis. En el juego, puedo entrar en una partida desde el menú y jugar. Después de mi turno, la IA toma el control y realiza todas las acciones necesarias, como un jugador. Puede atacar, moverse y capturar edificios. Ahora, exploremos cómo construir una IA así.
Primero, antes de adentrarnos en la construcción de una IA para Athena Crisis, dediquemos un poco de tiempo a comprender qué es Athena Crisis. Estoy aquí en el juego en el menú, y puedes ver la página de descripción general en este momento, y puedo entrar en una partida desde aquí mismo. Y así, puedo jugar el juego. Aún no todos los ataques tienen sonido, pero algunos sí lo tienen. Pero lo interesante es que, una vez que termino mi turno, déjame construir algunas unidades. Cuando termino mi turno, la IA toma el control y se encarga de su turno. Realiza ataques, se mueve, puede capturar edificios, puede hacer todo lo que un jugador haría.
3. Building an AI with Abstractions
Veamos cómo construir una IA así. Hablaremos sobre código, abstracciones, primitivas, algoritmos de búsqueda y matemáticas. Construir una IA para un videojuego puede ser desafiante, pero al tener abstracciones básicas y abordarlo como si estuvieras jugando el juego, se vuelve más manejable.
4. Supuestos y Abstracciones para Construir una IA
Quiero construir una IA que sea rápida, sin estado, determinista y componible. Si estoy construyendo una IA que se comporte como un jugador humano, necesito tener abstracciones en el juego que pueda proporcionar al código de la IA que sean básicamente las mismas que le doy a un jugador.
Y así, los supuestos que hice son que quiero construir una IA que sea rápida, sin estado, determinista y componible. Así que te he lanzado muchas palabras. Y la forma en que lo veo es que si estoy construyendo una IA que se comporte como un jugador humano, de la misma manera que estoy jugando, necesito tener abstracciones en el juego que pueda proporcionar al código de la IA que sean básicamente las mismas que le doy a un jugador. Por supuesto, es un poco diferente porque el jugador ve un mapa, se renderiza en un navegador y todo eso, pero debajo de eso, debe haber un nivel
5. Construyendo una IA sin estado para Athena Crisis
Para construir una IA sin estado para Athena Crisis, se necesitan primitivas sólidas como un estado de mapa y acciones. La IA debe ser rápida, sin estado y determinista. La composabilidad también es importante, permitiendo que los módulos sean reutilizables en todo el sistema. La arquitectura de Athena Crisis utiliza estructuras de datos persistentes inmutables, asegurando cambios declarativos en el estado del juego. La IA se ejecuta en el servidor, comportándose como otro jugador, y comunica sus acciones al cliente. Las actualizaciones optimistas garantizan que el cliente y el servidor tomen acciones simultáneamente.
6. Transformadores de acciones y arquitectura
Los transformadores de acciones y la arquitectura de acción-respuesta son la pieza central en la que estamos trabajando. Los jugadores realizan acciones, que se ejecutan en el estado del juego. Las acciones visibles se calculan en función de la niebla de guerra y la visibilidad individual de los jugadores. El generador de código automatiza los codificadores y decodificadores de acciones. Ejecutar una acción implica obtener unidades, asegurarse de los oponentes y verificar la elegibilidad para el ataque.
7. Implementando Comportamientos de IA y Creando una Clase
La arquitectura funciona aplicando respuestas de acción al estado del juego, actualizando unidades con nuevos datos. Este enfoque simplifica la construcción de una IA al generar acciones válidas para el estado actual del juego. La arquitectura proporciona una capa de abstracción común, evitando el fraude de la IA y asegurando que todos los jugadores jueguen según las mismas reglas. Implementemos comportamientos de IA describiendo el comportamiento más básico y creando una pequeña clase.
Y luego realizas una serie de cálculos de daño. Y luego devuelves las estadísticas para las nuevas unidades. Y luego, cuando estás buscando, cuando tienes niebla de guerra, tienes que, como dije, calcular si esas acciones son visibles o no. Entonces hay una definición que uso, básicamente dice que si ambos campos son visibles, entonces puedes recibir la respuesta de acción regular de ataque a la unidad. Si solo la fuente, solo la unidad que está atacando es visible, entonces transforma esa respuesta de acción en un ataque a una unidad oculta. Y si solo el objetivo es visible, lo transforma en un ataque de una fuente oculta a una unidad. Obviamente, estos se invierten, porque si solo el objetivo es visible, entonces la fuente del ataque es visible. Así que es un ataque de fuente oculta. Y luego, más adelante, hay muchas animaciones involucradas aquí. No las mostraré hoy porque no son relevantes para construir la IA, pero aplicamos esas respuestas de acción. Así que observamos todas las respuestas de acción y si está atacando a una unidad, recibimos todos los nuevos datos de la unidad. Obtenemos las unidades existentes y luego, según el estado, actualizamos la unidad con los nuevos datos. Todo aquí es inmutable. Y descubrí que esta arquitectura funciona muy bien para construir una IA. Aquí tienes un ejemplo rápido. Simplemente estoy moviendo y atacando al tanque rosa. Primero, aplicamos la respuesta de acción desde esta posición aquí arriba y la movemos al puente, y luego usamos esa unidad que está en el puente para atacar a la unidad que está junto a ella. Y así es como funciona la arquitectura. Entonces, todo lo que realmente necesitamos si estamos construyendo una IA es generar un montón de estas acciones que sean válidas para el estado actual del juego. Esto simplifica significativamente el problema del proyecto. Porque imagina, no tienes una abstracción como esta donde estás aplicando acciones a un estado de juego y para cada acción del jugador, estás modificando manualmente el estado del juego. Dices, OK, atacar, y luego simplemente vas y tienes código imperativo que cambia todo en un solo lugar. Y luego, si intentas construir una IA, tienes que copiar todo eso a tu IA y luego tienes problemas. Pero también proporciona esta capa de abstracción común donde no le das a la IA acceso para hacer cosas como hacer trampa. Si estás realizando un ataque o ejecutando un ataque con este tipo de abstracción, la IA no puede tener un ataque que sea el doble de efectivo o algo así si eso tampoco está permitido para el jugador. Por supuesto, es posible que desees tener un sistema así. Pero en un juego como Athena Crisis, quieres que todos los jugadores jueguen según las mismas reglas. Finalmente, implementemos comportamientos de IA. Lo hacemos simplemente describiendo el comportamiento más básico.
8. Agregando Comportamientos y Movimientos de IA
La primera versión de nuestra IA solo puede finalizar el turno. Ejecutamos la acción Fin de Turno en el estado del juego y agregamos un método auxiliar llamado actuar. Usamos la función de acción para encadenar los comportamientos de la IA. Cuando la IA está ejecutando un Fin de Turno, devolvemos nulo. Para agregar un movimiento, intentamos mover una unidad. Si no se pueden mover más unidades, finalizamos el turno. Implementamos la función de movimiento utilizando funciones auxiliares para obtener las unidades disponibles y determinar hacia dónde deben ir según el estado del mapa.
9. Moviendo Unidades y Comportamientos de las Unidades
Solo tenemos unos pocos grupos y encontramos un objetivo. Si tenemos una ubicación, ejecutamos una acción de movimiento; de lo contrario, una acción completa. Cada función debe devolver una acción o modificar el estado del juego. La función de movimiento evita el recomputo cuando no hay a dónde ir. Se utiliza el algoritmo A estrella para optimizar el movimiento en la cuadrícula 2D. Las unidades tienen diferentes comportamientos basados en sus habilidades, como capturar edificios o atacar a otros. El comportamiento de la unidad se determina por las posiciones interesantes en el mapa y sus capacidades.
Porque el problema al que te enfrentas, de lo contrario, si ejecutas esta función de acción en un bucle, entrará en la función de movimiento y luego siempre intentará recomputar todo esto, solo para darse cuenta de que no hay a dónde ir. Entonces, siempre debes asegurarte de que cada una de estas funciones, cuando no haya más acciones que tomar, devuelvan nulo o modifiquen el estado del juego para que puedas volver a esa función para mover la siguiente unidad. Entonces, idealmente, a medida que ejecutas acciones de juego aquí, el número de unidades disponibles disminuye a cero para que puedas ingresar a la función de fin de turno aquí.
Muy bien, ahora, descubramos todo esto sobre cómo moverse realmente. Hay un algoritmo muy común . Hay muchos algoritmos para buscar, buscar en una cuadrícula 2D hacia dónde vas. Me decidí por A estrella, funciona muy bien para este tipo de juego. Y lo único aquí es que básicamente estás haciendo una búsqueda en profundidad en una cuadrícula 2D para averiguar dónde deberías ir y estás tratando de hacerlo de la manera más rápida posible con el menor costo. Si solo miramos el mapa del juego, esta unidad no puede ir a las montañas y cuesta más ir al bosque que quedarse en la calle. Entonces, estamos tratando de optimizar cómo llegar desde esta casilla verde, desde esta unidad hasta aquí. En este caso, solo hay un camino, ¿verdad? Pero aún así necesitamos averiguar, está bien, ¿es este el camino a seguir? o deberíamos pasar por el río. Pero ya sabes, esta unidad no puede pasar por el río, así que una vez que haces esta búsqueda de ruta, tienes paredes o tienes un costo de movimiento más alto que ciertas casillas. Y luego, una vez que tienes este radio y esta capacidad para averiguar dónde puede ir esta unidad, entonces podemos averiguar, está bien, ¿cuáles son las posiciones interesantes en un mapa y luego averiguar si la unidad realmente puede viajar allí. Entonces, esto es obviamente una versión simplificada, pero aquí hay tres cosas en las que podrías fijarte. La implementación real en Athena Crisis es de unas cientos de líneas, dependiendo del estado del juego y la unidad sobre la que estás preguntando qué hacer. Entonces, por ejemplo, las unidades pueden capturar edificios, las unidades pueden atacar a otras, las unidades pueden suministrar combustible y munición a otras unidades. Entonces, por ejemplo, podrías tener un sistema aquí donde una unidad que puede suministrar a otras pensará en otras unidades si tienen poca munición, ¿verdad? O en este caso, si la unidad no tiene un ataque o se queda sin munición, está en peligro. Entonces, si está en la primera línea, realmente pensará que las posiciones interesantes son los edificios de vuelta donde están mis bases. Y a través de eso, si alimentamos eso en el sistema que describí, esa unidad intentará retirarse. Y aquí, por ejemplo, si la unidad tiene la capacidad de capturar otros edificios, entonces el lugar más interesante para ir es a otros edificios que son propiedad del oponente. Y finalmente, si la unidad tiene ataques regulares, lo más probable es que encuentre interesante ir a otras unidades, como unidades oponentes
10. Building AI: Encontrar Objetivos y Agregar Ataques
En el lado izquierdo, tenemos todo el mapa con unidades amarillas y rosas. Utilizamos un algoritmo de K-means para encontrar posiciones interesantes y reducirlas a grupos. Luego, encontramos el objetivo más cercano basado en el radio de movimiento y posicionamos la unidad junto a él. Finalmente, ejecutamos una acción de movimiento hacia el puente. Agregar ataques es similar a moverse. Primero analizamos los ataques, luego nos movemos a lugares interesantes y terminamos el turno. Elegimos el mejor ataque basado en el resultado para el jugador actual. Si es necesario, nos acercamos al objetivo antes de atacar.
Y luego simplemente podemos, tal vez en este caso, usar la distancia en la cuadrícula. Pero la implementación real, la forma en que funciona, es que en realidad se verá el radio de movimiento, porque es posible que tengas una unidad que esté muy cerca de otra, pero hay una montaña en medio, por lo que no puede acceder a esa unidad. Entonces, en realidad debes mirar el radio, el radio de movimiento de esa unidad para ver cuál es el más fácil de alcanzar. Y una vez que sepamos cuál es la unidad más cercana, averiguaremos cómo llegar allí realmente. Y luego intentaremos posicionar la unidad justo al lado del objetivo. Entonces, en este caso, objetivo.padre, esta función devuelve una lista de rutas donde cada... lo siento, una lista de campos y donde cada campo tiene un padre, para que puedas navegarlo. Y no podemos mover la unidad encima de otra, así que tenemos que moverla al padre de esa unidad. Y finalmente, podemos unirlo todo y nuestra unidad se mueve hacia el puente. Como dije, buscamos las posiciones interesantes, las reducimos a grupos, encontramos una ruta hacia un objetivo y luego ejecutamos una acción de movimiento. Una vez que hemos terminado con la acción de movimiento, terminamos el turno. Muy bien, y luego lo otro que quiero mostrar es cómo construir un ataque. Por ahora, todo lo que hacemos es que la unidad se mueve, pero ¿cómo agregamos ataques? Y en realidad es muy similar a moverse. Entonces, ¿qué tal si cada vez que la IA comienza, primero miramos los ataques? Si no hay ataques para hacer, entonces nos movemos a lugares interesantes, y finalmente terminamos el turno. La forma en que he implementado esto es que en cada punto del juego, miro cuál es el mejor ataque que tiene el mejor resultado para el jugador actual. Y si hay un ataque disponible, entonces nos aseguramos de que debemos movernos allí. Y si es así, si la distancia es mayor que uno, entonces primero nos acercamos a esa unidad y luego atacamos a esa unidad. Muy bien, ¿cómo averiguamos cuál es el mejor ataque? Aquí hay una implementación básica para averiguar el mejor ataque.
11. Analizando Unidades y Asignando Pesos
Analizamos las unidades y sus capacidades de ataque, asignando pesos al daño probable. Priorizamos las acciones en función del estado del juego y la importancia de derrotar ciertas unidades. En lugar de maximizar el daño, consideramos la cantidad mínima de daño necesaria para eliminar una unidad del campo. Evitamos acciones de bajo daño para prevenir contraataques. Priorizamos la defensa de edificios y unidades con habilidades especiales. Finalmente, observamos cómo nuestra unidad se mueve y ataca al objetivo.
En primer lugar, analizamos todas las unidades que tiene el jugador. Luego, determinamos, okay, anteriormente les mostré el algoritmo A estrella, y podemos extenderlo para no solo proporcionar el radio de movimiento, sino también el radio de ataque, que generalmente es el radio de movimiento más un campo a cada lado, algo así. Luego, para cada unidad a la que esa otra unidad puede atacar, determinamos cuál es el daño probable que podemos infligir, y luego le asignamos un peso. Y, ya saben, acompáñenme por un momento, suponemos que el daño máximo tiene el peso más alto. Luego, lo agregamos a una lista de posibles ataques. Y luego simplemente devolvemos el que tiene el peso más alto. En este caso, el daño más alto. Pero puede que no sea ideal pensar siempre en hacer la mayor cantidad de daño. Por lo tanto, es necesario introducir pesos. Y en este caso, dependiendo del estado del juego, puede ser más valioso atacar ciertas unidades en cierto estado que atacar otras unidades. Por ejemplo, si estás derrotando a esa unidad, es mucho más importante ejecutar esa acción que si solo estás reduciendo un poco su salud. Y este es un cálculo ligeramente más complejo porque lo que he descubierto es que no quieres tener el daño máximo a una unidad que ya está dañada. En realidad, quieres encontrar la unidad que puede hacer la menor cantidad de daño a una cierta unidad para sacarla del campo porque eso reserva otras unidades más fuertes para hacer ataques más fuertes a otras unidades más adelante. Y otra cosa que he descubierto es que, quieres evitar acciones de muy bajo daño porque puede que solo tengas una unidad que se encuentre con otra unidad y no haga ningún daño pero luego el contraataque es tan fuerte que esa unidad es eliminada del campo. Por lo tanto, es posible que desees evitar eso también. Y luego se vuelve mucho más interesante aquí en este lado también dice, okay, ¿qué pasa si hay un edificio aquí y luego hay una unidad oponente en ese campo y esa unidad está tratando de tomar tu edificio eso probablemente es mucho más importante que eliminar una unidad aleatoria que está en otro lugar del campo. Y luego, hay varios casos en los que, si esta unidad está transportando otras unidades o si el edificio en cuestión es el... Si el edificio donde se encuentra esa unidad es tu propia sede, es muy probable que pierdas. Por lo tanto, le daremos prioridad. O en algunos casos, algunas unidades tienen la capacidad de atacar y otras solo tienen otras habilidades especiales. La mayoría de las veces, es más importante atacar esas unidades. Y luego, juntamos todo eso y luego, veremos cómo nuestra unidad se mueve y ataca a esa otra unidad. Muy bien.
12. Building AI: Next Steps and Conclusion
Para continuar construyendo la IA, debemos admitir todas las capacidades de las unidades y edificios, eliminar la información no visible para la IA y considerar comportamientos de IA personalizables. Las IA reales en los videojuegos se optimizan para predecir acciones futuras, pero esto puede ralentizar la IA. Esta visión general es útil para construir una IA de juego de estrategia por turnos en 2D. A continuación, consideremos construir una IA para un juego de estrategia en tiempo real. La charla fue diseñada con React y MDX, y el código fuente está disponible en GitHub. Si estás interesado, ponte en contacto con Nakazawa Tech para colaborar.
Entonces les mostré cómo agregar una IA a un juego de video, cómo moverla, cómo ejecutar ataques. ¿Cuál sería el siguiente paso? En primer lugar, debes admitir todas las capacidades de las unidades y edificios que tiene el juego, para que la IA tenga las mismas capacidades que un jugador humano. No hemos pensado en la niebla de guerra en absoluto en esta IA. De hecho, debemos asegurarnos de que la IA no obtenga información que el jugador no tenga. Por lo tanto, debemos eliminar toda la información que no sea visible para la IA.
Una cosa que encontré muy divertida y que pensé que iba a ser muy difícil, pero resultó ser relativamente fácil, es agregar comportamientos de IA personalizables. Puedes hacer que una IA sea más agresiva, defensiva o pasiva, o puedes adaptar su estilo según el estado del juego, cuando es atacada, cambiará de defensiva a agresiva, algo así. Si has estado siguiendo esto y estás interesado en construir una IA, te recomiendo encarecidamente que construyas tu primera versión y luego pienses en cómo hacerla defensiva o más agresiva. Es realmente divertido experimentar con eso y ver qué tipo de resultados tiene al ajustar el pequeño peso de priorizar una cosa sobre otra.
Finalmente, como dije al principio, solo queremos que esta IA sea rápida, sin estado y componible, y no haga ningún tipo de planificación. No mira hacia atrás. No tiene memoria. No piensa en cinco turnos adelante, en cuál es el movimiento más inteligente que podría hacer ahora que me preparará para el éxito más adelante. Las IA reales en los videojuegos probablemente hagan algún tipo de optimización para predecir lo que va a suceder en el futuro. Planifican cuál es la mejor acción, no solo ahora, sino también si pensamos en el futuro, según cómo pueda evolucionar el juego. El problema con eso es que tiende a volverse muy lento porque la IA tiene que pensar mucho. Por ejemplo, ¿qué pasa si me muevo de esta manera y luego el jugador contrario tiene cinco opciones y puede tomar una de esas cinco, lo que luego genera siete opciones para mí y luego tienes esta explosión en términos de toma de decisiones? Por lo tanto, se vuelve muy lento. Pero espero que esta visión general te haya sido útil si nunca has construido una IA desde cero para entender cómo construir una IA para un juego de estrategia por turnos en 2D. Ahora, el siguiente paso podría ser, ¿cómo construir una IA para un juego de estrategia en tiempo real que tal vez también esté construido en una cuadrícula o algo así?
Otra cosa que quería compartir es que toda esta charla fue diseñada con React y MDX. Construí un sistema llamado reMDX que puedes usar para hacer presentaciones de diapositivas y puedes encontrar el código fuente de toda esta presentación en GitHub también. Y nuevamente, trabajo en Nakazawa Tech, una pequeña startup en Tokio. Si te gustaría trabajar con nosotros, por favor ponte en contacto. Muchas gracias.
Check out more articles and videos
We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career
Workshops on related topic
Table of the content:- Introduction- Intro to PlayCanvas- What we will be building- Adding a character model and animation- Making the character move with scripts- 'Fake' running- Adding obstacles- Detecting collisions- Adding a score counter- Game over and restarting- Wrap up!- Questions
Workshop levelFamiliarity with game engines and game development aspects is recommended, but not required.
In the workshop they'll be a mix of presentation and hands on exercises to cover topics including:
- GPT fundamentals- Pitfalls of LLMs- Prompt engineering best practices and techniques- Using the playground effectively- Installing and configuring the OpenAI SDK- Approaches to working with the API and prompt management- Implementing the API to build an AI powered customer facing application- Fine tuning and embeddings- Emerging best practice on LLMOps
Comments