changeset 592:1560ef13146c

rpg: map support player sprite
author David Demelier <markand@malikania.fr>
date Mon, 20 Mar 2023 21:59:02 +0100
parents bca466732620
children f9e85d0aca74
files libmlk-example/assets/maps/world.json libmlk-rpg/CMakeLists.txt libmlk-rpg/mlk/rpg/map-loader-file.c libmlk-rpg/mlk/rpg/map-loader-file.h libmlk-rpg/mlk/rpg/map-loader.c libmlk-rpg/mlk/rpg/map-loader.h mlk-map/mlk-map.c
diffstat 7 files changed, 222 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/libmlk-example/assets/maps/world.json	Mon Mar 20 21:12:15 2023 +0100
+++ b/libmlk-example/assets/maps/world.json	Mon Mar 20 21:59:02 2023 +0100
@@ -69,22 +69,37 @@
  "orientation":"orthogonal",
  "properties":[
         {
-         "name":"origin-x",
+         "name":"player-origin-x",
          "type":"int",
          "value":384
         }, 
         {
-         "name":"origin-y",
+         "name":"player-origin-y",
          "type":"int",
          "value":480
         }, 
         {
+         "name":"player-sprite",
+         "type":"string",
+         "value":"john.png"
+        }, 
+        {
+         "name":"player-sprite-h",
+         "type":"int",
+         "value":48
+        }, 
+        {
+         "name":"player-sprite-w",
+         "type":"int",
+         "value":48
+        }, 
+        {
          "name":"title",
          "type":"string",
          "value":"Isolated Island"
         }],
  "renderorder":"right-down",
- "tiledversion":"1.9.2",
+ "tiledversion":"1.10.0",
  "tileheight":48,
  "tilesets":[
         {
@@ -93,6 +108,6 @@
         }],
  "tilewidth":48,
  "type":"map",
- "version":"1.9",
+ "version":"1.10",
  "width":30
 }
\ No newline at end of file
--- a/libmlk-rpg/CMakeLists.txt	Mon Mar 20 21:12:15 2023 +0100
+++ b/libmlk-rpg/CMakeLists.txt	Mon Mar 20 21:59:02 2023 +0100
@@ -48,6 +48,7 @@
 	${libmlk-rpg_SOURCE_DIR}/mlk/rpg/tileset-loader-file.h
 	${libmlk-rpg_SOURCE_DIR}/mlk/rpg/tileset-loader.h
 	${libmlk-rpg_SOURCE_DIR}/mlk/rpg/tileset.h
