Bot World

Learn how to program Bots, NPCs, and Rovers…

World

World parameters

Custom map

Maps are loaded from the folder maps as transparent PNGs.
Where the image is black or transparent, bots can move; everything else is treated as a wall.

Game mode

For now only free-for-all mode is available.

Add NPC

Used only if mode is "Fixed point". If the point is inside a wall, the world will try to find a nearby free spot.

You can add several bots of the same or different types.
Player 1: arrows to move and Enter to shoot.
Player 2: W/S move forward/backward, A/D turn, Space = shoot.

Scores

Live bot editor

You must define a function createBot(world) that returns an object with the method update(state). The code below is already an operational bot.

Drag blocks to define your bot logic. Then press “Dump to code” to generate createBot(world) in code mode.

Saved bots are stored in this browser using localStorage. You can modify system bots by loading and registering new behavior.


Help: How do I create my own bot?

In Bot World you can program tanks that move and shoot on their own. You don’t need much programming knowledge: we’ll go step by step.

1. What is a bot here?

A bot is a tank that thinks by itself. The world tells it what’s happening (for example “I see an enemy in front of me”) and the bot responds by saying what it wants to do (move, turn, shoot…).

  • Input: what the bot “sees” → state.
  • Output: what the bot wants to do → cmd.

2. Important parts of the screen

  • General tab: to create the map and add bots.
  • Editor tab: where you write your bot’s code.
  • Bot console (below the editor): shows messages, warnings and errors from your bots.
  • Help tab: this screen, to remind you how everything works.

3. Quick steps to create your first bot

  1. Go to the Editor tab.
  2. In Bot ID, write a name without spaces, for example: myFirstBot.
  3. In Visible name, write how it will appear in the table, for example: My First Bot.
  4. Optional: choose a color, for example #ff8800.
  5. Modify the code in the editor (below we explain how it works).
  6. Click “Register in world”.
  7. Now go to General and in “Bot type” choose your id (for example myFirstBot).
  8. Click “Add bot” and you will see it appear on the map.

If you change the bot’s code in the editor and press “Register in world” again, all instances of that bot will automatically use the new code.

4. Basic bot code

All bots follow the same structure:

function createBot(world) {
    return {
        update: function (state) {
            const cmd = {
                move: 0,   // -1 = backwards, 1 = forwards
                turn: 0,   // -1 = turn left, 1 = turn right
                shoot: false // true = shoot
            };

            // here you decide what the bot does

            return cmd;
        }
    };
}

The update(state) function runs many times per second. Each time, you read the state and return a cmd with instructions.

5. What does the state object contain?

Inside update(state) you can use:

  • state.self.x and state.self.y: bot position on the map (numbers).
  • state.self.angle: angle the tank is facing (you don't need deep math; changing it makes it turn).
  • state.enemyVisible: true if the bot sees an enemy within its field of view.
  • state.enemyDistance: distance to the closest enemy (or null if none are visible).
  • state.enemyDirection: indicates whether the enemy is to the left, center, or right:
    • -1: to the left.
    • 0: roughly in front.
    • 1: to the right.
  • state.canShoot: true if the bot can shoot at this moment (there is a cooldown between shots).
  • state.wallAhead: true if there is a wall (or map border) directly ahead within a certain distance.
  • state.wallDistance: distance in pixels to the wall ahead, or null if none is near in that direction.

6. What does each cmd field mean?

  • cmd.move – how the bot moves:
    • 1 → move forward quickly.
    • -1 → move backward.
    • 0.5 → move forward slowly.
    • 0 → do not move.
  • cmd.turn – how the bot turns:
    • 1 → turn strongly right.
    • -1 → turn strongly left.
    • 0.3 → turn slightly.
    • 0 → do not turn.
  • cmd.shoot – shoot or not:
    • true → try to shoot.
    • false → do not shoot.

7. Simple bot examples

7.1. Patrol bot that always turns

function createBot(world) {
    return {
        update: function (state) {
            const cmd = {
                move: 0.5,  // move forward
                turn: 0.3,  // turn slowly to the right
                shoot: false
            };
            return cmd;
        }
    };
}

7.2. Brave bot that goes after what it sees

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

            if (state.enemyVisible) {
                // turn towards the enemy
                cmd.turn = state.enemyDirection;
                // move fast
                cmd.move = 1;
                // shoot if possible
                if (state.canShoot) {
                    cmd.shoot = true;
                }
            } else {
                // can't see anyone: turn while searching
                cmd.turn = 0.4;
                cmd.move = 0.2;
            }

            return cmd;
        }
    };
}

7.3. Bot that avoids crashing into walls

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

            // If a wall is very close ahead, turn to avoid it
            if (state.wallAhead && state.wallDistance !== null && state.wallDistance < 40) {
                cmd.move = -0.2;   // step back a bit
                cmd.turn = 1;      // turn strongly right
                return cmd;
            }

            if (state.enemyVisible) {
                // Turn toward the enemy and move in
                cmd.turn = state.enemyDirection;
                cmd.move = 0.8;
                if (state.canShoot) {
                    cmd.shoot = true;
                }
            } else {
                // Patrol looking for enemies
                cmd.turn = 0.3;
                cmd.move = 0.4;
            }

            return cmd;
        }
    };
}

