Drawing tiles
Tiles can be drawn with multiple approaches, some of which going to be covered by following example.
h2d.Bitmap
Bitmap
is a simple container to draw one Tile
. It’s the most basic type, but should be used with caution, as each Bitmap
causes a draw call.
h2d.TileGroup
TileGroup
allows to batch-draw Tiles beloning to same Texture
with ability to apply individual tint, transform and alpha to each tile. This class can be used to draw static tiles, but not very well suited for dynamic movement, since it should be cleared and refilled with data each time something should be altered.
TileGroup hacking
With @:privateAccess tileGroup.content
it’s possible to access underlying TileLayerContent
instance and do more fine-tuned geometry operations other than simple rectangles.
h2d.SpriteBatch
SpriteBatch
allows to batch-render Tiles belonging to same Texture
, but contrary to TileGroup
, it updates batch data each frame and allows to control each SpriteElement
individually. Note that by default SpriteBatch does not utilize scale and rotation of SpriteElements and it should be enabled with hasRotationScale
flag. Same applies to update
method of SpriteElement - it will be called only when hasUpdate
flag is set.
BasicElement and updates
h2d.SpriteBatch.BasicElement
is a good example of how update
method can be utilized. This class provides simple simulation of gravity, friction and velocity.
Sample
This example draws tile layers from a Tiled export file (json) using TileGroup
batching, Bitmap
for backdrop image and SpriteBatch
for batch-rendering of moving sprites.
The example uses a backdrop.png, bunnies.png, tiles.json and tiles.png files, that should be put in the resources (/res
) folder. Those files are not included in 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 * mapData.tilewidth, tiles[tid - 1]);
}
}
}
// Create raining bunnies with SpriteBatch
var bunnies = hxd.Res.bunnies.toTile();
var batch = new h2d.SpriteBatch(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.SimpleElement {
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 };