+	${libmlk-rpg_SOURCE_DIR}/mlk/rpg/walksprite.h
 )
 
 set(
--- a/libmlk-rpg/mlk/rpg/map-loader-file.c	Mon Mar 20 21:12:15 2023 +0100
+++ b/libmlk-rpg/mlk/rpg/map-loader-file.c	Mon Mar 20 21:59:02 2023 +0100
@@ -19,12 +19,72 @@
 #include <assert.h>
 
 #include <mlk/core/alloc.h>
+#include <mlk/core/image.h>
+#include <mlk/core/sprite.h>
+#include <mlk/core/texture.h>
 
 #include "map-loader-file.h"
 #include "map-loader.h"
 #include "map.h"
 #include "tileset-loader.h"
 
+static inline void *
+allocate(void ***array, size_t width)
+{
+	void **ptr, *elem;
+
+	/* Not yet allocated? Allocate a new pointer element. */
+	if (!*array)
+		ptr = mlk_alloc_new0(1, sizeof (void *));
+	else
+		ptr = mlk_alloc_expand(*array, 1);
+
+	if (!ptr)
+		return NULL;
+
+	/* Now allocate the element itself because. */
+	if (!(elem = mlk_alloc_new0(1, width)))
+		return NULL;
+
+	/* Store it into the array of elements. */
+	ptr[mlk_alloc_getn(ptr) - 1] = elem;
+	*array = ptr;
+
+	return elem;
+}
+
+static struct mlk_texture *
+init_texture(struct mlk_map_loader *self,
+             struct mlk_map *map,
+             const char *ident)
+{
+	(void)map;
+
+	struct mlk_map_loader_file *file = self->data;
+	struct mlk_texture *texture;
+	char path[MLK_PATH_MAX];
+
+	snprintf(path, sizeof (path), "%s/%s", file->directory, ident);
+
+	/* No need to deallocate, already done in finish anyway. */
+	if (!(texture = allocate((void ***)&file->textures, sizeof (struct mlk_texture))))
+		return NULL;
+	if (mlk_image_open(texture, path) < 0)
+		return NULL;
+
+	return texture;
+}
+
+static struct mlk_sprite *
+init_sprite(struct mlk_map_loader *self, struct mlk_map *map)
+{
+	(void)map;
+
+	struct mlk_map_loader_file *file = self->data;
+
+	return allocate((void ***)&file->sprites, sizeof (struct mlk_sprite));
+}
+
 static struct mlk_tileset *
 init_tileset(struct mlk_map_loader *self,
              struct mlk_map *map,
@@ -86,6 +146,31 @@
 	return ptr;
 }
 
+static void
+finish(void ***ptr, void (*finish)(void *))
+{
+	size_t len;
+
+	/* Already cleared. */
+	if (!*ptr)
+		return;
+
+	len = mlk_alloc_getn(*ptr);
+
+	for (size_t i = 0; i < len; ++i)
+		finish((*ptr)[i]);
+
+	mlk_alloc_free(*ptr);
+	*ptr = NULL;
+}
+
+static void
+finish_texture(void *element)
+{
+	mlk_texture_finish(element);
+	mlk_alloc_free(element);
+}
+
 void
 mlk_map_loader_file_init(struct mlk_map_loader_file *file,
                          struct mlk_map_loader *loader,
@@ -105,6 +190,10 @@
 		loader->data = file;
 	if (!loader->init_tileset)
 		loader->init_tileset = init_tileset;
+	if (!loader->init_texture)
+		loader->init_texture = init_texture;
+	if (!loader->init_sprite)
+		loader->init_sprite = init_sprite;
 	if (!loader->alloc_tiles)
 		loader->alloc_tiles = alloc_tiles;
 	if (!loader->expand_blocks)
@@ -124,4 +213,7 @@
 	mlk_tileset_loader_file_finish(&file->tileset_loader_file);
 	mlk_alloc_free(file->blocks);
 	file->blocks = NULL;
+
+	finish((void ***)&file->sprites, mlk_alloc_free);
+	finish((void ***)&file->textures, finish_texture);
 }
--- a/libmlk-rpg/mlk/rpg/map-loader-file.h	Mon Mar 20 21:12:15 2023 +0100
+++ b/libmlk-rpg/mlk/rpg/map-loader-file.h	Mon Mar 20 21:59:02 2023 +0100
@@ -31,6 +31,8 @@
 #include "tileset.h"
 
 struct mlk_map_loader;
+struct mlk_sprite;
+struct mlk_texture;
 
 /**
  * \struct mlk_map_loader_file
@@ -47,6 +49,9 @@
 	/** \cond MLK_PRIVATE_DECLS */
 	unsigned int *tiles[MLK_MAP_LAYER_TYPE_LAST];
 
+	struct mlk_texture **textures;
+	struct mlk_sprite **sprites;
+
 	/*
 	 * We use a tileset file loader if init_tileset function isn't present
 	 * in this map loader.
--- a/libmlk-rpg/mlk/rpg/map-loader.c	Mon Mar 20 21:12:15 2023 +0100
+++ b/libmlk-rpg/mlk/rpg/map-loader.c	Mon Mar 20 21:59:02 2023 +0100
@@ -24,6 +24,7 @@
 #include <mlk/util/util.h>
 
 #include <mlk/core/err.h>
+#include <mlk/core/sprite.h>
 #include <mlk/core/trace.h>
 #include <mlk/core/util.h>
 
@@ -187,16 +188,49 @@
 }
 
 static int
-parse_origin(struct mlk_map_loader *loader,
-             struct mlk_map *map,
-             const char *line,
-             FILE *fp)
+parse_player_origin(struct mlk_map_loader *loader,
+                    struct mlk_map *map,
+                    const char *line,
+                    FILE *fp)
 {
 	(void)loader;
 	(void)fp;
 
-	if (sscanf(line, "origin|%d|%d", &map->player_x, &map->player_y) != 2)
-		return mlk_errf("invalid origin");
+	if (sscanf(line, "player-origin|%d|%d", &map->player_x, &map->player_y) != 2)
+		return mlk_errf("invalid player origin");
+
+	return 0;
+}
+
+static int
+parse_player_sprite(struct mlk_map_loader *loader,
+                    struct mlk_map *map,
+                    const char *line,
+                    FILE *fp)
+{
+	(void)fp;
+
+	char format[32], ident[FILENAME_MAX + 1] = {0};
+	unsigned int w = 0, h = 0;
+	struct mlk_sprite *sprite;
+	struct mlk_texture *texture;
+
+	snprintf(format, sizeof (format), "player-sprite|%%u|%%u|%%%zu[^\n]", sizeof (ident) - 1);
+
+	if (sscanf(line, format, &w, &h, ident) != 3)
+		return mlk_errf("invalid player sprite");
+	if (!(texture = loader->init_texture(loader, map, ident)))
+		return -1;
+	if (!(sprite = loader->init_sprite(loader, map)))
+		return -1;
+
+	sprite->cellw = w;
+	sprite->cellh = h;
+	sprite->texture = texture;
+	mlk_sprite_init(sprite);
+
+	/* Add this sprite into the final map. */
+	map->player_sprite = sprite;
 
 	return 0;
 }
