diff --git a/CMakeLists.txt b/CMakeLists.txt index 80b750c..cf3f26d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ find_package(Gint 2.1 REQUIRED) set(SOURCES src/main.c + src/engine.c # ... ) # Shared assets, fx-9860G-only assets and fx-CG-50-only assets @@ -20,6 +21,7 @@ set(ASSETS set(ASSETS_fx assets-fx/levels.png assets-fx/title.png + assets-fx/spritesheet.png assets-fx/font_mystere.png # ... ) diff --git a/MystNB.g1a b/MystNB.g1a index 43edcef..c7d3956 100644 Binary files a/MystNB.g1a and b/MystNB.g1a differ diff --git a/assets-fx/fxconv-metadata.txt b/assets-fx/fxconv-metadata.txt index 961995f..3a685d7 100644 --- a/assets-fx/fxconv-metadata.txt +++ b/assets-fx/fxconv-metadata.txt @@ -1,10 +1,6 @@ -levels.png: +*.png: type: bopti-image - name: img_levels - -title.png: - type: bopti-image - name: img_title + name_regex: (.*)\.png img_\1 font_mystere.png: type: font diff --git a/assets-fx/spritesheet.png b/assets-fx/spritesheet.png new file mode 100644 index 0000000..3bbfcd1 Binary files /dev/null and b/assets-fx/spritesheet.png differ diff --git a/src/engine.c b/src/engine.c new file mode 100644 index 0000000..d5fe81d --- /dev/null +++ b/src/engine.c @@ -0,0 +1,56 @@ +#include +#include +#include "engine.h" + +#define CELL_X(x) (-2 + 10 * (x)) +#define CELL_Y(y) (-3 + 10 * (y)) + +//--- +// Rendering +//--- + +static void engine_draw_player(struct player const *player) +{ + extern bopti_image_t img_spritesheet; + + dsubimage(CELL_X(player->x) - 1, CELL_Y(player->y) - 5, + &img_spritesheet, player->dir * 12, 0, 12, 16, DIMAGE_NONE); +} + +void engine_draw(struct game const *game) +{ + dclear(C_WHITE); + + for(int p = 0; game->players[p]; p++) + { + engine_draw_player(game->players[p]); + } +} + +//--- +// Physics +//--- + +/* Check whether a cell of the map is walkable */ +static int map_walkable(struct map const *map, int x, int y) +{ + /* TODO: Read the map's data array */ + return (x >= 1) && (y >= 1) && (x < map->w - 1) && (y < map->h - 1); +} + +int engine_move(struct game *game, struct player *player, int dir) +{ + int dx = (dir == DIR_RIGHT) - (dir == DIR_LEFT); + int dy = (dir == DIR_DOWN) - (dir == DIR_UP); + + /* Always update the direction */ + player->dir = dir; + + /* Only move the player if the destination is walkable */ + if(!map_walkable(game->map, player->x + dx, player->y + dy)) return 0; + + player->x += dx; + player->y += dy; + + return 1; +} diff --git a/src/engine.h b/src/engine.h new file mode 100644 index 0000000..2dc81bf --- /dev/null +++ b/src/engine.h @@ -0,0 +1,55 @@ +#ifndef _MYSTNB_ENGINE_H +#define _MYSTNB_ENGINE_H + +#include + +#define PLAYER_COUNT 1 + +/* Directions */ +#define DIR_DOWN 0 +#define DIR_RIGHT 1 +#define DIR_UP 2 +#define DIR_LEFT 3 + +/* struct player: A player on the map, triggering actions as they move */ +struct player +{ + /* Position in map */ + int x, y; + /* Direction currently facing */ + int dir; + /* Animation and frame */ + struct animation const *anim; + int frame; +}; + +/* struct map: A map with moving doors, collectibles, and fog */ +struct map +{ + /* Width and height */ + int w, h; + /* Whether fog is enabled */ + int fog; + /* Raw data */ + uint8_t *data; +}; + +/* struct game: A running game with a map and some players */ +struct game +{ + /* Current map */ + struct map *map; + /* Players */ + struct player *players[PLAYER_COUNT + 1]; + /* Current game time (ms) */ + int time; +}; + +/* Draw the current game frame from scratch; does not dupdate() */ +void engine_draw(struct game const *game); + +/* Try to move a player along a direction. Returns 1 if the move is successful, + 0 otherwise (collisions or out-of-bounds moves) */ +int engine_move(struct game *game, struct player *player, int direction); + +#endif /* _MYSTNB_ENGINE_H */ diff --git a/src/main.c b/src/main.c index 0a72769..19f21d4 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,8 @@ #include #include +#include "engine.h" + static void draw_menu(int selected) { extern bopti_image_t img_title; @@ -31,7 +33,7 @@ static void draw_menu(int selected) } } -int main(void) +static int main_menu(void) { extern font_t font_mystere; dfont(&font_mystere); @@ -52,5 +54,59 @@ int main(void) selected++; } + return selected; +} + +/* Returns a direction to move in */ +static int get_inputs(void) +{ + int opt = GETKEY_DEFAULT & ~GETKEY_REP_ARROWS; + + while(1) + { + int key = getkey_opt(opt, NULL).key; + + if(key == KEY_DOWN) return DIR_DOWN; + if(key == KEY_RIGHT) return DIR_RIGHT; + if(key == KEY_UP) return DIR_UP; + if(key == KEY_LEFT) return DIR_LEFT; + } +} + +int main(void) +{ + GUNUSED int level = main_menu(); + + struct player singleplayer = { + .x = 2, + .y = 3 + }; + struct map map = { + .w = 13, + .h = 7 + }; + struct game game = { + .map = &map, + .players = { &singleplayer, NULL }, + .time = 0, + }; + + int level_finished = 0; + + while(!level_finished) + { + int turn_finished = 0; + while(!turn_finished) + { + engine_draw(&game); + dupdate(); + + int dir = get_inputs(); + turn_finished = engine_move(&game, &singleplayer, dir); + } + + /* Update doors, etc */ + } + return 1; }