Skip to content
Martin Cohen edited this page Dec 9, 2016 · 3 revisions

Punity has it's own Tile and TileMap structs. These are general-purpose structs (that can also be extended) used for drawing, collision detection and are also used to import a Tiled JSON format (see more below).

TileMap is a simple structure that holds pointers to instances of tiles. That means that each new property of tile adds to the size of the tilemap.

Tile holds it's own pointer to a bitmap and an index that tells where to find the tile in the bitmap. It also holds flags and layer properties that are used by collision system. The flags property uses lowest 4 bits for Edge_* flags, that are used to tell which side of the tile is collidable. The rest of flags is for your own use.

Tilesets in Punity are done via Bitmap that has tile_width and tile_height. These two properties are not set and has to be set after the bitmap is initialized:

Bitmap bitmap;
bitmap_load_resource(&bitmap, "tileset.png");
bitmap.tile_width = 16;
bitmap.tile_height = 16;

Tiled JSON format

You can import Tiled JSON format by including lib/punity-tiled.h (also requires lib/json.h):

#define PUNITY_IMPLEMENTATION
#include "punity.h"

#define TILED_IMPLEMENATION
#include "punity-tiled.h"

All the json (for maps, external tilesets) as well as images (for bitmaps) must be included in assets. This is how you load the scenes:

Tiled tiled;
TiledScene scene1;
TiledScene scene2;
TiledScene scene3;
// ...

int init() {

    // Initializes an object that holds bitmap cache.
    tiled_init(&tiled);
    // Loads `scene1.json`.
    tiledscene_load_resource(&tiled, &scene1, "scene1.json", 0, 0);
    // Loads `scene2.json`.
    tiledscene_load_resource(&tiled, &scene2 "scene2.json", 0, 0);
    // Loads `scene3.json`.
    tiledscene_load_resource(&tiled, &scene3, "scene3.json", 0, 0);
    // We're finished loading everyhing, so clear the `tiled` cache.
    tiled_free(&tiled);
}

Tiled's Tilesets

The importer reads all the tilesets and their bitmaps. However, each bitmap is loaded only once (and reused). So it is not needed (not even recommended) to load tilesets yourself with bitmap_load_resource as that would result in duplicate bitmap data in memory which is usually not what you want. All variants of tilesets are supported: single-image tilesets, image collection tilesets and also both of those in external tileset variant.

Tiled's Scene

The scene is an object representing a single map. TiledScene contains all the items (objects and tilemaps) but does not contain layers. Tiled's layers are largely ignored (although tilemap's layer is used to get the properties for the tilemap).

To iterate over the items in the TiledScene you can do this:

    for (TiledItem *item = scene1.items;
         item != scene1.items_end;
         item = tileditem_next(item))
    {
        switch (item->type)
        {
        case TiledType_TileMap:
            tilemap_draw(&item->tilemap);
            break;
        case TiledType_Rectangle:
            rect_draw(item->rect, 2);
            break;
        case TiledType_Image:
            bitmap_draw(item->tile.tileset, item->rect.min_x, item->rect.min_y, 0, 0, 0);
            break;
        }
    }

However drawing directly from the TiledScene is not what you end up with. Usually you use the items in TiledScene as an original prototype to restore the scene's state (for example when the player restarts the game). More over, the TiledScene by itself can only provide tilemaps. What you want to do is to have a function that sets up Scene and SceneEntities, and perhaps even copies the tilemap to a distinct "runtime" version that is then set to the Scene to get collisions from.

Tiled's Custom Properties

Currently no properties are being read (I'll be slowly adding support for custom properties that make sense in Punity (like tile edges)), but you can implement it by passing a callback function to the tiledscene_load_resource:

TILED_CALLBACK(tiled_callback)
{
    for (int i = 0; i != properties_count; ++i) {
        switch (properties[i].value->type)
        {
        case json_string:
            LOG("%s = %s\n", properties[i].name, properties[i].value->string.ptr);
            break;
        }
    }
}

int init() {
    // Initializes an object that holds bitmap cache.
    tiled_init(&tiled);
    // Loads `scene1.json`.
    tiledscene_load_resource(&tiled, &scene1, "scene1.json", tiled_callback, 0);
    // We're finished loading everyhing, so clear the `tiled` cache.
    tiled_free(&tiled);
}

Tiled callback is defined as follows:

#define TILED_CALLBACK(name) \
    void name(int type, void *data, json_object_entry *properties, size_t properties_count, void *user)

The callback is called for various items that have the custom properties specified:

  • Every tile prototype. The type will be set to TiledType_Tile, and data will point to Tile struct.
  • Every tilemap (tile layer). The type will be set to TiledType_Item, data will point to TiledItem struct, and it's type will be set to TiledType_TileMap.
  • Every object. The type will be set to TiledType_Item, data will point to TiledItem struct, and it's type will be set to TiledType_Rectangle or TiledType_Image (or other that might be added in the future).

Thanks to this, and possibility to extend every struct in Tiled importer or Punity, you can convert any custom properties to actual struct properties that can be efficiently read in runtime.

Clone this wiki locally