8. If something goes wrong…

  • If you see an error message when registering the bot, check that all curly braces { } and parentheses ( ) are correctly closed.
  • If a bot gets “stuck”, you can use the Kill button in the scoreboard to restart it.
  • If a bot behaves strangely, try:
    • Using smaller values in move and turn.
    • Adding console.log("state:", state); inside update. You'll see the messages in both the Bot Console (below the editor) and the browser console (F12).
  • Errors from your bots (like a TypeError) will appear with their message and details in the Bot Console, making it easier to find which line failed. (Note: subtract 3 from the line number shown; if it says “line 30”, the real error is around line 27, due to the wrapper we generate around bot code.)

9. Ideas to improve your bot

  • Run away when the enemy is too close.
  • Turn in circles while shooting.
  • Only shoot if the enemy is centered (better accuracy).
  • Change behavior when the bot has many points.
  • Avoid walls using state.wallAhead and state.wallDistance.

10. ⭐ Advanced mode (optional)

If you have mastered the basics, the world offers advanced sensors that allow you to create much smarter bots. You don’t have to use them all—just experiment when you’re curious.

10.1. Detect bullets coming toward you

The state includes sensors to know if a bullet is heading straight at your bot:

state.bulletIncoming       // true if a bullet is approaching
state.bulletDistance       // distance to the closest bullet
state.bulletDirection      // -1 left, 1 right

Example: dodge bullets by turning the opposite way:

if (state.bulletIncoming && state.bulletDistance < 60) {
    cmd.turn = -state.bulletDirection; // turn opposite direction
    cmd.move = 1; // accelerate to escape
    return cmd;
}

10.2. Wall radar in four directions

Besides wallAhead, you also have wall information on each side:

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

Example: keep centered in corridors by avoiding side walls:

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

10.3. Advanced enemy information

  • state.enemyPos → exact enemy position.
  • state.enemyAngle → enemy angle.
  • state.enemyHp → enemy health (if used).
  • state.enemyDensity → how many enemies are ahead, behind, left or right.

Example: attack if the enemy is centered in your FOV:

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

10.4. Bots with memory

Your bot can remember things between frames using state.memory. You just need to return cmd.memory in the output.


// Example: turn for 30 frames and then change strategy
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; // save changes

10.5. Detect if the bot is stuck

The world calculates whether your bot has moved or collided:

state.last.moved      // true if it moved since last frame
state.last.collided   // true if it collided with a wall

Example: automatically unstuck:


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

These sensors allow building more complex bots: explorers, patrol bots, snipers, bots that flee intelligently, or even bots that “learn” simple behavior patterns using memory.

Tip: start with very simple behavior and add advanced ideas slowly. The best bot is the one you have fun creating!

And that’s it! Experiment, break things, and try again. Every time you change the code and register the bot again, you’re one step closer to having the strongest bot in the world. 💥🤖

11. Three golden rules so your advanced bots stop losing

If you want your advanced bots to stop embarrassing themselves:

  1. Rule 1 – Never stop applying pressure

    In your update(state) function, you can add at the end a small “aggressive fallback” so the bot never freezes or spins uselessly:

    
    if (!state.enemyVisible) {
        // Default aggressive patrol
        cmd.turn ||= 0.3;
        cmd.move ||= 0.7;
    } else {
        // If I see an enemy, always some forward movement and turning
        if (Math.abs(cmd.move) < 0.2) cmd.move = 0.4;
        if (Math.abs(cmd.turn) < 0.1) cmd.turn = state.enemyDirection || 0.2;
    }
    

    This ensures the bot never stays still or spins endlessly.

  2. Rule 2 – Defensive states must expire

    If the bot enters “panic mode” when dodging bullets, that mode must end after a few ticks, or it will dodge forever.

    
    if (state.bulletIncoming && state.bulletDistance !== null && state.bulletDistance < 80) {
        // 1–2 frames of strong dodge
        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) {
        // Reduce counter and gradually return to normal
        cmd.memory.dodgeUntil--;
    }
    

    Without “expiration”, panic mode becomes an infinite loop and the bot never resumes its offensive plan.

  3. Rule 3 – Shooting is cheap, don’t be a perfectionist

    For snipers and advanced bots, it’s better to shoot “good enough” than to wait for the perfect shot:

    
    if (state.enemyVisible && state.canShoot) {
        const dist = state.enemyDistance || 9999;
    
        // Optimal sniper range
        if (dist < 180 && dist > 40) {
            cmd.shoot = true;
        }
    
        // Positioning adjustment
        if (dist <= 60) {
            cmd.move = -0.5; // move away a bit
        } else if (dist > 160) {
            cmd.move = 0.6;  // move closer a bit
        }
    
        cmd.turn = state.enemyDirection;
    }
    

    The key: don’t wait for a perfect shot. Shooting with a bit of error still works very well.