Mundo de Bots

Aprende como programar Bots, NPCs, Rovers...

Mundo

Parámetros del mundo

Mapa personalizado

Los mapas se cargan desde la carpeta maps como PNG transparentes.
Donde la imagen sea negra o transparente se podrá circular; el resto se considera muro.

Modo de juego

Por ahora sólo está disponible el modo todos contra todos.

Añadir NPC

Se usa sólo si el modo es "Punto fijo". Si el punto está dentro de un muro, el mundo intentará buscar un sitio cercano libre.

Puedes añadir varios bots del mismo tipo o de tipos distintos.
Jugador 1: flechas para mover y Intro para disparar.
Jugador 2: W/S avanzar/retroceder, A/D girar, espacio = disparar.

Puntuaciones

Editor de bot (en vivo)

Debes definir una función createBot(world) que devuelva un objeto con el método update(state). El código de abajo ya es un bot operativo.

Arrastra bloques para definir la lógica de tu bot. Luego pulsa “Volcar a código” para generar el createBot(world) en modo código.

Los bots guardados se almacenan en este navegador usando localStorage. Se puede modificar el comportamiento de los bots del sistema cargando y registando el nuevo comportamiento.


Ayuda: ¿Cómo creo mi propio bot?

En Mundo de Bots puedes programar tanques que se mueven y disparan solos. No hace falta saber mucha programación: iremos paso a paso.

1. ¿Qué es un bot aquí?

Un bot es un tanque que piensa por sí mismo. El mundo le dice lo que está pasando (por ejemplo “veo un enemigo delante”) y el bot responde diciendo lo que quiere hacer (moverse, girar, disparar…).

  • Entrada: lo que el bot “ve” → state.
  • Salida: lo que el bot quiere hacer → cmd.

2. Partes importantes de la pantalla

  • Pestaña General: para crear el mapa y añadir bots.
  • Pestaña Editor: donde escribes el código de tu bot.
  • Consola del bot (debajo del editor): muestra mensajes, avisos y errores de tus bots.
  • Pestaña Ayuda: esta pantalla, para recordar cómo se hace todo.

3. Pasos rápidos para crear tu primer bot

  1. Ve a la pestaña Editor.
  2. En Id del bot escribe un nombre sin espacios, por ejemplo: miPrimerBot.
  3. En Nombre visible pon cómo se verá en la tabla, por ejemplo: Mi Primer Bot.
  4. Opcional: elige un color, por ejemplo #ff8800.
  5. Modifica el código que hay en el editor (más abajo te explicamos cómo funciona).
  6. Pulsa “Registrar en el mundo”.
  7. Ahora ve a General y en “Tipo de bot” elige tu id (por ejemplo miPrimerBot).
  8. Pulsa “Añadir bot” y verás cómo aparece en el mapa.

Si cambias el código del bot en el editor y pulsas otra vez “Registrar en el mundo”, las instancias de ese bot usarán el nuevo código automáticamente.

4. El código básico de un bot

Todos los bots siguen la misma estructura:

function createBot(world) {
    return {
        update: function (state) {
            const cmd = {
                move: 0,   // -1 = hacia atrás, 1 = hacia delante
                turn: 0,   // -1 = girar izquierda, 1 = girar derecha
                shoot: false // true = disparar
            };

            // aquí decides qué hace el bot

            return cmd;
        }
    };
}

La función update(state) se ejecuta muchas veces por segundo. Cada vez miras el state y devuelves un cmd con las órdenes.

5. ¿Qué tiene el objeto state?

Dentro de update(state) puedes usar:

  • state.self.x y state.self.y: posición del bot en el mapa (números).
  • state.self.angle: ángulo al que apunta el tanque (no hace falta entender los radianes, sólo saber que cambiarlo hace que mire a otra dirección).
  • state.enemyVisible: true si el bot ve algún enemigo en su cono de visión.
  • state.enemyDistance: distancia al enemigo más cercano (o null si no ve a nadie).
  • state.enemyDirection: indica si el enemigo está a la izquierda, centro o derecha:
    • -1: está a la izquierda.
    • 0: más o menos de frente.
    • 1: está a la derecha.
  • state.canShoot: true si el bot puede disparar en este momento (hay un tiempo de recarga entre disparos).
  • state.wallAhead: true si el bot tiene un muro (o el borde del mapa) justo delante en la dirección a la que mira, dentro de un cierto alcance.
  • state.wallDistance: distancia en píxeles hasta ese muro de delante, o null si no hay ninguno cerca en esa dirección.

