ondras / rot.js

ROguelike Toolkit in JavaScript. Cool dungeon-related stuff, interactive manual, documentation, tests!
https://ondras.github.io/rot.js/hp/
BSD 3-Clause "New" or "Revised" License
2.33k stars 254 forks source link

[Question] Is there a way to use two different tilesets? #163

Open Gerhard-Wonner opened 5 years ago

Gerhard-Wonner commented 5 years ago

[Question] Is there a way to use two different tilesets? E.g. one PNG for the dungeon tiles as background and one animated GIF for the characters in the foreground? By the way, thank you for creating this amazing engine! :-)

ondras commented 5 years ago

Hi @Gerhard-Wonner,

no. Only one tileset is supported; also please note that animated GIFs are not really possible because there is no straightforward way (in client-side JS) to access individual animation frames.

I would suggest storing your animated GIF as a spritesheet instead, using a setTimeout-based loop to draw individual frames.

Gerhard-Wonner commented 5 years ago

Hi @ondras, thank you for your helpful answer! 👍

eScribMac commented 4 years ago

@ondras would you be interested in a PR to support multiple tilesets?

ondras commented 4 years ago

Hi @eScribMac,

would you please elaborate a bit on this feature? What is its purpose, what problems does it solve, what API would you propose etc? Is there any prior art for this?

eScribMac commented 4 years ago

I am currently using a PNG tilesheet collection that I found online. It comes broken into different files for the environment tiles, characters, monsters, etc. There are 12 files in total. I could combine these files in an image editor, but it would be tedious and finding in the coordinates on such a large image would be tedious as well.

For the API, my suggestion would be to maintain backwards compatibility but behave differently if the tileMap property is a collection of some kind rather than a DOM element. For example (modified from the docs):

var floorTileSet = document.createElement("img");
floorTileSet.src = "floorTiles.png";
var monsterTileSet = document.createElement("img");
monsterTileSet.src = "monsterTiles.png";

var options = {
    layout: "tile",
    bg: "transparent",
    tileWidth: 64,
    tileHeight: 64,
    tileSet: {floor: floorTileSet, monsters: monsterTileSet},
    tileMap: {
        "@": ['monsters', 0, 0],
        "#": ['floor', 0, 64],
        ".": ['floor', 64, 0],
        "P": ['monsters', 64, 64]
    },
    width: 30,
    height: 30
}

I'm open to suggestions for a more ergonomic way to identify which tilesheet is being used in tileMap.

I'm not aware of any prior art in particular - I know libtcod only supports a single font sheet, for example.

ondras commented 4 years ago

I am currently using a PNG tilesheet collection that I found online. It comes broken into different files for the environment tiles, characters, monsters, etc. There are 12 files in total. I could combine these files in an image editor, but it would be tedious and finding in the coordinates on such a large image would be tedious as well.

I see. Well, the feature itself makes sense.

I also see some issues with the outlined approach when using the WebGL tile renderer. Individual tile sets would have to be loaded as WebGL textures and my limited WebGL experience tells me that the number of simultaneously active textures is limited, so we would have to find a way to somehow juggle texturing units during the draw calls.

However, I have an idea to solve the problem in a different manner:

let tileSet = {floor: floorTileSet, monsters: monsterTileSet};
let tileMap = {
    "@": ['monsters', 0, 0],
    "#": ['floor', 0, 64],
    ".": ['floor', 64, 0],
    "P": ['monsters', 64, 64]
}

[tileSet, tileMap] = mergeTileSets(tileSet, tileMap);
let options = { tileSet, tileMap };

So the user will still have multiple tileSet images, but we will provide a pre-processing method that will merge these images into one, offsetting the tileMap indices and creating a merged tileMap as well. The current Tile renderer will still accept only one tileSet. What do you think?

mreinstein commented 4 years ago

It sounds like the use cases described here center around manipulating sprites/spritesheets.

There are a lot of tools around spritesheet handling already, for example: https://www.codeandweb.com/texturepacker

In the interests of keeping the rot.js core small, it might make sense to rely on these external tools to do the tedious work, rather than mixing this in.