Tiles can be drawn with multiple approaches, some of which will be discussed below.
Bitmap
is a simple container to draw one Tile
. It's the most basic type, but it should be used with caution, as each Bitmap creates a draw call.
TileGroup
allows you to batch-draw Tiles that share the same Texture
. You can adjust the tint, position, and transparency of each tile. This class can be used to draw static tiles, but it's not well suited for dynamic movement because it must be cleared and refilled when changes are made.
Pro Tip: With
@:privateAccess tileGroup.content
, you can access the underlyingTileLayerContent
instance, and perform advanced geometry operations beyond simple rectangles.
SpriteBatch
allows you to batch-render Tiles that share the same Texture
. Unlike TileGroup
, it updates data every frame and lets you control each SpriteElement
individually. Note that, by default, SpriteBatch does not handle the scale or rotation of SpriteElements; it must be enabled with the hasRotationScale
flag. The same applies to the update()
method of SpriteElement — it will only be called when the hasUpdate
flag is set.
h2d.SpriteBatch.BasicElement
demonstrates how to use the update()
method. This class also provides a basic simulation of gravity, friction, and velocity.
This example demonstrates how to draw tile layers from a Tiled export file in JSON format. It uses TileGroup
for static terrain, Bitmap
for a backdrop image, and SpriteBatch
for rendering moving sprites.
To recreate this example, place the following files — backdrop.png, bunnies.png, tiles.png, and tiles.json — in the resources (/res
) folder. These files are not included in the samples directory.
class Main extends hxd.App {
static function main() {
// embed the resources
hxd.Res.initEmbed();
new Main();
}
override private function init() {
super.init();
// Add backdrop Bitmap
var bitmap = new h2d.Bitmap(hxd.Res.backdrop.toTile(), s2d);
// parse Tiled json file
var mapData:TiledMapData = haxe.Json.parse(hxd.Res.tiles_json.entry.getText());
// get tile image (tiles.png) from resources
var tileImage = hxd.Res.tiles_png.toTile();
// create a TileGroup for fast tile rendering, attach to 2d scene
var group = new h2d.TileGroup(tileImage, s2d);
var tw = mapData.tilewidth;
var th = mapData.tileheight;
var mw = mapData.width;
var mh = mapData.height;
// make sub tiles from tile
var tiles = [
for(y in 0 ... Std.int(tileImage.height / th))
for(x in 0 ... Std.int(tileImage.width / tw))
tileImage.sub(x * tw, y * th, tw, th)
];
// iterate on all layers
for(layer in mapData.layers) {
// iterate on x and y
for(y in 0 ... mh) for (x in 0 ... mw) {
// get the tile id at the current position
var tid = layer.data[x + y * mw];
if (tid != 0) { // skip transparent tiles
// add a tile to the TileGroup
group.add(x * tw, y * th, tiles[tid - 1]);
}
}
}
// Create raining bunnies with SpriteBatch
var bunnies = hxd.Res.bunnies.toTile();
var batch = new h2d.SpriteBatch(bunnies, s2d);
batch.hasRotationScale = true;
batch.hasUpdate = true;
// Note: Does not count as a bunnymark.
for (i in 0...100) {
var bunny = new Bunny(bunnies);
batch.add(bunny);
bunny.reset();
}
}
}
class Bunny extends h2d.SpriteBatch.BasicElement {
public function new(t:h2d.Tile) {
super(t);
gravity = 100;
}
public function reset() {
y = -t.height;
x = Math.random() * (batch.getScene().width - t.width);
scale = 1 + (Math.random() - 0.5) * .1;
vx = Math.random() * 60;
}
override function update(dt:Float) {
super.update(dt);
if (y > batch.getScene().height) reset();
return true;
}
}
// simple type definition for Tile map
typedef TiledMapData = { layers:Array<{ data:Array<Int>}>, tilewidth:Int, tileheight:Int, width:Int, height:Int };