6. ¿Qué significa cada campo de cmd?

  • cmd.move – cómo se mueve el bot:
    • 1 → avanzar hacia delante (rápido).
    • -1 → ir hacia atrás.
    • 0.5 → avanzar más despacio.
    • 0 → no moverse.
  • cmd.turn – cómo gira:
    • 1 → girar fuerte a la derecha.
    • -1 → girar fuerte a la izquierda.
    • 0.3 → girar un poco.
    • 0 → no girar.
  • cmd.shoot – disparar o no:
    • true → intenta disparar.
    • false → no dispara.

7. Ejemplos de bots sencillos

7.1. Bot patrulla que gira siempre

function createBot(world) {
    return {
        update: function (state) {
            const cmd = {
                move: 0.5,  // avanza
                turn: 0.3,  // gira despacio a la derecha
                shoot: false
            };
            return cmd;
        }
    };
}

7.2. Bot valiente que va a por lo que ve

function createBot(world) {
    return {
        update: function (state) {
            const cmd = { move: 0, turn: 0, shoot: false };

            if (state.enemyVisible) {
                // gira hacia el enemigo
                cmd.turn = state.enemyDirection;
                // avanza rápido
                cmd.move = 1;
                // dispara si puede
                if (state.canShoot) {
                    cmd.shoot = true;
                }
            } else {
                // no ve a nadie: gira buscando
                cmd.turn = 0.4;
                cmd.move = 0.2;
            }

            return cmd;
        }
    };
}

7.3. Bot que evita chocarse con muros

function createBot(world) {
    return {
        update: function (state) {
            const cmd = { move: 0, turn: 0, shoot: false };

            // Si hay un muro muy cerca delante, giramos para evitarlo
            if (state.wallAhead && state.wallDistance !== null && state.wallDistance < 40) {
                cmd.move = -0.2;   // retrocede un poco
                cmd.turn = 1;      // gira fuerte a la derecha
                return cmd;
            }

            if (state.enemyVisible) {
                // Gira hacia el enemigo y avanza
                cmd.turn = state.enemyDirection;
                cmd.move = 0.8;
                if (state.canShoot) {
                    cmd.shoot = true;
                }
            } else {
                // Patrulla buscando enemigos
                cmd.turn = 0.3;
                cmd.move = 0.4;
            }

            return cmd;
        }
    };
}

8. Si algo sale mal…

  • Si te aparece un mensaje de error al registrar el bot, revisa que todas las llaves { } y paréntesis ( ) estén bien cerrados.
  • Si un bot se queda “colgado”, puedes usar el botón Kill en la tabla de puntuaciones para reiniciarlo.
  • Si un bot se comporta raro, prueba a:
    • Poner valores más pequeños en move y turn.
    • Añadir console.log("state:", state); dentro de update. Verás los mensajes tanto en la Consola del bot (debajo del editor) como en la consola del navegador (F12).
  • Los errores de tus bots (por ejemplo, un TypeError) también aparecerán con su mensaje y detalles en la Consola del bot, para que sea más fácil encontrar qué línea está fallando. (a la linea del primer error hay que restarle 3, es decir, si indica fallo en la linea 30 realmente esta en la 3, esto se debe al encapsulado que hacemos del codigo del bot )

9. Ideas para mejorar tu bot

  • Que huya cuando el enemigo esté muy cerca.
  • Que gire en círculos mientras dispara.
  • Que sólo dispare si el enemigo está pegado al centro (para fallar menos).
  • Que cambie de comportamiento cuando lleve muchos puntos.
  • Que evite los muros usando state.wallAhead y state.wallDistance.

10. ⭐ Modo avanzado (opcional)

Si ya dominas lo básico, el mundo ofrece sensores avanzados que permiten crear bots mucho más inteligentes. No hace falta usarlos todos: están ahí para que experimentes cuando tengas curiosidad.

10.1. Detectar balas que vienen hacia ti

El estado incluye sensores para saber si una bala va directa hacia tu bot:

state.bulletIncoming       // true si una bala se acerca
state.bulletDistance       // distancia a la bala más cercana
state.bulletDirection      // -1 izquierda, 1 derecha

Ejemplo: esquivar balas girando hacia el lado contrario:

if (state.bulletIncoming && state.bulletDistance < 60) {
    cmd.turn = -state.bulletDirection; // giro en sentido opuesto
    cmd.move = 1; // acelero para escapar
    return cmd;
}

10.2. Radar de muros en cuatro direcciones

Además de wallAhead, tienes información de muros a cada lado:

state.wallRadar.front
state.wallRadar.back
state.wallRadar.left
state.wallRadar.right

Ejemplo: centrarse en pasillos evitando muros laterales:

if (state.wallRadar.left < 30) cmd.turn = 0.5;
if (state.wallRadar.right < 30) cmd.turn = -0.5;

