From d3dc2389c308278442831f370950b2d25e5fa734 Mon Sep 17 00:00:00 2001 From: zlago Date: Fri, 27 Sep 2024 10:32:11 +0200 Subject: tile collision --- src/collision.h | 15 ++++++++ src/loader.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++- src/loader.h | 6 +++ src/main.c | 4 +- src/res/autotiles.col | 2 + src/res/tileset.col | 64 +++++++++++++++++++++++++++++++ src/tilemap.c | 27 ++++++++++--- src/tilemap.h | 3 +- 8 files changed, 214 insertions(+), 10 deletions(-) create mode 100644 src/collision.h create mode 100644 src/res/autotiles.col create mode 100644 src/res/tileset.col (limited to 'src') diff --git a/src/collision.h b/src/collision.h new file mode 100644 index 0000000..3b7a457 --- /dev/null +++ b/src/collision.h @@ -0,0 +1,15 @@ +#pragma once + +typedef unsigned collision_T; + +enum _collisions { + COLLISION_SOLID, + COLLISION_HAZARD, + COLLISION_FLOOR, + + COLLISION_LENGTH // no. of checked inputs +}; + +#define collision_solid(a) (1 & a >> COLLISION_SOLID) +#define collision_hazard(a) (1 & a >> COLLISION_HAZARD) +#define collision_floor(a) (1 & a >> COLLISION_FLOOR) diff --git a/src/loader.c b/src/loader.c index 985f4b7..6a50341 100644 --- a/src/loader.c +++ b/src/loader.c @@ -11,6 +11,7 @@ #include "loader.h" #include "util.h" #include "main.h" +#include "collision.h" static void *inflateWrapped(void *const restrict data, uint32_t const outsize); @@ -18,6 +19,7 @@ typedef enum { FILE_EXT_UNKNOWN, FILE_EXT_TEXTURE, FILE_EXT_MAP, + FILE_EXT_COLLISION, } ext_T; ext_T get_extension_type(char *extension, int length); @@ -35,7 +37,7 @@ struct blob_collection { struct blob blob; name_T name; } items[]; -} *textures = NULL, *maps = NULL; +} *textures = NULL, *maps = NULL, *collisions = NULL; static int name_compare(name_T a, name_T b) { return strcmp(a, b); @@ -85,6 +87,16 @@ void res_init_map(void) { maps = res_init_blobs(); } +void res_init_collision(void) { + collisions = res_init_blobs(); +} + +void res_init(void) { + res_init_texture(); + res_init_map(); + res_init_collision(); +} + void res_free_texture(void) { for (size_t i = 0; i < textures->count; i++) { SDL_DestroyTexture(textures->items[i].blob.data); @@ -107,6 +119,11 @@ void res_free_map(void) { maps = NULL; } +void res_free_collision(void) { + res_free_blobs(maps); + collisions = NULL; +} + static int res_compare_blobs(void const *a, void const *b) { struct blob_item const *aa = a, *bb = b; return name_compare(aa->name, bb->name); @@ -139,6 +156,10 @@ struct blob res_get_map(name_T const name) { return res_get_blob(name, maps); } +struct blob res_get_collision(name_T const name) { + return res_get_blob(name, collisions); +} + static struct blob_collection *res_push_blob(struct blob *blob, name_T name, struct blob_collection *collection, void (*freeFunc)(void *)) { int found; struct blob_item new = {.blob = *blob, .name = name}; @@ -181,6 +202,10 @@ void res_push_map(struct blob *blob, name_T name) { maps = res_push_blob(blob, name, maps, blob_free_func); } +void res_push_collision(struct blob *blob, name_T name) { + collisions = res_push_blob(blob, name, collisions, blob_free_func); +} + int loadResources(char *filename) { // open the file FILE *zip = fopen(filename, "rb"); @@ -285,6 +310,81 @@ int loadResources(char *filename) { blob = (struct blob) {.data = chaos_file->data, .size = chaos_file->size}; res_push_map(&blob, chaos_file->name); break; + + case FILE_EXT_COLLISION:; + char const *props = chaos_file->data; + size_t remaining = chaos_file->size; + if (props[remaining - 1] != '\n') { + fprintf(stderr, "warn: will not load %s.col (missing trailing newline)\n", chaos_file->name); + free(chaos_file->name); + free(chaos_file->data); + break; + } + int tiles = 0; + for (size_t i = 0; i < remaining; i++) { + if (props[i] == '\n') { + tiles++; + } + } + //fprintf(stderr, "allocating %u tiles\n", tiles); + collision_T *const data = calloc(tiles, sizeof (collision_T)); + for (int tile = 0; tile < tiles; tile++) { + char const *tmp = memchr(props, '\n', remaining); + size_t tile_remaining = tmp - props; + //fprintf(stderr, "tile %u (%zu):", tile, tile_remaining); + char const *tile_props = props; + props += tile_remaining + 1; + while (true) { + char const *tile_prop = memchr(tile_props, ',', tile_remaining); + char const *const str = tile_props; + size_t len; + if (tile_prop == NULL) { + len = tile_remaining; + //fprintf(stderr, " '%.*s'", len, tile_props); + //fprintf(stderr, " '%u'", len); + } else { + len = tile_prop - tile_props; + //fprintf(stderr, " '%.*s'", len, tile_props); + //fprintf(stderr, " '%u'", len); + tile_props += len + 1; + tile_remaining -= len + 1; + } + + if (len == 0) { + break; + } + + #define t(a, b)\ + else if (len == sizeof (a) - 1 && memcmp(str, a, sizeof (a) - 1) == 0) {\ + data[tile] |= b;\ + } + t("solid", 1 << COLLISION_SOLID | 1 << COLLISION_FLOOR) + t("hazard", 1 << COLLISION_HAZARD) + t("semisolid", 1 << COLLISION_FLOOR) + #undef t + #if 0 + if (len == 5 && memcmp(str, "solid", 5) == 0) { + data[tile] |= 1 << COLLISION_SOLID | 1 << COLLISION_FLOOR; + } else if (len == 6 && memcmp(str, "hazard", 6) == 0) { + data[tile] |= 1 << COLLISION_HAZARD; + } else if (len == 9 && memcmp(str, "semisolid", 9) == 0) { + data[tile] |= 1 << COLLISION_FLOOR; + } + #endif + else { + fprintf(stderr, "warn: %s: unrecognized property '%.*s'\n", chaos_file->name, (int) len, str); + } + + if (tile_prop == NULL) { + break; + } + } + //fprintf(stderr, " %b\n", data[tile]); + } + free(chaos_file->data); + blob = (struct blob) {.data = data, .size = tiles}; + res_push_collision(&blob, chaos_file->name); + break; default: free(chaos_file->data), chaos_file->data = NULL; @@ -310,6 +410,7 @@ ext_T get_extension_type(char *extension, int length) { ext("jpg", FILE_EXT_TEXTURE); ext("gif", FILE_EXT_TEXTURE); ext("map", FILE_EXT_MAP); + ext("col", FILE_EXT_COLLISION); return FILE_EXT_UNKNOWN; #undef ext } diff --git a/src/loader.h b/src/loader.h index 45a1ac0..6ffb60e 100644 --- a/src/loader.h +++ b/src/loader.h @@ -5,6 +5,8 @@ struct blob { size_t size; }; +void res_init(void); + void res_init_texture(void); void res_free_texture(void); struct blob res_get_texture(name_T const name); @@ -13,4 +15,8 @@ void res_init_map(void); void res_free_map(void); struct blob res_get_map(name_T const name); +void res_init_collision(void); +void res_free_collision(void); +struct blob res_get_collision(name_T const name); + int loadResources(char *filename); diff --git a/src/main.c b/src/main.c index 394f52c..6da4d9a 100644 --- a/src/main.c +++ b/src/main.c @@ -48,9 +48,7 @@ int main(int argc, char **argv) { SDL_RenderSetLogicalSize(renderer, WINDOW_WIDTH, WINDOW_HEIGHT); { - res_init_texture(); - res_init_map(); - //init_tilemap(); + res_init(); void *a = util_executableRelativePath("assets.res", *argv, 0); puts(a); if (loadResources(a)) { diff --git a/src/res/autotiles.col b/src/res/autotiles.col new file mode 100644 index 0000000..bb9556c --- /dev/null +++ b/src/res/autotiles.col @@ -0,0 +1,2 @@ +solid +solid diff --git a/src/res/tileset.col b/src/res/tileset.col new file mode 100644 index 0000000..7e9599d --- /dev/null +++ b/src/res/tileset.col @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +solid,hazard +solid,hazard +solid,hazard +solid,hazard + + + + + + + + + + + + +solid,hazard +solid,hazard +solid,hazard +solid,hazard + + + + + + + + + + + + diff --git a/src/tilemap.c b/src/tilemap.c index 5660046..84d2509 100644 --- a/src/tilemap.c +++ b/src/tilemap.c @@ -8,6 +8,7 @@ #include "main.h" #include "tilemap.h" +#include "collision.h" struct tilemap *tilemap = NULL, *next_tilemap = NULL; @@ -58,7 +59,9 @@ struct tilemap *load_tilemap(void *data, size_t size) { SDL_SetRenderTarget(renderer, tilemap->tileset); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); - + + collision_T collision[256] = {0}; + for (uint32_t count = sets->tilesets_count; count > 0; count--) { int height = *(uint32_t *) str; str += sizeof (uint32_t); @@ -67,8 +70,14 @@ struct tilemap *load_tilemap(void *data, size_t size) { goto fail; } void *tex = res_get_texture(str).data; + struct blob col = res_get_collision(str); SDL_RenderCopy(renderer, tex, &(SDL_Rect) {0, 0, 128, height}, &(SDL_Rect) {0, y, 128, height}); + if (col.size + y * 2 > 0xf0) { + fprintf(stderr, "warn: '%s' overflows tile properties\n", str); + col.size = 0xf0 - y * 2; + } + memcpy(collision + y * 2, col.data, col.size * sizeof (collision_T)); y += height; str += len + 1; @@ -78,9 +87,11 @@ struct tilemap *load_tilemap(void *data, size_t size) { SDL_SetRenderTarget(renderer, tilemap->wang_tileset); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); - - if (sets->tilesets_count) { + + int wangs = 0; + if (sets->wang_count) { int height = *(uint32_t *) str; + wangs = height / 8; str += sizeof (uint32_t); size_t len = strnlen(str, size); if (len == size) { @@ -88,13 +99,19 @@ struct tilemap *load_tilemap(void *data, size_t size) { return NULL; } void *tex = res_get_texture(str).data; + struct blob col = res_get_collision(str); SDL_RenderCopy(renderer, tex, &(SDL_Rect) {0, 0, 128, height}, &(SDL_Rect) {0, 0, 128, height}); + if (col.size > 16) { + fprintf(stderr, "warn: '%s' overflows tile properties\n", str); + col.size = 16; + } + memcpy(collision + 0xf0, col.data, col.size * sizeof (collision_T)); str += len + 1; size -= len + 4 + 1; } - + struct map const *const map = (void *) str; if (map->width * map->height * map->layers > size - sizeof (struct map)) { goto fail; @@ -121,7 +138,7 @@ struct tilemap *load_tilemap(void *data, size_t size) { } } - for (int tile = 0xf0; tile < 0x100; tile++) { + for (int tile = 0xf0; tile < 0xf0 + wangs; tile++) { for (int y = 0; y < map->height - 1; y++) { size_t const yy = y * map->width; for (int x = 0; x < map->width - 1; x++) { diff --git a/src/tilemap.h b/src/tilemap.h index e9b42aa..587bdf6 100644 --- a/src/tilemap.h +++ b/src/tilemap.h @@ -1,4 +1,5 @@ #pragma once +#include "collision.h" extern struct tilemap { void *tileset; @@ -10,7 +11,7 @@ extern struct tilemap { struct parallax { float x, y; } *parallax; - unsigned *collision; + collision_T *collision; void **tilemaps; } *tilemap, *next_tilemap; -- cgit 1.4.1-2-gfad0