Learn how to program Bots, NPCs, and Rovers…
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.
For now only free-for-all mode is available.
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.
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.

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.
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…).
state.cmd.myFirstBot.
My First Bot.
#ff8800.id (for example myFirstBot).
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.
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.
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:
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.
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.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;
}
};
}
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;
}
};
}
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;
}
};
}
{ } and parentheses
( ) are correctly closed.
move and turn.console.log("state:", state); inside
update. You'll see the messages in both the
Bot Console (below the editor) and the browser console (F12).
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.)
state.wallAhead and state.wallDistance.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.
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;
}
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;
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;
}
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
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. 💥🤖
If you want your advanced bots to stop embarrassing themselves:
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.
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.
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.
| Id | Name | JS lines | Blocks | Size | Actions |
|---|