10.3. Información avanzada del enemigo

  • state.enemyPos → posición exacta del enemigo.
  • state.enemyAngle → ángulo del enemigo.
  • state.enemyHp → vida del enemigo (si se usa).
  • state.enemyDensity → cuántos enemigos hay delante, detrás, izquierda o derecha.

Ejemplo: atacar si el enemigo está centrado en nuestro FOV:

if (state.enemyVisible && Math.abs(state.enemyDirection) < 0.2) {
    cmd.move = 1;
    if (state.canShoot) cmd.shoot = true;
}

10.4. Crear bots con memoria

Tu bot puede recordar cosas entre frames usando state.memory. Solo tienes que devolver cmd.memory en la salida.


    // Ejemplo: girar durante 30 frames y luego cambiar de estrategia
    if (!state.memory.turnTime) state.memory.turnTime = 0;

    state.memory.turnTime++;
    cmd.turn = 1;

    if (state.memory.turnTime > 30) {
        cmd.turn = -1;
    }

    cmd.memory = state.memory; // guardar cambios

10.5. Detectar si el bot se ha quedado atascado

El mundo calcula si tu bot ha logrado moverse o ha chocado:

state.last.moved      // true si se movió desde el último frame
state.last.collided   // true si chocó contra un muro

Ejemplo: desatascarse automáticamente:


    if (!state.last.moved && state.last.collided) {
        cmd.move = -1;   // retroceder
        cmd.turn = 1;    // girar fuerte
        return cmd;
    }

Estos sensores permiten crear bots más complejos: exploradores, bots que patrullan, bots francotiradores, bots que huyen inteligentemente, o incluso bots que “aprenden” patrones sencillos usando memoria.

Consejo: empieza por un comportamiento muy simple, y añade ideas avanzadas poco a poco. ¡El mejor bot es el que te diviertes creando!

¡Y ya está! Experimenta, rompe cosas y vuelve a probar. Cada vez que cambias el código y vuelves a registrar el bot, estás un paso más cerca de tener el bot más fuerte del mundo. 💥🤖

11. Tres reglas de oro para que tus avanzados dejen de perder

Si quieres que los avanzados dejen de hacer el ridículo:

  1. Regla 1 – Nunca dejes de presionar

    En tu función update(state) puedes añadir al final un pequeño “filtro agresivo” para que el bot no se quede parado ni mareado:

    
        if (!state.enemyVisible) {
            // Patrulla agresiva por defecto
            cmd.turn ||= 0.3;
            cmd.move ||= 0.7;
        } else {
            // Si veo enemigo, siempre algo de avance y de giro
            if (Math.abs(cmd.move) < 0.2) cmd.move = 0.4;
            if (Math.abs(cmd.turn) < 0.1) cmd.turn = state.enemyDirection || 0.2;
        }
    

    Así te aseguras de que el bot no se quede parado o dando vueltas sin sentido.

  2. Regla 2 – Los estados defensivos tienen que caducar

    Si el bot entra en “modo pánico” al esquivar balas, ese modo debe terminar después de unos cuantos ticks, o se quedará esquivando para siempre.

    
        if (state.bulletIncoming && state.bulletDistance !== null && state.bulletDistance < 80) {
            // 1–2 ticks de esquiva fuerte
            cmd.move = 1;
            cmd.turn = state.bulletDirection > 0 ? -0.8 : 0.8;
            cmd.memory = cmd.memory || {};
            cmd.memory.dodgeUntil = (cmd.memory.dodgeUntil || 0) + 1;
        } else if (cmd.memory && cmd.memory.dodgeUntil > 0) {
            // Reducimos el contador y volvemos poco a poco al comportamiento normal
            cmd.memory.dodgeUntil--;
        }
    

    Si no le pones “caducidad” a esos modos de pánico, el bot entra en un bucle de evasión infinita y no vuelve al plan ofensivo.

  3. Regla 3 – Disparar es barato, no seas perfeccionista

    Para francotiradores y bots avanzados, es mejor disparar “bastante bien” que esperar al tiro perfecto:

    
        if (state.enemyVisible && state.canShoot) {
            const dist = state.enemyDistance || 9999;
    
            // Rango óptimo de francotirador
            if (dist < 180 && dist > 40) {
                cmd.shoot = true;
            }
    
            // Ajuste de posición
            if (dist <= 60) {
                cmd.move = -0.5; // se aleja un poco
            } else if (dist > 160) {
                cmd.move = 0.6;  // se acerca un poco
            }
    
            cmd.turn = state.enemyDirection;
        }
    

    La clave: no esperar al tiro perfecto. Disparar con un poco de error sigue funcionando muy bien.