2026 Summer Roguelike project, Part 5

 from Red Blob Games
18 Aug 2026

Part 5 adds bumping into enemies.

I’m liking querying the Table class. Here’s the tutorial’s Python code checking if there are any entities on a tile:

if not any(entity.x == x and entity.y == y for entity in dungeon.entities):
    …

And here’s a query on my table:

let location = {type: 'map', x, y};
if (!world.entities.findAny({location})) {
    …
}

Similarly, the tutorial has:

def get_blocking_entity_at_location(self, location_x: int, location_y: int) -> Optional[Entity]:
    for entity in self.entities:
        if entity.blocks_movement and entity.x == location_x and entity.y == location_y:
            return entity

and I have

let entity = world.entities.findAny({blocksMovement: true, location: {type: 'map', x: newX, y: newY}});

However I’m not liking the object creation. I don’t have factories like the Python tutorial uses. I probably should have added them, but I inlined the calls instead. The tutorial has:

entity_factories.orc.spawn(dungeon, x, y)

whereas my code has:

let type = randint(0, 3) === 0? 'troll' : 'orc';
world.entities.create(type, {location});

This seemed fine at the time, but later on when we introduce combat, my code get more awkward. On the plus side, my entity objects have no cycles, which makes saving & loading easier later on.

I am not sure what to think of the tutorial’s class hierarchies. They have Action, ActionWithDirection, EscapeAction, MovementAction, MeleeAction, BumpAction. I don’t have any of that. I put that logic into a single function:

/**
 * Attempt to run the action
 * @param {Action} action
 * @returns {boolean} - true if the turn ends
 */
function handlePlayerAction(action) {
    switch (action.type) {
        case 'move':
            let newX = world.player.location.x + action.dx;
            let newY = world.player.location.y + action.dy;
            let tile = world.tiles.findAny({walkable: true, position: {x: newX, y: newY}});
            if (!tile) return false;

            let blockingEntity = world.entities.findAny({blocksMovement: true, location: {type: 'map', x: newX, y: newY}});
            if (blockingEntity) {
                console.log(`You kick the ${blockingEntity.type}, much to its annoyance!`);
                return true;
            } else {
                world.player.location = {type: 'map', x: newX, y: newY};
                return true;
            }
    }

    throw `Unknown action: ${JSON.stringify(action)}`;
}

I think this shows my general bias. I usually prefer union types with switch statements over inheritance hierarchies. I think there are pros and cons of the two approaches. I wish Javascript had enums more like Rust’s.

Here’s the game at the end of Part 5:

Email me , or comment here: