Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added typed properties support and properties for TileMap and Layer #3

Merged
merged 7 commits into from
May 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [next]

* Added typed properties support and properties for TileMap and Layer

## 0.3.0

* `Layer` using 2d list store layer's `_tiles`,useful for get tile by coordinate `x,y`
Expand Down
4 changes: 4 additions & 0 deletions lib/src/layer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Layer {
int height;
bool visible;

Map<String, dynamic> properties = {};

TileMap map;
List<List<int>> tileMatrix;

Expand Down Expand Up @@ -49,6 +51,8 @@ class Layer {

assembleTileMatrix(inflatedString);
}

properties = TileMapParser._parsePropertiesFromElement(element);
}

// TMX data format documented here: https://github.com/bjorn/tiled/wiki/TMX-Map-Format#data
Expand Down
17 changes: 11 additions & 6 deletions lib/src/object_group.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ class ObjectGroup {

TileMap map;

Map<String, String> properties = {};
Map<String, dynamic> properties = {};
List<TmxObject> tmxObjects = [];

ObjectGroup.fromXML(XmlElement element) {
if (element == null) { throw 'arg "element" cannot be null'; }
if (element == null) {
throw 'arg "element" cannot be null';
}

NodeDSL.on(element, (dsl) {
name = dsl.strOr('name', name);
Expand All @@ -22,12 +24,15 @@ class ObjectGroup {
visible = dsl.boolOr('visible', visible);
});

properties = TileMapParser._parseProperties(TileMapParser._getPropertyNodes(element));
properties = TileMapParser._parsePropertiesFromElement(element);

var objectNodes = element.children
.where((node) => node is XmlElement)
.where((node) => (node as XmlElement).name.local == 'object');
tmxObjects = objectNodes.map((objectNode)
=> new TmxObject.fromXML(objectNode)).toList();
.cast<XmlElement>()
.where((node) => node.name.local == 'object');

tmxObjects = objectNodes
.map((objectNode) => new TmxObject.fromXML(objectNode))
.toList();
}
}
6 changes: 3 additions & 3 deletions lib/src/tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ class Tile {
margin = tileset.margin;
gid = tileId + tileset.firstgid;
properties = tileset.tileProperties[gid];
if (properties == null) {
properties = {};
}

properties ??= {};

_image = tileset.tileImage[gid];
}

Expand Down
17 changes: 12 additions & 5 deletions lib/src/tile_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class TileMap {
List<Tileset> tilesets = new List<Tileset>();
List<Layer> layers = new List<Layer>();
List<ObjectGroup> objectGroups = [];
Map<String, dynamic> properties = {};

/**
* Retrieve a tile based on its GID
Expand All @@ -20,16 +21,17 @@ class TileMap {
* A GID of 0 is always an "empty" tile
*/
Tile getTileByGID(int gid) {
if (gid == 0) { return new Tile.emptyTile(); }
if (gid == 0) {
return new Tile.emptyTile();
}
var ts = tilesets.lastWhere((tileset) => tileset.firstgid <= gid);
return new Tile(gid - ts.firstgid, ts);
}

// Returns a tileset based on its name
Tileset getTileset(String name) {
return tilesets.firstWhere((tileset) => tileset.name == name,
orElse: () => throw new ArgumentError('Tileset $name not found')
);
orElse: () => throw new ArgumentError('Tileset $name not found'));
}

/**
Expand All @@ -54,11 +56,16 @@ class TileMap {
*/
Tile getTileByPhrase(String tilePhrase) {
var split = tilePhrase.split('|');
if (split.length != 2) { throw new ArgumentError("$tilePhrase not in the format of 'TilesetName|LocalTileID"); }
if (split.length != 2) {
throw new ArgumentError(
'$tilePhrase not in the format of "TilesetName|LocalTileID"',
);
}

var tilesetName = split.first;
var tileId = int.parse(split.last,
onError: (src) => throw new ArgumentError('Local tile ID $src is not an integer.') );
onError: (src) =>
throw new ArgumentError('Local tile ID $src is not an integer.'));

return getTileByLocalID(tilesetName, tileId);
}
Expand Down
66 changes: 48 additions & 18 deletions lib/src/tile_map_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ class TileMapParser {
TileMapParser();

TileMap parse(String xml, {TsxProvider tsx}) {

var xmlElement = _parseXml(xml).rootElement;

if (xmlElement.name.local != 'map') {
Expand All @@ -17,12 +16,11 @@ class TileMapParser {
map.width = int.parse(xmlElement.getAttribute('width'));
map.height = int.parse(xmlElement.getAttribute('height'));

xmlElement.children.where((node) => node is XmlNode).forEach( (XmlNode node) {
if (!(node is XmlElement)) {
return;
}
var element = node as XmlElement;
switch(element.name.local) {
xmlElement.children
.where((node) => node is XmlElement)
.cast<XmlElement>()
.forEach((XmlElement element) {
switch (element.name.local) {
case 'tileset':
map.tilesets.add(new Tileset.fromXML(element, tsx: tsx)..map = map);
break;
Expand All @@ -35,19 +33,49 @@ class TileMapParser {
}
});

map.properties = TileMapParser._parsePropertiesFromElement(xmlElement);

return map;
}

static Image _parseImage(XmlElement node) {
var attrs = node.getAttribute;
return new Image(attrs('source'), int.parse(attrs('width')), int.parse(attrs('height')));

return new Image(
attrs('source'),
int.parse(attrs('width')),
int.parse(attrs('height')),
);
}

static Map<String, dynamic> _parsePropertiesFromElement(XmlElement element) {
return TileMapParser._parseProperties(
TileMapParser._getPropertyNodes(element),
);
}

static Map<String, String> _parseProperties(nodes) {
var map = new Map<String, String>();
nodes.forEach( (property) {
var attrs = property.getAttribute;
map[attrs('name')] = attrs('value');
static Map<String, dynamic> _parseProperties(nodes) {
final map = <String, dynamic>{};

nodes.forEach((property) {
final attrs = property.getAttribute;
final value = attrs('value');
final name = attrs('name');

switch (attrs('type')) {
case 'bool':
map[name] = value == 'true';
break;
case 'int':
map[name] = int.parse(value);
break;
case 'float':
map[name] = double.parse(value);
break;
default: // for types file, color (returns ARGB), string
map[name] = value;
break;
}
});

return map;
Expand All @@ -67,8 +95,11 @@ class TileMapParser {
static Iterable<XmlElement> _getPropertyNodes(XmlElement node) {
var propertyNode = node.children
.where((node) => node is XmlElement)
luanpotter marked this conversation as resolved.
Show resolved Hide resolved
.firstWhere((node) => (node as XmlElement).name.local == 'properties', orElse: () => null) as XmlElement;
if (propertyNode == null) { return []; }
.cast<XmlElement>()
.firstWhere((element) => element.name.local == 'properties', orElse: () => null);
if (propertyNode == null) {
return [];
}
return propertyNode.findElements('property');
}

Expand All @@ -83,17 +114,16 @@ class TileMapParser {
}

static Function _getDecoder(String encodingType) {
switch(encodingType) {
switch (encodingType) {
case 'base64':
return _decodeBase64;
default:
throw 'Incompatible encoding found: $encodingType';
}

}

static Function _getDecompressor(String compressionType) {
switch(compressionType) {
switch (compressionType) {
case 'zlib':
return new ZLibDecoder().decodeBytes;
case 'gzip':
Expand Down
10 changes: 4 additions & 6 deletions lib/src/tileset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class Tileset {

Image image;
List<Image> images = new List<Image>();
Map<String, String> properties = new Map<String, String>();
Map<int, Map<String, String>> tileProperties = new Map();
Map<String, dynamic> properties = {};
Map<int, Map<String, dynamic>> tileProperties = {};
Map<int, Image> tileImage = new Map();

Tileset(this.firstgid);
Expand All @@ -27,15 +27,13 @@ class Tileset {
image = _findImage(element);
_addImage(image);

properties = TileMapParser._parseProperties(
TileMapParser._getPropertyNodes(element));
properties = TileMapParser._parsePropertiesFromElement(element);

// Parse tile properties, if present.
element.findElements('tile').forEach((XmlElement tileNode) {
int tileId = int.parse(tileNode.getAttribute('id'));
int tileGid = tileId + firstgid;
tileProperties[tileGid] = TileMapParser._parseProperties(
TileMapParser._getPropertyNodes(tileNode));
tileProperties[tileGid] = TileMapParser._parsePropertiesFromElement(tileNode);
var image = _findImage(tileNode);
tileImage[tileGid] = image;
_addImage(image);
Expand Down
15 changes: 8 additions & 7 deletions lib/src/tmx_object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ class TmxObject {
bool isPolyline = false;

List<Point> points = [];
Map<String, String> properties = {};

Map<String, dynamic> properties = {};

TmxObject.fromXML(XmlElement element) {
if (element == null) { throw 'arg "element" cannot be null'; }
if (element == null) {
throw 'arg "element" cannot be null';
}

NodeDSL.on(element, (dsl) {
name = dsl.strOr('name', name);
Expand All @@ -36,19 +37,19 @@ class TmxObject {
visible = dsl.boolOr('visible', visible);
});

properties = TileMapParser._parseProperties(TileMapParser._getPropertyNodes(element));
properties = TileMapParser._parsePropertiesFromElement(element);

// TODO: it is implied by the spec that there are only two children to
// an object node: an optional <properties /> and an optional <ellipse />,
// <polygon />, or <polyline />
var xmlElements = element.children
.where((node) => node is XmlElement)
.where((node) => (node as XmlElement).name.local != 'properties');
.where((node) => node is XmlElement)
.where((node) => (node as XmlElement).name.local != 'properties');

if (xmlElements.length > 0) {
var node = xmlElements.first as XmlElement;

switch(node.name.local) {
switch (node.name.local) {
case 'ellipse':
isEllipse = true;
break;
Expand Down