# HG changeset patch # User David Demelier # Date 1605473269 -3600 # Node ID adcbb7ccfdee8f4f4eca828bd0b42faa4e68db83 # Parent 70e6ed74940d55827152913697f0bace614ce3e1 rpg: some refactoring Rename map tile properties into `map_tiledef` and refactor a bit functions to reduce code duplication. Also add more sane collisions in the test map. diff -r 70e6ed74940d -r adcbb7ccfdee examples/assets/maps/simple.json --- a/examples/assets/maps/simple.json Sat Nov 14 16:59:11 2020 +0100 +++ b/examples/assets/maps/simple.json Sun Nov 15 21:47:49 2020 +0100 @@ -53,7 +53,7 @@ "value":"World" }], "renderorder":"right-down", - "tiledversion":"1.4.2", + "tiledversion":"2020.10.30", "tileheight":48, "tilesets":[ { @@ -73,7 +73,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -99,7 +98,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -125,7 +123,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -151,7 +148,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -177,7 +173,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -203,7 +198,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -229,7 +223,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -255,7 +248,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -281,7 +273,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -307,7 +298,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -333,7 +323,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -359,7 +348,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -385,7 +373,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -411,7 +398,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -437,7 +423,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -463,7 +448,6 @@ "objectgroup": { "draworder":"index", - "id":2, "name":"", "objects":[ { @@ -485,6 +469,838 @@ } }, { + "id":304, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":305, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":306, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":307, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":308, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":309, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":310, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":311, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":328, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":329, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":330, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":331, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":332, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":333, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":334, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":335, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":352, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":353, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":354, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":355, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":356, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":357, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":358, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":359, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":376, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":377, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":378, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":379, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":380, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":381, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":382, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":383, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { "id":384, "objectgroup": { @@ -535,6 +1351,214 @@ } }, { + "id":400, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":401, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":402, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":403, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":404, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":405, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":406, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":407, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { "id":408, "objectgroup": { @@ -583,6 +1607,188 @@ "x":0, "y":0 } + }, + { + "id":424, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":425, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":426, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":427, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":428, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":429, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }, + { + "id":430, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":48, + "id":1, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":48, + "x":0, + "y":0 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } }], "tilewidth":48 }], @@ -590,4 +1796,4 @@ "type":"map", "version":1.4, "width":100 -} +} \ No newline at end of file diff -r 70e6ed74940d -r adcbb7ccfdee librpg/rpg/map-file.c --- a/librpg/rpg/map-file.c Sat Nov 14 16:59:11 2020 +0100 +++ b/librpg/rpg/map-file.c Sun Nov 15 21:47:49 2020 +0100 @@ -44,14 +44,14 @@ }; static int -tile_cmp(const void *d1, const void *d2) +tiledef_cmp(const void *d1, const void *d2) { - const struct map_tile *mt1 = d1; - const struct map_tile *mt2 = d2; + const struct map_tiledef *mtd1 = d1; + const struct map_tiledef *mtd2 = d2; - if (mt1->id < mt2->id) + if (mtd1->id < mtd2->id) return -1; - if (mt1->id > mt2->id) + if (mtd1->id > mtd2->id) return 1; return 0; @@ -194,27 +194,27 @@ } static bool -parse_tiles(struct parser *ps, const char *line) +parse_tiledefs(struct parser *ps, const char *line) { (void)line; short x, y; unsigned short id, w, h; - struct map_tile *tiles = NULL; - size_t tilesz = 0; + struct map_tiledef *tiledefs = NULL; + size_t tiledefsz = 0; while (fscanf(ps->fp, "%hu|%hd|%hd|%hu|%hu\n", &id, &x, &y, &w, &h) == 5) { - tiles = allocator.realloc(tiles, ++tilesz * sizeof (*tiles)); - tiles[tilesz - 1].id = id; - tiles[tilesz - 1].x = x; - tiles[tilesz - 1].y = y; - tiles[tilesz - 1].w = w; - tiles[tilesz - 1].h = h; + tiledefs = allocator.realloc(tiledefs, ++tiledefsz * sizeof (*tiledefs)); + tiledefs[tiledefsz - 1].id = id; + tiledefs[tiledefsz - 1].x = x; + tiledefs[tiledefsz - 1].y = y; + tiledefs[tiledefsz - 1].w = w; + tiledefs[tiledefsz - 1].h = h; } - qsort(tiles, tilesz, sizeof (struct map_tile), tile_cmp); - ps->map->tiles = ps->mf->tiles = tiles; - ps->map->tilesz = tilesz; + qsort(tiledefs, tiledefsz, sizeof (*tiledefs), tiledef_cmp); + ps->map->tiledefs = ps->mf->tiledefs = tiledefs; + ps->map->tiledefsz = tiledefsz; return true; } @@ -234,7 +234,7 @@ { "tileset", parse_tileset }, { "origin", parse_origin }, { "layer", parse_layer }, - { "tiles", parse_tiles } + { "tiledefs", parse_tiledefs } }; for (size_t i = 0; i < NELEM(props); ++i) @@ -327,7 +327,7 @@ { assert(file); - free(file->tiles); + free(file->tiledefs); texture_finish(&file->tileset); memset(file, 0, sizeof (*file)); } diff -r 70e6ed74940d -r adcbb7ccfdee librpg/rpg/map-file.h --- a/librpg/rpg/map-file.h Sat Nov 14 16:59:11 2020 +0100 +++ b/librpg/rpg/map-file.h Sun Nov 15 21:47:49 2020 +0100 @@ -71,9 +71,9 @@ */ struct map_layer layers[MAP_LAYER_TYPE_NUM]; - struct map_tile *tiles; /*!< (*) Per tile properties. */ - struct texture tileset; /*!< (*) Tileset image. */ - struct sprite sprite; /*!< (*) Tileset sprite. */ + struct map_tiledef *tiledefs; /*!< (*) Per tile properties. */ + struct texture tileset; /*!< (*) Tileset image. */ + struct sprite sprite; /*!< (*) Tileset sprite. */ }; /** diff -r 70e6ed74940d -r adcbb7ccfdee librpg/rpg/map.c --- a/librpg/rpg/map.c Sat Nov 14 16:59:11 2020 +0100 +++ b/librpg/rpg/map.c Sun Nov 15 21:47:49 2020 +0100 @@ -89,6 +89,39 @@ [0xC] = 5 }; +struct collision { + int x; + int y; + unsigned int w; + unsigned int h; +}; + +static bool +is_collision_out(const struct map *map, struct collision *block, int drow, int dcol) +{ + if (drow) { + /* Object outside of left-right bounds. */ + if (block->x + (int)block->w <= map->player_x || + block->x >= map->player_x + (int)map->player_sprite->cellw) + return false; + + if ((drow < 0 && block->y >= map->player_y + (int)map->player_sprite->cellh) || + (drow > 0 && block->y + block->h <= map->player_y + map->player_sprite->cellh)) + return false; + } else if (dcol) { + /* Object outside of up-down bounds. */ + if (block->y + (int)block->h <= map->player_y || + block->y >= map->player_y + (int)map->player_sprite->cellh) + return false; + + if ((dcol < 0 && block->x >= map->player_x + (int)map->player_sprite->cellw) || + (dcol > 0 && block->x + block->w <= map->player_x + map->player_sprite->cellw)) + return false; + } + + return true; +} + static void center(struct map *map) { @@ -175,190 +208,160 @@ } static int -cmp_tile(const struct map_tile *t1, const struct map_tile *t2) +cmp_tile(const struct map_tiledef *td1, const struct map_tiledef *td2) { - if (t1->id < t2->id) + if (td1->id < td2->id) return -1; - if (t1->id > t2->id) + if (td1->id > td2->id) return 1; return 0; } -static struct map_tile * -find_tile_by_id(const struct map *map, unsigned short id) +static struct map_tiledef * +find_tiledef_by_id(const struct map *map, unsigned short id) { typedef int (*cmp)(const void *, const void *); - const struct map_tile key = { + const struct map_tiledef key = { .id = id }; - return bsearch(&key, map->tiles, map->tilesz, sizeof (struct map_tile), (cmp)cmp_tile); + return bsearch(&key, map->tiledefs, map->tiledefsz, sizeof (key), (cmp)cmp_tile); } -static struct map_tile * -find_tile_in_layer(const struct map *map, const struct map_layer *layer, int pr, int pc) +static struct map_tiledef * +find_tiledef_by_row_column_in_layer(const struct map *map, + const struct map_layer *layer, + int row, + int col) { unsigned short id; - if ((id = layer->tiles[pc + pr * map->w]) == 0) + if (row < 0 || (unsigned int)row >= map->h || + col < 0 || (unsigned int)col >= map->w) + return false; + + if ((id = layer->tiles[col + row * map->w]) == 0) return NULL; - return find_tile_by_id(map, id - 1); + return find_tiledef_by_id(map, id - 1); } -static bool -can_be_used(const struct map *map, const struct map_tile *block, int drow, int dcol) +static struct map_tiledef * +find_tiledef_by_row_column(const struct map *map, int row, int col) { - if (drow) { - /* Object outside of left-right bounds. */ - if (block->x + (int)block->w <= map->player_x || - block->x >= map->player_x + (int)map->player_sprite->cellw) - return false; - - if ((drow < 0 && block->y >= map->player_y + (int)map->player_sprite->cellh) || - (drow > 0 && block->y + block->h <= map->player_y + (int)map->player_sprite->cellh)) - return false; - } else if (dcol) { - /* Object outside of up-down bounds. */ - if (block->y + (int)block->h <= map->player_y || - block->y >= map->player_y + (int)map->player_sprite->cellh) - return false; - - if ((dcol < 0 && block->x >= map->player_x + (int)map->player_sprite->cellw) || - (dcol > 0 && block->x + block->w <= map->player_x + (int)map->player_sprite->cellw)) - return false; - } - - return true; -} + struct map_tiledef *tile; -static bool -find_tile_absolute(const struct map *map, struct map_tile *block, int row, int col, int drow, int dcol) -{ - struct map_tile *tile, tmp; - - if (row < 0 || (unsigned int)row >= map->h || col < 0 || (unsigned int) col >= map->w) - return false; - - if (!(tile = find_tile_in_layer(map, &map->layers[1], row, col))) - tile = find_tile_in_layer(map, &map->layers[0], row, col); - - if (!tile) - return false; + /* TODO: probably a for loop when we have indefinite layers. */ + if (!(tile = find_tiledef_by_row_column_in_layer(map, &map->layers[1], row, col))) + tile = find_tiledef_by_row_column_in_layer(map, &map->layers[0], row, col); - /* Convert to absolute values. */ - tmp.id = tile->id; - tmp.x = tile->x + col * map->tileset->cellw; - tmp.y = tile->y + row * map->tileset->cellh; - tmp.w = tile->w; - tmp.h = tile->h; - - /* This tile is not usable */ - if (!tile || !can_be_used(map, &tmp, drow, dcol)) - return false; - - memcpy(block, &tmp, sizeof (tmp)); - - return true; + return tile; } static void -find_block_y(const struct map *map, struct map_tile *block, int pr, int pc, int drow) +find_block_iterate(const struct map *map, + struct collision *block, + int rowstart, + int rowend, + int colstart, + int colend, + int drow, + int dcol) { - int ncols = map->player_sprite->cellw / map->tileset->cellw; - int nrows = map->player_sprite->cellh / map->tileset->cellh; - int start, end; + assert(map); + assert(block); + + for (int r = rowstart; r <= rowend; ++r) { + for (int c = colstart; c <= colend; ++c) { + struct map_tiledef *td; + struct collision tmp; + + if (!(td = find_tiledef_by_row_column(map, r, c))) + continue; - if (drow < 0) { - start = 0; - end = pr; - block->x = block->y = block->h = 0; - block->w = map->real_w; - } else { - start = pr + nrows; - end = map->h; - block->x = block->h = 0; - block->y = map->real_h; - block->w = map->real_w; - } + /* Convert to absolute values. */ + tmp.x = td->x + c * map->tileset->cellw; + tmp.y = td->y + r * map->tileset->cellh; + tmp.w = td->w; + tmp.h = td->h; + + /* This tiledef is out of context. */ + if (!is_collision_out(map, &tmp, drow, dcol)) + continue; - for (int r = start; r <= end; ++r) { - for (int c = 0; c <= ncols; ++c) { - struct map_tile tmp; - - if (!find_tile_absolute(map, &tmp, r, pc + c, drow, 0)) - continue; if ((drow < 0 && tmp.y + tmp.h > block->y + block->h) || - (drow > 0 && tmp.y < block->y)) - memcpy(block, &tmp, sizeof (tmp)); + (drow > 0 && tmp.y < block->y) || + (dcol < 0 && tmp.x + tmp.w > block->x + block->w) || + (dcol > 0 && tmp.x < block->x)) { + block->x = tmp.x; + block->y = tmp.y; + block->w = tmp.w; + block->h = tmp.h; + } } } } static void -find_block_x(const struct map *map, struct map_tile *block, int pr, int pc, int dcol) +find_collision(const struct map *map, struct collision *block, int drow, int dcolumn) { - int ncols = map->player_sprite->cellw / map->tileset->cellw; - int nrows = map->player_sprite->cellh / map->tileset->cellh; - int start, end; + assert((drow && !dcolumn) || (dcolumn && !drow)); + + const int playercol = map->player_x / map->tileset->cellw; + const int playerrow = map->player_y / map->tileset->cellh; + const int ncols = map->player_sprite->cellw / map->tileset->cellw; + const int nrows = map->player_sprite->cellh / map->tileset->cellh; + int rowstart, rowend, colstart, colend; + + if (drow) { + colstart = playercol; + colend = playercol + ncols; - if (dcol < 0) { - start = 0; - end = pc; - block->x = block->y = block->w = 0; - block->h = map->real_h; + if (drow < 0) { + /* Moving UP. */ + rowstart = 0; + rowend = playerrow; + block->x = block->y = block->h = 0; + block->w = map->real_w; + } else { + /* Moving DOWN. */ + rowstart = playerrow + nrows; + rowend = map->h; + block->x = block->h = 0; + block->y = map->real_h; + block->w = map->real_w; + } } else { - start = pc + ncols; - end = map->w; - block->x = map->real_w; - block->y = block->w = 0; - block->h = block->h; + rowstart = playerrow; + rowend = playerrow + nrows; + + if (dcolumn < 0) { + /* Moving LEFT. */ + colstart = 0; + colend = playercol; + block->x = block->y = block->w = 0; + block->h = map->real_h; + } else { + /* Moving RIGHT. */ + colstart = playercol + ncols; + colend = map->w; + block->x = map->real_w; + block->y = block->w = 0; + block->h = block->h; + } } - for (int c = start; c <= end; ++c) { - for (int r = 0; r <= nrows; ++r) { - struct map_tile tmp; - - if (!find_tile_absolute(map, &tmp, pr + r, c, 0, dcol)) - continue; - if ((dcol < 0 && tmp.x + tmp.w > block->x + block->w) || - (dcol > 0 && tmp.x < block->x)) - memcpy(block, &tmp, sizeof (tmp)); - } - } -} - -/* - * Fill dimensions of the adjacent tile from the current player position. The - * arguments drow/dcolumn indicate the desired movement (e.g. -1, +1) but only - * one at a time must be set. - * - * The argument block will be set to a rectangle that will collide with the - * player according to its position and destination. It is never null because - * if no tile definition is found it is set to the screen edges. - */ -static void -find_tile_collision(const struct map *map, struct map_tile *block, int drow, int dcol) -{ - assert((drow != 0 && dcol == 0) || (drow == 0 && dcol != 0)); - - const int pcol = map->player_x / map->tileset->cellw; - const int prow = map->player_y / map->tileset->cellh; - - if (drow) - find_block_y(map, block, prow, pcol, drow); - else if (dcol) - find_block_x(map, block, prow, pcol, dcol); + find_block_iterate(map, block, rowstart, rowend, colstart, colend, drow, dcolumn); } static void move_x(struct map *map, int delta) { - struct map_tile block; + struct collision block; - find_tile_collision(map, &block, 0, delta < 0 ? -1 : +1); + find_collision(map, &block, 0, delta < 0 ? -1 : +1); if (delta < 0 && map->player_x + delta < (int)(block.x + block.w)) delta = map->player_x - block.x - block.w; @@ -379,9 +382,9 @@ static void move_y(struct map *map, int delta) { - struct map_tile block; + struct collision block; - find_tile_collision(map, &block, delta < 0 ? -1 : +1, 0); + find_collision(map, &block, delta < 0 ? -1 : +1, 0); if (delta < 0 && map->player_y + delta < (int)(block.y + block.h)) delta = map->player_y - block.y - block.h; @@ -453,7 +456,7 @@ } for (size_t i = 0; i < ntiles; ++i) { - const struct map_tile *tile; + const struct map_tiledef *td; int mx, my, mr, mc, sr, sc, id; if (layer->tiles[i] == 0) @@ -475,8 +478,8 @@ sprite_draw(map->tileset, sr, sc, mx, my); - if ((tile = find_tile_by_id(map, id)) && texture_ok(&colbox)) - texture_scale(&colbox, 0, 0, 5, 5, mx + tile->x, my + tile->y, tile->w, tile->h, 0); + if ((td = find_tiledef_by_id(map, id)) && texture_ok(&colbox)) + texture_scale(&colbox, 0, 0, 5, 5, mx + td->x, my + td->y, td->w, td->h, 0); if (map->flags & MAP_FLAGS_SHOW_GRID) { painter_set_color(0x202e37ff); diff -r 70e6ed74940d -r adcbb7ccfdee librpg/rpg/map.h --- a/librpg/rpg/map.h Sat Nov 14 16:59:11 2020 +0100 +++ b/librpg/rpg/map.h Sun Nov 15 21:47:49 2020 +0100 @@ -48,7 +48,7 @@ /** * \brief Describe a tile in a tileset. */ -struct map_tile { +struct map_tiledef { short id; /*!< (*) Tile index. */ short x; /*!< (*) Collision region starts in y. */ short y; /*!< (*) Collision region starts in y. */ @@ -90,8 +90,8 @@ unsigned short tile_h; /*!< (-) Pixels per cell (height). */ struct sprite *tileset; /*!< (+&) Tileset to use. */ struct texture picture; /*!< (-) Map drawn into a texture. */ - struct map_tile *tiles; /*!< (+&?) Per tile properties (must be sorted). */ - size_t tilesz; /*!< (+) Number of tile properties. */ + struct map_tiledef *tiledefs; /*!< (+&?) Per tile properties (must be sorted by id). */ + size_t tiledefsz; /*!< (+) Number of tile properties. */ /* View options. */ enum map_flags flags; /*!< (+) View options. */ diff -r 70e6ed74940d -r adcbb7ccfdee tests/test-map.c --- a/tests/test-map.c Sat Nov 14 16:59:11 2020 +0100 +++ b/tests/test-map.c Sun Nov 15 21:47:49 2020 +0100 @@ -48,17 +48,17 @@ GREATEST_ASSERT_EQ(5, map.layers[1].tiles[1]); GREATEST_ASSERT_EQ(6, map.layers[1].tiles[2]); GREATEST_ASSERT_EQ(7, map.layers[1].tiles[3]); - GREATEST_ASSERT_EQ(2, map.tilesz); - GREATEST_ASSERT_EQ(0, map.tiles[0].id); - GREATEST_ASSERT_EQ(10, map.tiles[0].x); - GREATEST_ASSERT_EQ(12, map.tiles[0].y); - GREATEST_ASSERT_EQ(5, map.tiles[0].w); - GREATEST_ASSERT_EQ(7, map.tiles[0].h); - GREATEST_ASSERT_EQ(2, map.tiles[1].id); - GREATEST_ASSERT_EQ(12, map.tiles[1].x); - GREATEST_ASSERT_EQ(14, map.tiles[1].y); - GREATEST_ASSERT_EQ(8, map.tiles[1].w); - GREATEST_ASSERT_EQ(10, map.tiles[1].h); + GREATEST_ASSERT_EQ(2, map.tiledefsz); + GREATEST_ASSERT_EQ(0, map.tiledefs[0].id); + GREATEST_ASSERT_EQ(10, map.tiledefs[0].x); + GREATEST_ASSERT_EQ(12, map.tiledefs[0].y); + GREATEST_ASSERT_EQ(5, map.tiledefs[0].w); + GREATEST_ASSERT_EQ(7, map.tiledefs[0].h); + GREATEST_ASSERT_EQ(2, map.tiledefs[1].id); + GREATEST_ASSERT_EQ(12, map.tiledefs[1].x); + GREATEST_ASSERT_EQ(14, map.tiledefs[1].y); + GREATEST_ASSERT_EQ(8, map.tiledefs[1].w); + GREATEST_ASSERT_EQ(10, map.tiledefs[1].h); map_finish(&map); map_file_finish(&loader); diff -r 70e6ed74940d -r adcbb7ccfdee tools/map/map.c --- a/tools/map/map.c Sat Nov 14 16:59:11 2020 +0100 +++ b/tools/map/map.c Sun Nov 15 21:47:49 2020 +0100 @@ -257,7 +257,7 @@ } static void -write_tileset_tile(const json_t *tile) +write_tileset_tiledef(const json_t *tile) { const json_t *id = json_object_get(tile, "id"); const json_t *objectgroup = json_object_get(tile, "objectgroup"); @@ -290,18 +290,18 @@ } static void -write_tileset_tiles(const json_t *tiles) +write_tileset_tiledefs(const json_t *tiles) { size_t index; json_t *object; - puts("tiles"); + puts("tiledefs"); json_array_foreach(tiles, index, object) { if (!json_is_object(object)) die("tile is not an object\n"); - write_tileset_tile(object); + write_tileset_tiledef(object); } } @@ -317,7 +317,7 @@ printf("tileset|%s\n", json_string_value(image)); if (json_is_array(tiles)) - write_tileset_tiles(tiles); + write_tileset_tiledefs(tiles); } static void