pythonarcade / pytiled_parser Goto Github PK
View Code? Open in Web Editor NEWPython Library for parsing Tiled Map Editor maps.
License: MIT License
Python Library for parsing Tiled Map Editor maps.
License: MIT License
On page: https://pytiled-parser.readthedocs.io/en/latest/
Link "Games using the Arcade library" leads to not existing page.
A very very small amount of work has been done on adding a programming guide to the docs. This should cover the general intended use of pytiled-parser, loading a map, extracting image data for tiles, etc. A lot of the will be conceptual, we can probably pull bits of code from the Arcade implementation of pytiled-parser for this. Exactly what should be included still needs worked through.
Currently, if we have a hitbox defined as a polygon:
<object id="1" x="128" y="0">
<polygon points="0,0 -118.364,0.0909091 -127.818,9.54545 -127.818,62.1818 -116.909,73.8182 -0.181818,74.1818"/>
</object>
pytiled will pull the object info, but not the polygon points.
Properties of tiles in tilesets are handled differently than properties in maps. According to the documentation the properties tag is the same as in all other places. Therefore I suggest using _parse_properties_element there as well.
There are a number of examples of the Tiled editor not following what appears to be documented in the TMX reference docs.
This is problematic for this project. If we follow the spec to the letter, then in some cases the code won't run (if an attribute or element is absent when it should be present according to the docs) or users will be confused (Tiled outputs something different than what we expect)
Decisions regarding this will need to be made on a case-by-case basis. Some of these examples are fairly minor, but some are more serious.
The most important thing is to document clearly and publicly where these contradictions exist, to reduce mistakes when developing on and against the API.
Examples will be created as separate issues and referenced back to this issue for posterity.
I'm looking forward to a release that includes reading polygon points. Unfortunately the latest available on pypi doesn't include this feature. Would it be possible to have a new release?
If you set parallaxx
on a layer but not parallaxy
, then parallaxy
is not set in the file.
Currently pytiled-parser assumes if one is set then the other is.
Relevant Arcade issue: pythonarcade/arcade#1001
Object templates are separate files which store a template that can be applied to an object which specifies itself as an instance of that template.
See: https://doc.mapeditor.org/en/stable/reference/json-map-format/#object-template
https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#object says:
rotation: The rotation of the object in degrees clockwise around (x, y) (defaults to 0).
This is inaccurate. By default, the rotation
attribute is absent for ALL object types.
This is a relatively minor issue, but a decision must be made as to assign a rotation value of 0
to all objects that lack a rotation
attribute, or to set it to None
.
This needs verified, but I stumbled upon it in the Tiled issues: mapeditor/tiled#2764
Funny enough, I had considered this possibility myself when working through testing scenarios, but figured there was no way that something like this would be the case.
Let this be a lesson to me to never assume.
A big part of the re-work for 2.0 was separating parsing from the API definition. This is what enabled support for TMX to come in 2.0, but also was the foundation for being able to save maps.
This isn’t a super straight forward process, as we do a lot of normalizing/converting of data as it’s loaded in, so it’s not quite as simple as “just dump the JSON back to a file”, especially when it comes to the TMX format.
We basically need to reverse the parsing process in order to do this. The goal for 2.1 is to have this for the JSON, with ability to save TMX/TSX likely to follow in a 2.2 release, however depending on how this turns out we could see both in 2.1.
If all of the other desired features are good and JSON serialization is done then we’ll probably save TMX serialization for 2.2, as that process is definitely going to be a bit more involved than JSON.
When you try to parse something like a text object, the text specific objects do not get put into the resulting tiled object. Was this on purpose or is it something you can implement because this would be a lifesaving feature to me.
My understanding for Python is the standard way to see if keys are in dictionaries is to do:
if my_key in my_dictionary:
pytiled tends to just try it, and catch the error if it occurs. I'm not sure about Python, but exception handling in languages like Java is slower than using if
statements. Also, I'm now debugging an exception that occurs in the except
section of one of these, and the debugging takes longer having to juggle understanding two exceptions rather than the one that matters.
I'd recommend using the if
method. (I have seen places where the try
method is recommended, so...right.)
I get the error:
tiles[id_] = objects.Tile(
id_=id_,
type_=_type,
> terrain=terrain,
animation=animation,
image=image,
properties=properties,
tileset=None,
)
E UnboundLocalError: local variable 'terrain' referenced before assignment
..\..\..\pytiled_parser\pytiled_parser\xml_parser.py:542: UnboundLocalError
Docs are currently being re-worked and using mkdocs. The autogenerated API docs are also being re-done as part of this. Currently the docstrings themselves are about half way to being done I’d say.
The setup within mkdocs definitely still needs some more work.
Still need to do some experimentation and testing out different methods for this to see what works best.
Currently TileSet parsing is a fairly internal function not intended for general consumption, while it is possible to use, it's not necessarily designed for it.
There are valid use-cases where a user may want to just parse a TileSet and not a full map, and PyTiled Parser's API doesn't lend itself well to doing that.
Hi.
While trying out this module, I've encountered following beheviour:
I used Tiled v 1.3.1 to create tmx file with 3 layers image, tiles and objects. In objects layer, I've added rotated elipses.
As you can see bellow, object_element.attrib["rotation"] can be float-based string, which fails to convert to int.
Simply changing 'int' typecast to 'float' fixed this issue for me.
Code:
import pytiled_parser
x=pytiled_parser.parse_tile_map('heightmapped01.tmx')
ValueError Traceback (most recent call last)
in
----> 1 x=pytiled_parser.parse_tile_map('heightmapped01.tmx')
~/PycharmProjects/SocialAgents/venv/lib/python3.6/site-packages/pytiled_parser/xml_parser.py in parse_tile_map(tmx_file)
891 tile_sets = _get_tile_sets(map_element, parent_dir)
892
--> 893 layers = _get_layers(map_element)
894
895 tile_map = objects.TileMap(
~/PycharmProjects/SocialAgents/venv/lib/python3.6/site-packages/pytiled_parser/xml_parser.py in _get_layers(map_element)
437 layer_parser = _get_layer_parser(element.tag)
438 if layer_parser:
--> 439 layers.append(layer_parser(element))
440
441 return layers
~/PycharmProjects/SocialAgents/venv/lib/python3.6/site-packages/pytiled_parser/xml_parser.py in parse_object_layer(element)
346 id, name, offset, opacity, properties = _parse_layer(element)
347
--> 348 tiled_objects = _parse_objects(element.findall("./object"))
349
350 color = None
~/PycharmProjects/SocialAgents/venv/lib/python3.6/site-packages/pytiled_parser/xml_parser.py in _parse_objects(object_elements)
310
311 try:
--> 312 tiled_object.rotation = int(object_element.attrib["rotation"])
313 except KeyError:
314 pass
ValueError: invalid literal for int() with base 10: '-44.5153'
Wang sets are currently like half-way implemented(not in any way that is exposed to user's however). Would be nice to finish this up, and also some changes have been made to the Wang sets as of Version 1.5 of Tiled.
See:
https://doc.mapeditor.org/en/stable/reference/json-map-format/#wang-set
https://doc.mapeditor.org/en/stable/reference/json-map-format/#tiled-1-5
As of Tiled 1.6 they have changed the type of the version
key to be a string rather than a number. Need to investigate what problems, if any, this might cause for us.
See: https://doc.mapeditor.org/en/stable/reference/json-map-format/#tiled-1-6
When loading a map that uses external tilesets, there is no way to get to their filenames or locations.
In my project for example, I reference other files in properties of tiles. Without the directory of the tileset I cannot find these files, as the path's are relative
Tile objects do not load properly when loaded from a template. This is because when it comes to templates, the tileset is defined at the template level, and not the map level.
In order to support proper loading of them, the tileset needs to be added into the map object, and have it's firstgid adjusted to work with the rest of the map.
This was found in the Arcade library via pythonarcade/arcade#919
In order to fix this, the map object will need created before the layers are processed, it's hard to say at this point how exactly that will look.
Running "make dist" on Windows creates an empty distribution that is only 2k large and doesn't include any source files.
Would be nice to be able to load in multiple maps within a World from a .world
file.
This feature is described more in depth at https://doc.mapeditor.org/en/stable/manual/worlds/
One of the possible file-types that Tiled supports is z standard. This is easy if the zstd library is loaded. But I hate putting it in as a 'required' dependency if it isn't being used. I'd suggest an optional load if the needed. See here:
As reported in pythonarcade/arcade#955 when an infinite map is loaded, the data is stored differently using chunks as opposed to the normal data
array you would see in a finite map.
The proposed fix is to automatically create that array for infinite maps, as most games/engines would exclusively be working with finite maps, and the infinite map feature is intended just for the editor more than anything. An infinite map would still store the chunk data and stuff, so re-saving a map or using that data from an engine would still be possible, but it would make it so a game or engine needs no specific code to have support for infinite maps.
In order for type-checkers to know that this package is type-annotated, it needs to include a py.typed
marker file, as outlined in PEP 561. Is there a reason this is not currently included?
As part of the documentation re-work some examples could be useful. We don’t really need an example for Arcade since it has its own wrapper, but it should be easy enough to create some minimal examples using Pyglet and Pygame. I think these would be the best way to demo intended usage of the API
Currently TMX/JSON maps and tile sets can be cross loaded within one another. This is really useful as it’s very easy in Tiled to have different tile set formats within one map.
Similarly it’s very easy to have different object template formats in maps/tilesets. Currently object templates cannot be cross loaded and an error is raised informing the user of such.
This was left out of 2.0 as the way object templating works is that the content of the file essentially gets “copy pasted” into map/tile set. Not literally but functionally that’s what happens. This means that in order to support cross loading, the parsers for TMX/JSON need a rather large system to be able to translate every possible object type to the other formats.
Transformations allow defining which ways tiles can be flipped or rotated within a tileset.
See: https://doc.mapeditor.org/en/stable/reference/json-map-format/#json-tileset-transformations
Tiled 1.9 introduced breaking changes in the json format which makes older json files crash pytiled-parser with a KeyError.
Tiled 1.9 projects can be run in 1.8 compatibility mode, which is a functioning workaround at the moment.
Currently we are only capable of accepting a file path to parse the map. Instead we should add the ability to pass an already parsed JSON, or a raw JSON string for example. This may have some implications for how we find the tileset files for external tilesets. What is likely is that the user will have to define any external tilesets to the parse function, in a dictionary that maps the tileset to whatever it’s filepath in the map object is.
Tiled stores the reference to tileset and image objects as relative to the map file, so one solution is to also accept a filepath alongside this and use that instead of deriving the parent directory of the map file.
See: https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python
This causes warnings in PEP-8 checks.
Following Tiled’s changelog, there are a number of new features coming in 1.8 which will require updates to pytiled-parser to support.
The Tiled changelog is available here: https://github.com/mapeditor/tiled/blob/master/NEWS.md
As of right now I’m going to consider these features on the 2.1 milestone, but depending on timing of when Tiled releases 1.8, these could find their way into a 2.0.X release as they’re a higher priority than the other 2.1 features.
This also brings to light that as development of both Tiled and pytiled-parser continues, there should be some kind of compatibility map. It gets a little rocky as if you’re not using any of the new features in 1.8, it probably doesn’t break anything, but it will likely be considered “incompatible” with versions of pytiled-parser prior to when those features were added.
In the past we didn’t cover all of Tiled’s festureset so this wasn’t as necessary, but moving forward I would like to try and keep all updates related to changes in Tiled to a single release. Rather than getting some features spread across a few different releases. This way it is easy to say “2.0.2 and above supports Tiled 1.4-1.8” for example.
There are two different Optional
types in pytiled_parser affecting us in pythonarcade/arcade#1751
Based on discussion, these types can be made non-optional in pytiled_parser which will (eventually) eliminate the need for the downstream assertions in arcade.
Discord conversation:
https://discord.com/channels/458662222697070613/458662458198982676/1108508437832270034
Tile.width
and Tile.height
are Optional
pytiled_parser/pytiled_parser/tileset.py
Lines 124 to 125 in 47297a7
So we use type assertions here:
https://github.com/pythonarcade/arcade/blob/4d7d846b5c853a509ae818bf98152623451eeb6f/arcade/tilemap/tilemap.py#L70-L73
TiledMap.map_file
is Optional
So we use a type assertion here:
https://github.com/pythonarcade/arcade/blob/4d7d846b5c853a509ae818bf98152623451eeb6f/arcade/tilemap/tilemap.py#L419-L421
In Tiled 1.8 the ability to create custom property types was added, this feature was further expanded on in the Tiled 1.9 update.
You can read more about the feature here: https://doc.mapeditor.org/en/stable/manual/custom-properties/#custom-types
I haven't given much thought to what this implementation looks like in pytiled-parser, so I will update this issue with the idea for how this will work once I've done that. This issue is intended to be the primary focus of pytiled-parser 2.3
It would appear as though one of two things is happening when loading an animated tile that uses tiles from a sheet image based tileset. We are somehow either leaving the tile.animation
property as None, or simply not loading the data and making it an empty list(whereas it is supposed to be a list of Frame
objects).
Need to do some more testing to get to the bottom of exactly what's wrong with this though, currently pytiled-parser only has test cases for animated tiles from individual images. I'll be working to add a test case for one with a sheet based tileset and work backwards from there.
This was reported found from pythonarcade/arcade#1362
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.