From 6bd6757583510ba3edf75451309e4b8ec8c9b0f1 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Sun, 25 Jun 2023 22:44:23 +0100 Subject: Add entity system, add new enemy (snake) --- TODO.md | 3 -- data/stage.json | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/Makefile | 2 +- src/entities.c | 72 +++++++++++++++++++++++++++++++++++ src/entities.h | 34 +++++++++++++++++ src/game.c | 6 +++ src/map.c | 45 ++++++++++++++++++++-- src/map.h | 5 --- src/player.c | 17 +++++++-- src/player.h | 1 + src/snake.c | 69 ++++++++++++++++++++++++++++++++++ src/snake.h | 7 ++++ tools/map.py | 2 +- 13 files changed, 358 insertions(+), 19 deletions(-) create mode 100644 src/entities.c create mode 100644 src/entities.h create mode 100644 src/snake.c create mode 100644 src/snake.h diff --git a/TODO.md b/TODO.md index 556dfb2..792c458 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,5 @@ # TODO -- entity system - - free/used lists - pick ups - extra time - bonuses @@ -9,7 +7,6 @@ - key / doors - end of stage - enemies - - pattern (snake) - flying (bat) - free - tracker diff --git a/data/stage.json b/data/stage.json index 2ae131e..9095400 100644 --- a/data/stage.json +++ b/data/stage.json @@ -41,6 +41,118 @@ "width":16, "x":16, "y":128 + }, + { + "height":16, + "id":2, + "name":"Snake", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":216, + "y":128 + }, + { + "height":16, + "id":3, + "name":"Snake", + "properties":[ + { + "name":"dir", + "type":"string", + "value":"left" + }], + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":288, + "y":128 + }, + { + "height":16, + "id":4, + "name":"Snake", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":184, + "y":152 + }, + { + "height":16, + "id":5, + "name":"Snake", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":32, + "y":152 + }, + { + "height":16, + "id":6, + "name":"Snake", + "properties":[ + { + "name":"dir", + "type":"string", + "value":"left" + }], + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":280, + "y":152 + }, + { + "height":16, + "id":7, + "name":"Snake", + "properties":[ + { + "name":"dir", + "type":"string", + "value":"left" + }], + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":112, + "y":152 + }, + { + "height":16, + "id":8, + "name":"Snake", + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":144, + "y":32 + }, + { + "height":16, + "id":9, + "name":"Snake", + "properties":[ + { + "name":"dir", + "type":"string", + "value":"left" + }], + "rotation":0, + "type":"", + "visible":true, + "width":16, + "x":112, + "y":80 }], "opacity":1, "type":"objectgroup", @@ -49,7 +161,7 @@ "y":0 }], "nextlayerid":4, - "nextobjectid":2, + "nextobjectid":10, "orientation":"orthogonal", "renderorder":"right-down", "tiledversion":"1.7.2", diff --git a/src/Makefile b/src/Makefile index 8f3c13a..4c26b5b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,6 @@ BIN := ../game.exe CC := i586-pc-msdosdjgpp-gcc -CFLAGS := -I. -c -Wall -Werror -pedantic -O2 -march=i386 +CFLAGS := -I. -c -Wall -Werror -pedantic -O2 -march=i386 -DDEBUG LDFLAGS := -s IMGS := $(wildcard ../data/*.png) diff --git a/src/entities.c b/src/entities.c new file mode 100644 index 0000000..be976ea --- /dev/null +++ b/src/entities.c @@ -0,0 +1,72 @@ +#include +#include + +#include "vga.h" +#include "map.h" +#include "data.h" + +#include "entities.h" + +#define MAX_ENTITY 32 + +static Entity entities[MAX_ENTITY]; +static uint8_t last; + +void entities_init() +{ + memset(entities, 0, sizeof(Entity) * MAX_ENTITY); + last = 0; +} + +Entity *entities_new() +{ + for (uint8_t i = 0; i < MAX_ENTITY; i++) + { + if (entities[i].used == 0) + { + memset(&entities[i], 0, sizeof(Entity)); + entities[i].used = 1; + + if (i >= last) + last = i + 1; + + return &entities[i]; + } + } + + return NULL; +} + +void entities_update() +{ + Entity *e = entities; + + for (uint8_t i = 0; i < last; i++, e++) + if (e->used) + e->update(e); +} + +void entities_erase() +{ + Entity *e = entities + last - 1; + + for (uint8_t i = 0; i < last; i++, e--) + if (e->used) + { + Rect dst = { e->x, e->y + MAP_OFFS_Y, 16, 16 }; + blit(e->bg, &dst); + } +} + +void entities_draw() +{ + Entity *e = entities; + + for (uint8_t i = 0; i < last; i++, e++) + if (e->used) + { + Rect dst = { e->x, e->y + MAP_OFFS_Y, 16, 16 }; + read_buffer(e->bg, &dst); + blitrc(binary_sprites_start, &e->frames[e->dir * 4 + e->frame], &dst); + } +} diff --git a/src/entities.h b/src/entities.h new file mode 100644 index 0000000..e553390 --- /dev/null +++ b/src/entities.h @@ -0,0 +1,34 @@ +#ifndef _ENTITIES_H +#define _ENTITIES_H + +#define DIR_RIGHT 0 +#define DIR_LEFT 1 + +#define WALK_DELAY 8 + +typedef struct entity_s +{ + uint8_t used; + uint16_t x; + uint16_t y; + uint8_t dir; + uint8_t frame; + uint8_t delay; + uint8_t gravity; + uint8_t flag; + uint8_t bg[16 * 16]; + /* expected to be 2 directions per 4 frames max; 8 Rect */ + const Rect *frames; + void (*update)(struct entity_s *e); +} Entity; + +void entities_init(); + +Entity *entities_new(); + +void entities_update(); + +void entities_erase(); +void entities_draw(); + +#endif /* _ENTITIES_H */ diff --git a/src/game.c b/src/game.c index c489417..001ce21 100644 --- a/src/game.c +++ b/src/game.c @@ -7,6 +7,7 @@ #include "map.h" #include "data.h" #include "timer.h" +#include "entities.h" #include "player.h" @@ -114,6 +115,7 @@ void run_game() map_init(binary_stage_start); map_render(); + entities_draw(); player_draw(); timer_start(GAME_TIME_MAX, &clock_updated); @@ -129,10 +131,14 @@ void run_game() if (hud) hud_render(); + /* erase first the last we draw */ player_erase(); + entities_erase(); player_update(); + entities_update(); + entities_draw(); player_draw(); wait_vsync(); diff --git a/src/map.c b/src/map.c index 4c5390f..c62c5c1 100644 --- a/src/map.c +++ b/src/map.c @@ -1,18 +1,33 @@ #include +#include #include +#include #include "vga.h" #include "data.h" +#include "entities.h" #include "player.h" +#include "snake.h" #include "map.h" +typedef enum +{ + Player = 0, + Snake, +} EntityType; + /* current map; set via map_init */ static const uint8_t *cmap; static uint8_t gold[MAP_W * MAP_H]; static uint8_t total_gold; +static void (* const init[])(Entity *) = +{ + snake_init, +}; + void map_init(const uint8_t map[]) { cmap = map; @@ -27,18 +42,40 @@ void map_init(const uint8_t map[]) if (gold[i] != 0xff) total_gold++; + entities_init(); + + Entity *e; + /* spawn entities, 0xff is the list terminator */ for ( const uint8_t *ent = map + MAP_W * MAP_H * 2; *ent != 0xff; ent += 4 ) - switch (*ent) + { + /* the player is not part of the entity system */ + if (*ent == Player) { - case Player: - player_init(ent[1] * MAP_TILE_W, ent[2] * MAP_TILE_H, ent[3] & 1); - break; + player_init(ent[1] * MAP_TILE_W, ent[2] * MAP_TILE_H, ent[3] & 1); + continue; } + + e = entities_new(); +#ifdef DEBUG + if (!e) + { + set_mode(3); + fprintf(stderr, "ERROR: run out of entities\n"); + exit(1); + } +#endif + + e->x = ent[1] * MAP_TILE_W; + e->y = ent[2] * MAP_TILE_H; + e->dir = ent[3] & 1; + + init[*ent - 1](e); + } } void map_render() diff --git a/src/map.h b/src/map.h index 992c982..42f8da7 100644 --- a/src/map.h +++ b/src/map.h @@ -14,11 +14,6 @@ #define MAP_FIRST_BLOCKED 40 #define MAP_FIRST_DEADLY 100 -typedef enum -{ - Player = 0, -} EntityType; - void map_init(const uint8_t map[]); void map_render(); diff --git a/src/player.c b/src/player.c index 856cafd..ae50348 100644 --- a/src/player.c +++ b/src/player.c @@ -6,17 +6,14 @@ #include "data.h" #include "game.h" +#include "entities.h" #include "player.h" -#define DIR_RIGHT 0 -#define DIR_LEFT 1 - #define FRAME_STANDING 0 #define FRAME_JUMPING 4 #define FRAME_DYING 5 #define WALK_CYCLE_FRAMES 4 -#define WALK_DELAY 8 #define GRAVITY_OFF 0 /* XXX: subtract 1 to get the value from gravity_seq */ @@ -298,6 +295,18 @@ void player_draw() blitrc(binary_sprites_start, &frames[dir][frame], &dst); } +uint8_t player_collision(Entity *e) +{ + if (invuln || dying) + return 0; + + if (y < e->y + 16 && e->y < y + 16 + && x < e->x + 8 && e->x < x + 8) + return 1; + + return 0; +} + void player_hit() { /* TODO: pickaxe */ diff --git a/src/player.h b/src/player.h index 9767fbe..104bfee 100644 --- a/src/player.h +++ b/src/player.h @@ -7,6 +7,7 @@ void player_update(); void player_erase(); void player_draw(); +uint8_t player_collision(Entity *e); void player_hit(); #endif /* _PLAYER_H */ diff --git a/src/snake.c b/src/snake.c new file mode 100644 index 0000000..e81a1c8 --- /dev/null +++ b/src/snake.c @@ -0,0 +1,69 @@ +#include + +#include +#include "map.h" +#include "entities.h" + +#include "player.h" + +#include "snake.h" + +static const Rect frames[2 * 4] = +{ + /* right */ + { 0, 32, 144, 144 }, + { 16, 32, 144, 144 }, + /* not used */ + { 0, 0, 144, 144 }, + { 0, 0, 144, 144 }, + + /* left */ + { 32, 32, 144, 144 }, + { 48, 32, 144, 144 }, + /* not used */ + { 0, 0, 144, 144 }, + { 0, 0, 144, 144 } +}; + +void snake_init(Entity *e) +{ + e->frames = (const Rect *)frames; + e->update = snake_update; +} + +void snake_update(Entity *e) +{ + if (e->delay & 1) + { + if (e->dir == DIR_RIGHT) + { + if (map_is_blocked(e->x + 16, e->y + 15) + || !map_is_blocked(e->x + 16, e->y + 16)) + e->dir = DIR_LEFT; + else + e->x++; + } + else + { + /* dir is LEFT */ + if (map_is_blocked(e->x - 1, e->y + 15) + || !map_is_blocked(e->x - 1, e->y + 16)) + e->dir = DIR_RIGHT; + else + e->x--; + } + } + + if (player_collision(e)) + { + player_hit(); + /* change direction */ + e->dir ^= 1; + } + + if (e->delay++ == WALK_DELAY + 4) + { + e->delay = 0; + e->frame ^= 1; + } +} diff --git a/src/snake.h b/src/snake.h new file mode 100644 index 0000000..48f22e9 --- /dev/null +++ b/src/snake.h @@ -0,0 +1,7 @@ +#ifndef _SNAKE_H +#define _SNAKE_H + +void snake_init(Entity *e); +void snake_update(Entity *e); + +#endif /* _SNAKE_H */ diff --git a/tools/map.py b/tools/map.py index 7e0210f..8464c28 100755 --- a/tools/map.py +++ b/tools/map.py @@ -10,7 +10,7 @@ __version__ = "1.0" ld = os.environ.get("LD", "i586-pc-msdosdjgpp-ld") strip = os.environ.get("STRIP", "i586-pc-msdosdjgpp-strip") -entity_types = ("Player",) +entity_types = ("Player", "Snake") def get_layer(data, name): -- cgit v1.2.3