Home

Awesome

TiledHX

A complete rewrite of the format-tiled library with a change in a structure and support for recent Tiled features. For curious souls you can also read the short backstory of both libraries.

Design notes

Usage

  1. Install library from Haxelib:
haxelib install tiledhx

Or for dev build from git:

haxelib git tiledhx https://github.com/Yanrishatum/tiledhx
  1. Add the library in HXML file:
-lib tiledhx
  1. Load the maps in the following manner:
// Create the loader. You should store it in a static variable somewhere
// so you can reuse it for loading multiple maps.
var loader = new tiled.Tiled();
// Assign the loader methods. In case of supported backends you won't need to do that.
loader.loadXML = myAssetManager.loadXML;
loader.loadJson = myAssetManager.loadJson;
// Optionally you can assign image loaders, see custom types section.
// loader.loadImage
// loader.loadTileset
// loader.subRegion

// Load the TmxMap itself:
var map = loader.loadTMX("path/to/map.tmx");
// Flat iterator allows you to iterate all of the layers even if your map contains nested layer groups.
// If you want to crawl in a nested manner - iterate over `map.layers`.
for (layer in map.flatIterator()) {
  switch (layer.kind) {
    case TTileLayer:
      // Use layer.tileChunks or layer.tiles to load the tile layer.
      // If your map is infinite (map.infinite), you _should_ use layer.tileChunks
    case TObjectGroup:
      // Load your objects
    case TImageLayer:
      // Load the layer consisting of a single image.
    case TGroup:
      // The layer subgroup.
      // Because we're using flat iterator, after this layer you will receive
      // sub-layer of that group
      // You also can access them via `layer.subLayers`.
  }
}

For an example of project generation see samples.

Using custom types for specific elements

It's possible to override various types to use ones from your engine to reduce the amount of extra passes and conversions between Tiled types and engine types.

This feature is based on Haxe allowing to override entire files provided by libraries by having them present in your classpath. I.e. to override ImageType you need to create src/tiled/types/ImageType.hx and declare your own ImageType here to override the type.

Currently it's possible to override the following:

See Default backend support for list of backends that are supported out of the box.

Object type integration

By default Tiled uses Properties class for property data in the object. But since Tiled 1.9 rework of type system, it's possible to switch to macro-generated object types supplied by your own code.

To enable this feature add one of the following defines to your HXML file:

Regardless of what mode is used, generating object types for .tiled-project file is possible.

Generating the object types

All classes that should be exposes to Tiled should implement the tiled.project.TiledClass interface.

Afterwards, add the following line to your HXML file:

--macro tiled.project.TiledProject.generateProject("path/to/my.tiled-project")

where "path/to/my.tile-project should point at the .tiled-project file you use to edit the maps.

Note: As of writing this (Tiled 1.9/1.10) - if .tiled-project is updated externally - you have to restart Tiled in order for it to changes in your object types.

Compiler gotcha: Keep in mind that if you do not import the class anywhere (or do not --macro include it) - compiler will not compile the class and therefore it will not be generated via generateProject. Make sure your TiledClass classes are property included.

Customizing object type

By default, generated classes will use #ffffffff color and use the name of the implementing class as a Tiled class name. This can be customized by adding the following metadata to your class:

Dictating applicable tiled types

By default, class cannot be applied to any of the Tiled entities (i.e. object/map/tile/layer/etc). There are 3 ways to denote compatibility:

The following init methods are supported:

Tip: If you use tile objects, you may want to expose class as both tile and object compatible, as you likely would set default values on tile first, and then would want it to be inherited to the object.

Exposing variables

In order to expose your class fields to Tiled, use the @:tvar metadata on desired fields. The property type is automatically derived from the field type. However, since some Tiled types use same underlying type, you can hint at what type it should be exposed as via @:tvar(file) / @:tvar(color) / etc.

If you want the field to be loaded in project property mode, but not explicitly exposed in Tiled, you can add optional to @:tvar declaration. i.e. @:tvar(file, optional) will parse the property as a file, however it will not list the property for Tiled. Main use case would be for rarely used properties as to not pollute the property list in Tiled. Keep in mind that you cannot add custom properties to nested classes, and optional property will not be available at all in such case.

If your exposed variable has a constant initializer (i.e. @:tvar var myField: Int = 10) - it will be reflected in Tiled, but only for constant expressions.

Supported field types are:

For example:

class MyFancyObject implements tiled.project.TiledClass {
  public function new() {}
  
  @:tvar var boolProp: Bool;
  @:tvar(file) var fileProp: String;
  @:tvar var sub: MyOtherFancyObject; /* that also implements TiledClass */
  @:tvar(string) var enumField: MyFancyEnum;
  @:tvar var flags: EnumFlags<MyFancyEnum>;
  @:tvar @:tfill(3) var stringList: Array<String>; // Will be exposed as stringList[0], stringList[1] and stringList[2]
  @:tvar(optional) var unlistedFloat: Float; // Won't appear on Tiled property list, but will be parsed for project mode.
}

Using project property mode

By using -D tiled_props=project you enable the project mode for the library. In this mode, classes that implement TiledClass will get extra generated fields and will be instantiated as the library loads the map and find those classes being used.

In Tiled instances, the properties: Properties field, will be replaced by a tclass: TiledClass field that will contain the TiledClass that was used in the map. Note that tclass is never null, and for instances that do not have a class will instead use tiled.project.PropertyClass that is a wrapper to classic properties field.

Major difference between dynamic and project is that in project mode any unknown properties are discarded and not stored in any way for instances that have a class attached to it.

In the future there may be added support for handling unknown properties.

<!-- TODO: Allow custom code in loadProperties/finalize --> <!-- TODO: Allow the fallback `loadUnknownProperty(name: String, data: RawPropertyValue)` for extra properties -->

Do note that the TiledClass interface will have a number of methods that you should not implement, as those are generated by the build macro.

Tiled enums vs Haxe enums

Tiled offers 2 ways to store enums: int and string.

Additionally, Tiled allows for multi-choice enums, that are stored as either comma-separated string for string type or a bitmask for int type. Their Haxe counterparts are Array<Enum> and haxe.EnumFlags<Enum> respectively.

Enums that are exposed as string enums will have _s postfix added to their name, as well as _fs postfix for multi-choice enums. And _f postfix for multi-choice integer enums.

Due to how Tiled is made, using both multi-choice and single-choice on same Enum will expose it twice under different names. Same goes for string vs int types.

Default backend support

Heaps

Define flags

<!-- * `tiled_extra_fields` - Enables the `@:build` macro for [extra fields](#extra-fields) on all Tiled types. --> <!-- # Extra fields TODO 1. Enable `-D tiled_extra_fields` 2. Use `--macro tiled.types.Macros.addXData(name, type)` -->