Mercurial > molko
changeset 41:3996f873a54b
core: implement walksprite, closes #2455
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 15 Jan 2020 13:11:47 +0100 |
parents | 2a087210c0b8 |
children | 22a09a5ee476 |
files | Makefile src/main.c src/map.c src/map.h src/painter.c src/painter.h src/walksprite.c src/walksprite.h |
diffstat | 8 files changed, 330 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Tue Jan 14 13:40:26 2020 +0100 +++ b/Makefile Wed Jan 15 13:11:47 2020 +0100 @@ -35,6 +35,7 @@ src/sys.c \ src/texture.c \ src/util.c \ + src/walksprite.c \ src/window.c OBJS= ${SRCS:.c=.o} DEPS= ${SRCS:.c=.d}
--- a/src/main.c Tue Jan 14 13:40:26 2020 +0100 +++ b/src/main.c Wed Jan 15 13:11:47 2020 +0100 @@ -23,7 +23,10 @@ #include "error.h" #include "event.h" #include "painter.h" +#include "image.h" +#include "map.h" #include "sys.h" +#include "walksprite.h" #include "window.h" #include "util.h" @@ -34,28 +37,94 @@ (void)argv; struct clock clock; + struct map map; + struct texture *guy; + struct sprite sprite; + struct walksprite ws; if (!sys_init()) error_fatal(); if (!window_init("Molko's Adventure", 1024, 576)) error_fatal(); + if (!map_open(&map, "world.json")) + error_fatal(); + if (!(guy = image_openf(sys_datapath("sprites/test-walk.png")))) + error_fatal(); + sprite_init(&sprite, guy, 48, 48); + walksprite_init(&ws, &sprite, 200); clock_start(&clock); + map_repaint(&map); + + int guy_x = 10; + int guy_y = 10; + int guy_dx = 0; + int guy_dy = 0; + + int dx = 0; + int dy = 0; + int orientation = 0; for (;;) { - /*uint64_t elapsed = clock_elapsed(&clock);*/ + uint64_t elapsed = clock_elapsed(&clock); union event ev; + clock_start(&clock); + while (event_poll(&ev)) { switch (ev.type) { case EVENT_QUIT: return 0; + case EVENT_KEYDOWN: + switch (ev.key.key) { + case KEY_UP: + orientation = 0; + dy = -5; + break; + case KEY_RIGHT: + orientation = 2; + dx = 5; + break; + case KEY_DOWN: + orientation = 4; + dy = 5; + break; + case KEY_LEFT: + orientation = 6; + dx = -5; + break; + default: + break; + } + break; + case EVENT_KEYUP: + switch (ev.key.key) { + case KEY_DOWN: + dy = 0; + break; + case KEY_UP: + dy = 0; + break; + case KEY_LEFT: + dx = 0; + break; + case KEY_RIGHT: + dx = 0; + break; + default: + break; + } + break; default: break; } } + map_move(&map, map.x + dx, map.y + dy); + walksprite_update(&ws, elapsed); painter_clear(); + map_draw(&map); + walksprite_draw(&ws, orientation, 100, 100); painter_present(); delay(50); }
--- a/src/map.c Tue Jan 14 13:40:26 2020 +0100 +++ b/src/map.c Wed Jan 15 13:11:47 2020 +0100 @@ -21,10 +21,13 @@ #include <stdlib.h> #include <string.h> +#include "error.h" +#include "error_p.h" #include "map.h" #include "image.h" #include "texture.h" #include "sprite.h" +#include "painter.h" #include <SDL.h> @@ -143,14 +146,56 @@ fclose(fp); + if (map->width == 0 || map->tilewidth == 0) + return error_printf("map width is null"); + if (map->height == 0 || map->tileheight == 0) + return error_printf("map height is null"); + + size_t pw = map->width * map->tilewidth; + size_t ph = map->height * map->tileheight; + + if (!(map->picture = texture_new(pw, ph))) + return error_sdl(); + return true; } void map_draw(struct map *map) { + /* TODO: coordinates here */ + /* TODO: remove window size here */ + texture_draw_ex( + map->picture, + map->x, + map->y, + 1024, + 576, + 0, + 0, + 1024, + 576, + 0 + ); +} + +void +map_repaint(struct map *map) +{ + struct texture *old; + + old = painter_get_target(); + painter_set_target(map->picture); draw_layer(map, &map->layers[0]); draw_layer(map, &map->layers[1]); + painter_set_target(old); +} + +void +map_view(struct map *map, uint64_t x, uint64_t y) +{ + map->x = x; + map->y = y; } void @@ -160,6 +205,8 @@ if (map->tileset) texture_close(map->tileset); + if (map->picture) + texture_close(map->picture); free(map->layers[0].tiles); free(map->layers[1].tiles);
--- a/src/map.h Tue Jan 14 13:40:26 2020 +0100 +++ b/src/map.h Wed Jan 15 13:11:47 2020 +0100 @@ -49,7 +49,10 @@ struct map { char title[MAP_TITLE_MAX]; /*!< (RW) The map title */ struct texture *tileset; /*!< (RW) Tileset to use */ + struct texture *picture; /*!< (RO) Map drawn into a picture */ struct sprite sprite; /*!< (RO) Sprite to render */ + uint64_t x; + uint64_t y; uint16_t width; /*!< (RO) Map width in cells */ uint16_t height; /*!< (RO) Map height in cells */ uint8_t tilewidth; /*!< (RO) Pixels per cell (width) */ @@ -79,6 +82,27 @@ map_draw(struct map *map); /** + * Force map repaint on its texture. + * + * \pre map != NULL + * \param map the map to repaint + * \warning This function does not render anything on the screen + */ +void +map_repaint(struct map *map); + +/** + * Move the origin of the picture rect to view. + * + * \param map the map + * \param x the x coordinate + * \param y the y coordinate + * \note This function may adjust the coordinates if needed + */ +void +map_view(struct map *map, uint64_t x, uint64_t y); + +/** * Close the map and its resources. * * \pre map != NULL
--- a/src/painter.c Tue Jan 14 13:40:26 2020 +0100 +++ b/src/painter.c Wed Jan 15 13:11:47 2020 +0100 @@ -21,9 +21,18 @@ #include "texture_p.h" #include "window_p.h" +static struct texture *renderer; + +struct texture * +painter_get_target(void) +{ + return renderer; +} + void -painter_use(struct texture *tex) +painter_set_target(struct texture *tex) { + renderer = tex; SDL_SetRenderTarget(win.renderer, tex ? tex->handle : NULL); }
--- a/src/painter.h Tue Jan 14 13:40:26 2020 +0100 +++ b/src/painter.h Wed Jan 15 13:11:47 2020 +0100 @@ -30,14 +30,27 @@ struct texture; /** + * Give the current texture being used for rendering, maybe NULL if the + * rendering is on root. + * + * \return texture or NULL + */ +struct texture * +painter_get_target(void); + +/** * Set the rendering context to the given texture. * + * Since this function change an internal global variable it is strongly + * encouraged to store a local backup of the current texture using \a + * painter_get_target and call this function with it afterwards. + * * If texture is NULL, use default context aka the window. * * \param tex the texture */ void -painter_use(struct texture *tex); +painter_set_target(struct texture *tex); /** * Get the current drawing color.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/walksprite.c Wed Jan 15 13:11:47 2020 +0100 @@ -0,0 +1,60 @@ +/* + * walksprite.c -- sprite designed for walking entities + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <string.h> + +#include "walksprite.h" +#include "sprite.h" + +void +walksprite_init(struct walksprite *ws, struct sprite *sprite, uint16_t delay) +{ + assert(ws); + assert(sprite); + + memset(ws, 0, sizeof (struct walksprite)); + ws->sprite = sprite; + ws->delay = delay; +} + +void +walksprite_update(struct walksprite *ws, unsigned ticks) +{ + assert(ws); + + ws->elapsed += ticks; + + if (ws->elapsed >= ws->delay) { + ws->index += 1; + + if (ws->index >= ws->sprite->ncols) + ws->index = 0; + + ws->elapsed = 0; + } +} + +void +walksprite_draw(struct walksprite *ws, uint8_t orientation, int x, int y) +{ + assert(ws); + assert(orientation < 8); + + sprite_draw(ws->sprite, orientation, ws->index, x, y); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/walksprite.h Wed Jan 15 13:11:47 2020 +0100 @@ -0,0 +1,104 @@ +/* + * walksprite.h -- sprite designed for walking entities + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_WALKSPRITE_H +#define MOLKO_WALKSPRITE_H + +/** + * \file walksprite.h + * \brief Sprite designed for walking entities. + */ + +#include <stdint.h> + +struct sprite; + +/** + * \brief Sprite designed for walking entities. + * + * This structure works with sprite images that are defined as using the + * following conventions: + * + * ``` + * 7 0 1 + * ↖ ↑ ↗ + * 6 ← → 2 + * ↙ ↓ ↘ + * 5 4 3 + * ``` + * + * Where numbers define row in the sprite according to the character + * orientation. In other terms, your image sprite should look like this: + * + * ``` + * row columns in your image + * ---|--------------------- + * 0 | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ + * 1 | ↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗ + * 2 | →→→→→→→→→→→→→→→→→→→→ + * 3 | ↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘ + * 4 | ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ + * 5 | ↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙ + * 6 | ←←←←←←←←←←←←←←←←←←←← + * 7 | ↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖ + * ``` + */ +struct walksprite { + struct sprite *sprite; /*!< (RW) The sprite to use */ + uint16_t delay; /*!< (RW) The delay between frames */ + uint8_t index; /*!< (RO) Current column index */ + uint16_t elapsed; /*!< (RO) Elapsed time since last frame */ +}; + +/** + * Initialize the walking sprite. + * + * \pre ws != NULL + * \pre sprite != NULL + * \param ws the walking sprite + * \param sprite the sprite to use + * \param delay the delay between sprites + */ +void +walksprite_init(struct walksprite *ws, struct sprite *sprite, uint16_t delay); + +/** + * Update the walking sprite + * + * \pre ws != NULL + * \param ws the walking sprite + * \param ticks the number of milliseconds between last frame + */ +void +walksprite_update(struct walksprite *ws, unsigned ticks); + +/** + * Draw the appropriate sprite cell to the screen according to the orientation + * given. + * + * \pre ws != NULL + * \pre orientation < 8 + * \param ws the walking sprite + * \param orientation the orientation (or the row between 0 and 7) + * \param x the x coordinate + * \param y the y coordinate + */ +void +walksprite_draw(struct walksprite *ws, uint8_t orientation, int x, int y); + +#endif /* !MOLKO_WALKSPRITE_H */