Table of Contents

I’d like to use some of Kenney’s sprites in my tutorials. He distributes them in separate PNG files, PNG spritesheets, SVG spritesheets, and SWF. I’d like to try the SVG spritesheets but the sprites are all put together into one big page and not separate out with <g> tags, so it’s not straightforward. I’m going to instead try using the PNG spritesheets.

I want to draw them in <canvas>:

#Map representation

The most convenient format for a tile map would be to have an array of strings, where each character corresponds to a different tile. That means I need a mapping from characters to tile data. I probably want that mapping to be manual so that the strings look good and are hand-editable. For example, “.” might be an open space and “X” might be a wall.

var map = [
    "          T ",
    "  T  //  ___",
    "  _______...",
    "__..........",
    "......***...",
    "........**..",
];

#Sprite rendering

I want some function for rendering a sprite based on spritesheet name and sprite name. That will look up the rectangle containing the sprite and then call canvas’s draw().

  • Some sprites should have their center point not at the top left, for rotation.
  • Most draw calls will have no rotation.

#Map editor

Click a tile on the palette, then click/drag to draw on the map. Import/export JSON. Bare bones. What about the mapping from character to tile?

#Spritesheet

Kenney includes spritesheets. Should I use those, or make my own? If I make my own (maybe using this library) I can mix and match sprites from different sets, and I also don’t need the page to load all the sprites I don’t use. I can fit 225 sprites onto one 2048x2048 spritesheet, and I think that’d be plenty for any of my tutorials. I’d read in a file like this:

[
   "Voxel pack (190 assets)/PNG/Tiles/": {
      '.': "dirt.png",
      "X": "stone.png",
      "_": ["grass.png", 16, 16],
   ]
]

and create a single spritesheet PNG file, along with a description:

var spritesheet = {
    url: "spritesheet_tiles.png",
    defaults: { width: 128, height: 128, cx: 0, cy: 0 },
    contents: {
        ' ': null,
        '.': {name: "dirt", x: 650, y: 130},
        '_': {name: "grass", x: 650, y: 0},
        "*": {name: "gravel_dirt", x: 520, y: 130},
        "T": {name: "mushroom_red", x: 390, y: 260},
        "/": {name: "grass1", x: 520, y: 650}
    }
};

There’s some up front work but it solves the character to spritesheet mapping, and simplifies the spritesheet management because there’s only one.

It’s also simple enough that I can do this manually until it becomes worth the effort to make a tool.

#Source data

Here’s spritesheet_tiles.png:

and here’s spritesheet_tiles.xml:

