-
Notifications
You must be signed in to change notification settings - Fork 28
Tilemaps
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;
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);
}
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.
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.
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 toTiledType_Tile
, anddata
will point toTile
struct. - Every tilemap (tile layer). The
type
will be set toTiledType_Item
,data
will point toTiledItem
struct, and it's type will be set toTiledType_TileMap
. - Every object. The
type
will be set toTiledType_Item
,data
will point toTiledItem
struct, and it's type will be set toTiledType_Rectangle
orTiledType_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.