Andrea Horvath

Software Engineer, Problem Solver


Herlock vs. Sherlock

This tiny game was made in a week for Bitsy Jam #69, where the theme was "public domain." Inspired by Sherlock Holmes entering the public domain, I created a miniature Pokémon-style battler where the copyright-friendly Herlock Sholmes faces off against the original Sherlock Holmes.

Bitsy is primarily designed for simple narrative adventures, so implementing a turn-based combat system required extending the engine far beyond its intended use case.



Core Features

  • Built a turn-based battle system inspired by Pokémon
  • Implemented enemy AI and combat resolution logic
  • Created dynamic health bars by modifying Bitsy tile data at runtime
  • Developed game-state management for player stats, enemy stats, and win/loss conditions
  • Added randomized battle dialogue and item usage systems

Building a Turn-Based Battler

Bitsy isn't designed for RPG-style combat, so I needed to build most of the battle logic myself. I used a small object-oriented architecture consisting of a Game object that managed player state and combat flow, and an Enemy object responsible for AI behavior and enemy-specific data.

Each turn generated a new Data object containing combat results, dialogue, and game-over information that was then passed back into Bitsy's scripting system. On game startup (and whenever a round ended), a new Game() instance was created to reset the battle state.

class Data {
    constructor(txt, enemyTxt, gameOver, win) {
        this.txt = txt;
        this.enemyTxt = enemyTxt;
        this.gameOver = gameOver;
        this.win = win;
    }
}

\\ example method showing player's `attack` functionality
attack() {
    var enemyTurn = this.enemy.play(this.stunned);
    let opt = SstunOpt;
    if (!this.stunned) {
        opt = playerAttackOptions[Math.floor(Math.random() * playerAttackOptions.length)];
        this.defended = false;
        this.enemy.takeDamage(opt.atk)
    }
    else {
        this.stunned = false;
    }


    if (enemyTurn.atk > 0) {
        this.takeDamage(enemyTurn.atk);
    }
    else if (enemyTurn.effect) {
        his.takeEffect(enemyTurn.effect)
    }

    return new Data(opt.txt, enemyTurn.txt, this.hp <= 0 || this.enemy.hp < 0, this.enemy.hp <= 0);
}

Creating Dynamic Health Bars

One of the biggest challenges was creating health bars. Bitsy's tiles are normally static (except for things like items and characters/sprites), so there isn't a built-in way to display UI elements that change during gameplay. To work around this, I tracked the locations of health bar tiles and replaced them with different sprites as health values changed.

const SHERLOCK_HEALTHBAR_SPRITES = {
    row: 14,
    col_start: 12,
    col_end: 4,
    full: {
        tile_id: "28",
        tile_name: "tile 28",
    },
    half: {
        tile_id: "2g",
        tile_name: "s_half_health",
    },
    empty: {
        tile_id: "2e",
        tile_name: "s_empty_health",
    }
}

The example above shows how I stored Sherlock's health bar sprite data. row and col variables help track where on the canvas these tiles were (as Bitsy games are organized in a 16x16 grid of 8-bit sprites). The tile data determines which sprite should be displayed as health values change. I then use this data inside updateTilemap(), which runs at the end of each turn.

updateTilemap(tilemap, player) {
    if (player === "enemy") {
        let data = HERLOCK_HEALTHBAR_SPRITES;
        let curTile = this.enemy.currentHealthTile;

        if (this.enemy.hp < this.enemy.lastHp) {
            tilemap[data.row][curTile] = data.empty.tile_id;
            this.enemy.currentHealthTile--;
            this.enemy.lastHp = this.enemy.hp;
        }
    }
    else {
        let data = SHERLOCK_HEALTHBAR_SPRITES
        let curTile = this.currentHealthTile;

        if (this.hp < this.lastHp) {
            tilemap[data.row][curTile] = data.empty.tile_id;
            this.currentHealthTile--;
            this.lastHp = this.hp;
        }
        else if (this.hp > this.lastHp) {
            let i = 2; // num of tiles to restore
            while (this.currentHealthTile != data.col_start && i > 0) {
                this.currentHealthTile++;
                i--;
                tilemap[data.row][this.currentHealthTile] = data.full.tile_id;
            }
            this.lastHp = this.hp;
        }
    }
}

\\ called after updateTilemap() in Bitsy's game code
drawRoom(room[state.room], { redrawAll: true });

By directly modifying the room's tile data and forcing a redraw, I was able to simulate health bars increasing and decreasing during combat, helping the game feel much closer to a traditional RPG despite being built in Bitsy.


Closing Thoughts

Herlock vs. Sherlock was a fun exercise in pushing Bitsy beyond its intended use case. While Bitsy is primarily designed for simple narrative experiences, this project challenged me to build turn-based combat, state management, and dynamic UI systems within its limitations.

The project reinforced one of my favorite aspects of working with small game engines: finding creative solutions to problems the engine was never designed to solve. Building a functioning battler inside Bitsy ended up being just as enjoyable as making the game itself.