Hi
I noticed with interest that Cocos2D had gained TMX map format support,
although it still lacks some features. At the same time I happen to
discover https://github.com/bitcraft/PyTMX which appears to be a pretty
complete python library for loading TMX files.
PyTMX list it features as:
Loads data and "properties" metadata from Tile's TMX format
"Properties" for: maps, tilesets, layers, objectgroups, objects, and tiles
Point data for polygon and polyline objects
Automatic flipping and rotation of tiles
Supports base64, csv, gzip, zlib and uncompressed XML
Image loading with pygame
It is made with Pygame in mind, but the TMX map loading code does not have
any dependency on Pygame and is cleanly separated from the image loading
and manipulation code.
For fun I made a quick proof of concept where I plugged PyTMX into Cocos2D
with what I believe is the same functionality as the existing TMX loading.
I've attached a patch with the code in case it could be interesting to look
at. It uses the following files from PyTMX:
constants.py
pytmx.py
utils.py
Regards,
Hogne
--
You received this message because you are subscribed to the Google Groups
"cocos2d discuss" group.
To view this discussion on the web visit
https://groups.google.com/d/msg/cocos-discuss/-/YMTWNVCoOZwJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/cocos-discuss?hl=en.
--- tiles.py.orig 2012-07-14 22:46:09.477427804 +0200
+++ tiles.py 2012-07-15 01:09:19.832906713 +0200
@@ -56,6 +56,9 @@
from cocos.director import director
from cocos.rect import Rect
+import pytmx.pytmx
+import itertools
+
# Implement these classes for backwards compatibility; some older code
# expects ScrollableLayer and ScrollingManager to be in the tiles module.
from cocos import layer
@@ -227,74 +230,47 @@
return resource
def load_tmx(filename):
- '''Load some tile mapping resources from a TMX file.
+ '''Load some tile mapping resources from a TMX file
+ using pytmx
'''
resource = Resource(filename)
+
+ tmxdata = pytmx.TiledMap(filename)
- tree = ElementTree.parse(resource.path)
- map = tree.getroot()
- if map.tag != 'map':
- raise ResourceError('document is <%s> instead of <map>'%
- map.name)
-
- width = int(map.attrib['width'])
- height = int(map.attrib['height'])
+ width = tmxdata.width
+ height = tmxdata.height
# XXX this is ASSUMED to be consistent
- tile_width = int(map.attrib['tilewidth'])
- tile_height = int(map.attrib['tileheight'])
+ tile_width = tmxdata.tileheight
+ tile_height = tmxdata.tileheight
# load all the tilesets
tilesets = []
- for tag in map.findall('tileset'):
- if 'source' in tag.attrib:
- firstgid = int(tag.attrib['firstgid'])
- path = resource.find_file(tag.attrib['source'])
- with open(path) as f:
- tag = ElementTree.fromstring(f.read())
- else:
- firstgid = int(tag.attrib['firstgid'])
-
- name = tag.attrib['name']
-
- for c in tag.getchildren():
- if c.tag == "image":
- # create a tileset from the image atlas
- path = resource.find_file(c.attrib['source'])
- tileset = TileSet.from_atlas(name, firstgid, path, tile_width, tile_height)
- # TODO consider adding the individual tiles to the resource?
- tilesets.append(tileset)
- resource.add_resource(name, tileset)
- elif c.tag == 'tile':
- # add properties to tiles in the tileset
- gid = tileset.firstgid + int(c.attrib['id'])
- tile = tileset[gid]
- props = c.find('properties')
- if props is None:
- continue
- for p in props.findall('property'):
- # store additional properties.
- name = p.attrib['name']
- value = p.attrib['value']
- # TODO consider more type conversions?
- if value.isdigit():
- value = int(value)
- tile.properties[name] = value
+
+ for tmx_tileset in tmxdata.tilesets:
+ path = tmx_tileset.source
+ firstgid = tmx_tileset.firstgid
+ name = tmx_tileset.name
+
+ # Not used yet
+ tile_margin = tmx_tileset.margin
+ tile_spacing = tmx_tileset.spacing
+
+ tileset = TileSet.from_atlas(name, firstgid, path, tile_width, tile_height, tmxdata.tile_properties)
+
+ # TODO consider adding the individual tiles to the resource?
+ tilesets.append(tileset)
+ resource.add_resource(name, tileset)
# now load all the layers
- for layer in map.findall('layer'):
- data = layer.find('data')
- if data is None:
- raise ValueError('layer %s does not contain <data>' % layer.name)
-
- data = data.text.strip()
- data = data.decode('base64').decode('zlib')
- data = struct.unpack('<%di' % (len(data)/4,), data)
- assert len(data) == width * height
+ for layer in tmxdata.tilelayers:
+ # Convert pytmx layer data array of arrays
+ # to a flat tuple as cocos expects
+ layer_data = tuple(itertools.chain(*layer.data))
cells = [[None] * height for x in range(width)]
- for n, gid in enumerate(data):
- if gid < 1:
+ for n, gid in enumerate(layer_data):
+ if gid < firstgid:
tile = None
else:
# UGH
@@ -306,10 +282,10 @@
j = height - (n // width + 1)
cells[i][j] = RectCell(i, j, tile_width, tile_height, {}, tile)
- id = layer.attrib['name']
+ id = layer.name
m = RectMapLayer(id, tile_width, tile_height, cells, None, {})
- m.visible = int(layer.attrib.get('visible', 1))
+ m.visible = int(layer.visible)
resource.add_resource(id, m)
@@ -490,7 +466,7 @@
return self[id]
@classmethod
- def from_atlas(cls, name, firstgid, file, tile_width, tile_height):
+ def from_atlas(cls, name, firstgid, file, tile_width, tile_height, tile_props = None):
image = pyglet.image.load(file)
rows = image.height / tile_height
columns = image.width / tile_width
@@ -499,9 +475,17 @@
id = firstgid
ts = cls(name, {})
ts.firstgid = firstgid
+
for j in range(rows-1, -1, -1):
for i in range(columns):
- ts[id] = Tile(id, {}, atlas[j, i])
+ if tile_props:
+ if id in tile_props:
+ props = tile_props[id]
+ else:
+ props = {}
+ else:
+ props = {}
+ ts[id] = Tile(id, props, atlas[j, i])
id += 1
return ts