Hi @player_03, thank you for the feedback! At the risk of going over this ad nauseum, we’ve been discussing this on Slack, and I think that we might be getting closer to a good implementation.
I think we need to consider the simple “fire and go” approach, somewhat like the addBitmapData
sample you have. I think that we also need to consider the mental process one might go through when building a Tilemap
. I think that Tileset
is one example of this – on the mental road, Tileset
is where you might begin, with “I have a set of tiles, I need to define their coordinates in the larger whole” and flow from there.
TilemapData
I have another implementation that more closely emulates Bitmap
/BitmapData
, and may consider all the points we’re raising.
Tilemap
(similar to Bitmap
) is pretty simple.
class Tilemap extends DisplayObject {
public var pixelSnapping:PixelSnapping;
public var smoothing:Bool;
public var tilemapData (default, set):TilemapData;
public function new (tilemapData:TilemapData = null, pixelSnapping:PixelSnapping = AUTO, smoothing:Bool = false);
}
The real logic follows in TilemapData
class TilemapData {
public var height (default, null):Int;
public var numTiles (default, null):Int;
public var tileset:Tileset;
public var width (default, null):Int;
public function new (width:Int, height:Int, tileset:Tileset = null);
public function addTile (tile:Tile):Tile;
public function addTiles (tiles:Array<Tile>):Array<Tile>;
public function addTileAt (tile:Tile, index:Int):Tile;
public function contains (tile:Tile):Bool;
public function getTileAt (index:Int):Tile;
public function getTileIndex (tile:Tile):Int;
public function removeTile (tile:Tile):Tile;
public function removeTileAt (index:Int):Tile;
public function removeTiles (beginIndex:Int = 0, endIndex:Int = 0x7fffffff):Void;
}
There are no layers, it is flat. We can use the display list to layer multiple tilemaps, or you can layer virtually and flatten when you get here. Unlike the previous approaches, note that the width
and height
are specific to TilemapData
, not Tilemap
You could use it in a compact form:
var tilemap = new Tilemap (new TilemapData (800, 600));
or you can set a default tileset
value:
var tilemapData = new TilemapData (800, 600, tileset);
var tilemap = new Tilemap (tilemapData);
This is what the Tileset
object looks like right now. I agree, I think that this could grow to support more data per tile if we need it (like center points), as well as automation for images that use consistent width and height per tile, with spacing.
class Tileset {
public var bitmapData (default, set):BitmapData;
public function new (bitmapData:BitmapData, rects:Array<Rectangle> = null);
public function addRect (rect:Rectangle):Int;
public function getRect (id:Int):Rectangle;
}
If you have a default tileset, then you do not need to define “tileset” per tile, you can define only the ID value. If you specifically add a tileset
value to a Tile
, you can use multiple tilesets in one map, but you can see that it’s more convenient to use one tileset
for the whole thing.
var tileset = new Tileset (Assets.getBitmapData ("tiles.png"), [ new Rectangle (0, 0, 100, 100) ]);
var tilemapData = new TilemapData (800, 600, tileset);
var tilemap = new Tilemap (tilemapData);
tilemapData.addTile (new Tile (0));
tilemapData.addTile (new Tile (0, 100, 100));
addChild (tilemap);
The alternative option is to not use a default tileset, and to define one per tile. This is supported, but is clearly not as simple to write as using only one tileset, so both use-cases are handled, while the single tileset approach is preferred by convention, I believe:
var tileset = new Tileset (Assets.getBitmapData ("tiles.png"));
tileset.addRect (new Rectangle (0, 0, 100, 100));
var tileset2 = new Tileset (Assets.getBItmapData ("tiles2.png"),
tileset2.addRect (new Rectangle (0, 0, 100, 100));
var tilemapData = new TilemapData (800, 600);
var tilemap = new Tilemap (tilemapData);
var tile = new Tile (0);
tile.tileset = tileset;
var tile2 = new Tile (0, 100, 100);
tile2.tileset = tileset2;
tilemapData.addTile (tile);
tilemapData.addTile (tile2);
addChild (tilemap);
For reference, this is what the Tile
type looks like
class Tile {
public var data:Dynamic;
public var id (default, set):Int;
public var matrix:Matrix;
public var rotation (get, set):Float;
public var scaleX (get, set):Float;
public var scaleY (get, set):Float;
public var tileset (default, set):Tileset;
public var x (get, set):Float;
public var y (get, set):Float;
public function new (id:Int = 0, x:Float = 0, y:Float = 0, scaleX:Float = 1, scaleY:Float = 1, rotation:Float = 0);
}