@@ -211,11 +245,12 @@
 		const char *property;
 		int (*read)(struct mlk_map_loader *, struct mlk_map *, const char *, FILE *);
 	} props[] = {
-		{ "columns",    parse_columns           },
-		{ "rows",       parse_rows              },
-		{ "tileset",    parse_tileset           },
-		{ "origin",     parse_origin            },
-		{ "layer",      parse_layer             },
+		{ "columns",            parse_columns           },
+		{ "rows",               parse_rows              },
+		{ "tileset",            parse_tileset           },
+		{ "player-origin",      parse_player_origin     },
+		{ "player-sprite",      parse_player_sprite     },
+		{ "layer",              parse_layer             },
 	};
 
 	for (size_t i = 0; i < MLK_UTIL_SIZE(props); ++i) {
--- a/libmlk-rpg/mlk/rpg/map-loader.h	Mon Mar 20 21:12:15 2023 +0100
+++ b/libmlk-rpg/mlk/rpg/map-loader.h	Mon Mar 20 21:59:02 2023 +0100
@@ -25,6 +25,8 @@
 
 struct mlk_map;
 struct mlk_map_block;
+struct mlk_sprite;
+struct mlk_texture;
 struct mlk_tileset;
 
 /**
@@ -59,6 +61,31 @@
 	/**
 	 * (read-write)
 	 *
+	 * Open a texture from the given ident name.
+	 *
+	 * \param self this loader
+	 * \param ident the texture name (or path)
+	 * \return a borrowed texture or NULL on failure
+	 */
+	struct mlk_texture * (*init_texture)(struct mlk_map_loader *self,
+	                                     struct mlk_map *map,
+	                                     const char *ident);
+
+	/**
+	 * (read-write)
+	 *
+	 * Return a sprite that the loader needs.
+	 *
+	 * \param self this loader
+	 * \return a unused sprite
+	 * \return a borrowed sprite or NULL on failure
+	 */
+	struct mlk_sprite * (*init_sprite)(struct mlk_map_loader *self,
+	                                   struct mlk_map *map);
+
+	/**
+	 * (read-write)
+	 *
 	 * Allocate the number of tiles required to fill a layer.
 	 *
 	 * \param self this loader
--- a/mlk-map/mlk-map.c	Mon Mar 20 21:12:15 2023 +0100
+++ b/mlk-map/mlk-map.c	Mon Mar 20 21:59:02 2023 +0100
@@ -56,27 +56,48 @@
 }
 
 static void
-write_origin(const json_t *props)
+write_player_origin(const json_t *props)
 {
-	const json_t *prop_origin_x;
-	const json_t *prop_origin_y;
+	const json_t *x, *y;
 
-	prop_origin_x = find_property(props, "origin-x");
-	prop_origin_y = find_property(props, "origin-y");
+	x = find_property(props, "player-origin-x");
+	y = find_property(props, "player-origin-y");
 
-	if (!prop_origin_x || !json_is_integer(prop_origin_x) ||
-	    !prop_origin_y || !json_is_integer(prop_origin_y))
+	if (!x || !json_is_integer(x) ||
+	    !y || !json_is_integer(y))
 		return;
 
-	printf("origin|%d|%d\n",
-	    (int)json_integer_value(prop_origin_x),
-	    (int)json_integer_value(prop_origin_y));
+	printf("player-origin|%d|%d\n",
+	    (int)json_integer_value(x),
+	    (int)json_integer_value(y));
+}
+
+static void
+write_player_sprite(const json_t *props)
+{
+	const json_t *sprite, *w, *h;
+
+	sprite = find_property(props, "player-sprite");
+	w = find_property(props, "player-sprite-w");
+	h = find_property(props, "player-sprite-h");
+
+	if (!sprite || !json_is_string(sprite) ||
+	    !w      || !json_is_integer(w)     ||
+	    !h      || !json_is_integer(h))
+		return;
+
+	printf("player-sprite|%d|%d|%s\n",
+	    (int)json_integer_value(w),
+	    (int)json_integer_value(h),
+	    json_string_value(sprite)
+	);
 }
 
 static void
 write_properties(const json_t *props)
 {
-	write_origin(props);
+	write_player_origin(props);
+	write_player_sprite(props);
 }
 
 static void