Search code examples
javascriptkaboom

Is there a way to merge multiple tiles in a level - Kaboom JS


When making a level in kaboomJS with a large tile map collisions, things start to get slow... So I was wondering if there was an easy way to merge multiple tiles like maybe a whole row of blocks could be treated as one large block?


Solution

  • 1. Tiles don't have to fit in the grid

    If you want to reduce the number of Game Objects in the Scene at a time you can have a single symbol in your level definition represent a Game Object that spans multiple grid tiles. So if you want a lot of platforms that are 3 grid squares wide, you don't need 3 objects per platform, you can just use a single character to represent a 3x1 rect:

    import kaboom from "kaboom"
    
    // initialize context
    kaboom()
    
    // load assets
    loadSprite("bean", "sprites/bean.png")
    
    addLevel(
      // Note: the hyphens here hare just place holders to remind us that the
      // game objects created by ➁ and ➂ are actually taking up 2 and 3 grid
      // squares respectively.
      [
        "    ⚥                           ",
        "                                ",
        "            ➂--                 ",
        "                                ",
        "       ➁-                       ",
        "                                ",
        "                                ",
        "################################",
      ],
      {
        width: 32,
        height: 32,
        "⚥": () => [
            sprite("bean"),
            area(),
          body(),
          "player"
        ],
        "#": () => [
          rect(32, 32),
          outline(2),
          area(),
          solid(),
        ],
        "➁": () => [
          rect(32 * 2, 32),
          outline(2),
          area(),
          solid(),
        ],
        "➂": () => [
          rect(32 * 3, 32),
          outline(2),
          area(),
          solid(),
        ],
      }
    );
    
    const player = get("player")[0];
    
    player.onUpdate(() => {
      const left = isKeyDown('left') || isKeyDown('a');
      const right = isKeyDown('right') || isKeyDown('d');
      if (left && !right) {
        player.move(-500, 0);
      } else if (right && !left) {
        player.move(500, 0);
      }
      camPos(player.pos);
    });
    
    onKeyPress("space", () => {
      if (player.isGrounded()) {
        player.jump();
      }
    });
    

    Obviously if you had many different shapes and sizes this would be quite onerous.

    2. Advanced: Quad Trees and Loading/Unloading Regions

    I actually ran into this problem myself on a recent Kaboom project and decided to completely overhaul the built in addLevel() with my own implementation that loaded from a bitmap instead of a bunch of strings, and then organized the level data into a quadtree so that I could quickly find chunks that overlapped the visible area, and load and unload game objects based on their visibility. The technique and code are a bit to complex it include here, so I'll just link to the Repl and the relevant source code: level-loader.ts and lib-quad-tree.ts and the usage in level-one.js .