<TextureAtlas imagePath="sprites.png">
        <SubTexture name="brick_grey.png" x="0" y="0" width="128" height="128"/>
        <SubTexture name="brick_red.png" x="260" y="1560" width="128" height="128"/>
        <SubTexture name="cactus_inside.png" x="650" y="1040" width="128" height="128"/>
        <SubTexture name="cactus_side.png" x="650" y="910" width="128" height="128"/>
        <SubTexture name="cactus_top.png" x="650" y="780" width="128" height="128"/>
        <SubTexture name="cotton_blue.png" x="650" y="650" width="128" height="128"/>
        <SubTexture name="cotton_green.png" x="650" y="520" width="128" height="128"/>
        <SubTexture name="cotton_red.png" x="650" y="390" width="128" height="128"/>
        <SubTexture name="cotton_tan.png" x="650" y="260" width="128" height="128"/>
        <SubTexture name="dirt.png" x="650" y="130" width="128" height="128"/>
        <SubTexture name="dirt_grass.png" x="650" y="0" width="128" height="128"/>
        <SubTexture name="dirt_sand.png" x="520" y="1820" width="128" height="128"/>
        <SubTexture name="dirt_snow.png" x="520" y="1690" width="128" height="128"/>
        <SubTexture name="fence_stone.png" x="520" y="1560" width="128" height="128"/>
        <SubTexture name="fence_wood.png" x="520" y="1430" width="128" height="128"/>
        <SubTexture name="glass.png" x="520" y="1300" width="128" height="128"/>
        <SubTexture name="glass_frame.png" x="520" y="1170" width="128" height="128"/>
        <SubTexture name="grass1.png" x="520" y="650" width="128" height="128"/>
        <SubTexture name="grass2.png" x="520" y="520" width="128" height="128"/>
        <SubTexture name="grass3.png" x="520" y="390" width="128" height="128"/>
        <SubTexture name="grass4.png" x="520" y="260" width="128" height="128"/>
        <SubTexture name="grass_brown.png" x="520" y="1040" width="128" height="128"/>
        <SubTexture name="grass_tan.png" x="520" y="910" width="128" height="128"/>
        <SubTexture name="grass_top.png" x="520" y="780" width="128" height="128"/>
        <SubTexture name="gravel_dirt.png" x="520" y="130" width="128" height="128"/>
        <SubTexture name="gravel_stone.png" x="520" y="0" width="128" height="128"/>
        <SubTexture name="greysand.png" x="390" y="1820" width="128" height="128"/>
        <SubTexture name="greystone.png" x="390" y="1690" width="128" height="128"/>
        <SubTexture name="greystone_ruby.png" x="390" y="1560" width="128" height="128"/>
        <SubTexture name="greystone_ruby_alt.png" x="390" y="1430" width="128" height="128"/>
        <SubTexture name="greystone_sand.png" x="390" y="1300" width="128" height="128"/>
        <SubTexture name="ice.png" x="390" y="1170" width="128" height="128"/>
        <SubTexture name="lava.png" x="390" y="1040" width="128" height="128"/>
        <SubTexture name="leaves.png" x="390" y="910" width="128" height="128"/>
        <SubTexture name="leaves_orange.png" x="390" y="780" width="128" height="128"/>
        <SubTexture name="leaves_orange_transparent.png" x="390" y="650" width="128" height="128"/>
        <SubTexture name="leaves_transparent.png" x="390" y="520" width="128" height="128"/>
        <SubTexture name="mushroom_brown.png" x="390" y="390" width="128" height="128"/>
        <SubTexture name="mushroom_red.png" x="390" y="260" width="128" height="128"/>
        <SubTexture name="mushroom_tan.png" x="390" y="130" width="128" height="128"/>
        <SubTexture name="oven.png" x="390" y="0" width="128" height="128"/>
        <SubTexture name="redsand.png" x="260" y="1820" width="128" height="128"/>
        <SubTexture name="redstone.png" x="260" y="1690" width="128" height="128"/>
        <SubTexture name="redstone_emerald.png" x="650" y="1170" width="128" height="128"/>
        <SubTexture name="redstone_emerald_alt.png" x="260" y="1430" width="128" height="128"/>
        <SubTexture name="redstone_sand.png" x="260" y="1300" width="128" height="128"/>
        <SubTexture name="rock.png" x="260" y="1170" width="128" height="128"/>
        <SubTexture name="rock_moss.png" x="260" y="1040" width="128" height="128"/>
        <SubTexture name="sand.png" x="260" y="910" width="128" height="128"/>
        <SubTexture name="snow.png" x="260" y="780" width="128" height="128"/>
        <SubTexture name="stone.png" x="260" y="650" width="128" height="128"/>
        <SubTexture name="stone_browniron.png" x="260" y="520" width="128" height="128"/>
        <SubTexture name="stone_browniron_alt.png" x="260" y="390" width="128" height="128"/>
        <SubTexture name="stone_coal.png" x="260" y="260" width="128" height="128"/>
        <SubTexture name="stone_coal_alt.png" x="260" y="130" width="128" height="128"/>
        <SubTexture name="stone_diamond.png" x="260" y="0" width="128" height="128"/>
        <SubTexture name="stone_diamond_alt.png" x="130" y="1820" width="128" height="128"/>
        <SubTexture name="stone_dirt.png" x="130" y="1690" width="128" height="128"/>
        <SubTexture name="stone_gold.png" x="130" y="1560" width="128" height="128"/>
        <SubTexture name="stone_gold_alt.png" x="130" y="1430" width="128" height="128"/>
        <SubTexture name="stone_grass.png" x="130" y="1300" width="128" height="128"/>
        <SubTexture name="stone_iron.png" x="130" y="1170" width="128" height="128"/>
        <SubTexture name="stone_iron_alt.png" x="130" y="1040" width="128" height="128"/>
        <SubTexture name="stone_sand.png" x="130" y="910" width="128" height="128"/>
        <SubTexture name="stone_silver.png" x="130" y="780" width="128" height="128"/>
        <SubTexture name="stone_silver_alt.png" x="130" y="650" width="128" height="128"/>
        <SubTexture name="stone_snow.png" x="130" y="520" width="128" height="128"/>
        <SubTexture name="table.png" x="130" y="390" width="128" height="128"/>
        <SubTexture name="track_corner.png" x="130" y="260" width="128" height="128"/>
        <SubTexture name="track_corner_alt.png" x="130" y="130" width="128" height="128"/>
        <SubTexture name="track_straight.png" x="130" y="0" width="128" height="128"/>
        <SubTexture name="track_straight_alt.png" x="0" y="1820" width="128" height="128"/>
        <SubTexture name="trunk_bottom.png" x="0" y="1690" width="128" height="128"/>
        <SubTexture name="trunk_mid.png" x="0" y="1560" width="128" height="128"/>
        <SubTexture name="trunk_side.png" x="0" y="1430" width="128" height="128"/>
        <SubTexture name="trunk_top.png" x="0" y="1300" width="128" height="128"/>
        <SubTexture name="trunk_white_side.png" x="0" y="1170" width="128" height="128"/>
        <SubTexture name="trunk_white_top.png" x="0" y="1040" width="128" height="128"/>
        <SubTexture name="water.png" x="0" y="910" width="128" height="128"/>
        <SubTexture name="wheat_stage1.png" x="0" y="780" width="128" height="128"/>
        <SubTexture name="wheat_stage2.png" x="0" y="650" width="128" height="128"/>
        <SubTexture name="wheat_stage3.png" x="0" y="520" width="128" height="128"/>
        <SubTexture name="wheat_stage4.png" x="0" y="390" width="128" height="128"/>
        <SubTexture name="wood.png" x="0" y="260" width="128" height="128"/>
        <SubTexture name="wood_red.png" x="0" y="130" width="128" height="128"/>
</TextureAtlas>