From 5ead22e91fe1165f3a9208c0d1c965b3edd104be Mon Sep 17 00:00:00 2001 From: zlago Date: Sun, 29 Sep 2024 22:45:59 +0200 Subject: player entity --- GNUmakefile | 2 + assets.mk | 2 +- src/main.c | 22 +++++++-- src/main.h | 26 +++++++++-- src/player.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tilemap.c | 65 +++++++++++++++++++++++++-- src/tilemap.h | 7 +++ 7 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 src/player.c diff --git a/GNUmakefile b/GNUmakefile index 314ea69..2e4afa6 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -28,6 +28,8 @@ out/${NS}/: out/: ${MKDIR} $@ +out/${NS}/libplum.o: cflags += -w + out/${NS}/%.o: src/%.c out/${NS}/%.d | out/${NS}/ ${CC} -c -o $@ $< ${cflags} diff --git a/assets.mk b/assets.mk index f2e47e7..340871c 100644 --- a/assets.mk +++ b/assets.mk @@ -14,7 +14,7 @@ out/%.png: src/res/%.ase | out/ out/set.%.png: src/res/set/%.ase | out/ ${PRITE} -b $(abspath $<) --save-as $(abspath $@) -out/%.png: out/set.%.png | out/ +out/%.png: out/set.%.png | out/rearrange out/rearrange $@ $< out/%.json: src/res/%.tmx ${tilesets} ${images} | out/ diff --git a/src/main.c b/src/main.c index eccd351..0e53a68 100644 --- a/src/main.c +++ b/src/main.c @@ -13,6 +13,8 @@ #include "incbin.h" #include "libplum.h" +#include "main.h" + SDL_Window *window = NULL; SDL_Renderer *renderer = NULL; @@ -30,6 +32,11 @@ SDL_Scancode keybinds[] = { SDL_SCANCODE_S, }; +struct entity player[1] = {0}; + +struct entity *player_new(void); +int player_property(struct entity *const restrict entity, char const *const restrict property, char const *const restrict value); + int main(int argc, char **argv) { if (SDL_Init(INIT_SUBSYSTEMS)) { fprintf(stderr, "failed to initialize SDL2: %s\n", SDL_GetError()); @@ -59,6 +66,7 @@ int main(int argc, char **argv) { free(a); struct blob map = res_get_map("untitled"); tilemap = tilemap_load(map.data, map.size); + //memmem(map.data + tilemap->byte_count, map.size - tilemap->byte_count, (char []) {0, 0}, 2); printf("load_tilemap %p\n", (void *) tilemap); SDL_SetRenderTarget(renderer, NULL); } @@ -83,6 +91,9 @@ int main(int argc, char **argv) { SDL_ShowWindow(window); int x = 0, y = 0; + player_new(); + player_property(player, "x", "40"); + player_property(player, "y", "40"); while (1) { SDL_Event evt; while (SDL_PollEvent(&evt)) { @@ -183,13 +194,18 @@ int main(int argc, char **argv) { SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); - x += input_right(input_now) - input_left(input_now); - y += input_down(input_now) - input_up(input_now); + //SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90}); + player[0].update(player); + + //x += input_right(input_now) - input_left(input_now); + //y += input_down(input_now) - input_up(input_now); + x = (player[0].x / 16) - (WINDOW_WIDTH / 2); + y = (player[0].y / 16) - (WINDOW_HEIGHT / 2); if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;} if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;} - //SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90}); tilemap_background(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT); + player[0].draw(player, x, y); tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT); //SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90}); // then we wait for the next video frame diff --git a/src/main.h b/src/main.h index 0595b37..26c4cf1 100644 --- a/src/main.h +++ b/src/main.h @@ -1,3 +1,23 @@ -//#include -extern void /*SDL_Window*/ *window; -extern void /*SDL_Renderer*/ *renderer; +#include +extern SDL_Window *window; +extern SDL_Renderer *renderer; + +extern unsigned input_now; + +extern struct entity { + int (*update)(struct entity *self); + int (*hurt)(struct entity *self, int damage); + int (*draw)(struct entity *self, int camx, int camy); + int x, y; // unsigned results in a bunch of weird edge cases + struct velocity { + signed x, y; + } velocity; + struct hitbox { + unsigned left, right, top, bottom; + } hitbox; + unsigned state; + int hp; + int timer; + void *texture; + void *ext; +} player[1]; diff --git a/src/player.c b/src/player.c new file mode 100644 index 0000000..4eba788 --- /dev/null +++ b/src/player.c @@ -0,0 +1,142 @@ +#include "main.h" +#include "input.h" +#include "loader.h" +#include "tilemap.h" +#include + +#define from_fixed(a) (a / 16) +#define to_fixed(a) (a * 16) + +enum { + PLAYER_IDLE, + PLAYER_JUMP, + PLAYER_FALL, +}; + +#define SIZE 8 +#define ACCELERATION 1 +#define FRICTION 2 +#define MAX_SPEED 12 +#define GRAVITY 1 + +static int move(struct entity *self) { + int dx = (input_right(input_now) - input_left(input_now)) * ACCELERATION; + self->velocity.x += dx; + if (dx == 0) { + if (self->velocity.x < -FRICTION) { + self->velocity.x += FRICTION; + } else if (self->velocity.x > FRICTION) { + self->velocity.x -= FRICTION; + } else { + self->velocity.x = 0; + } + } + if (self->velocity.x > MAX_SPEED) { + self->velocity.x = MAX_SPEED; + } else if (self->velocity.x < -MAX_SPEED) { + self->velocity.x = -MAX_SPEED; + } + self->x += self->velocity.x; + if (collision_solid(tilemap_area(tilemap, from_fixed(self->x), from_fixed(self->y), from_fixed(self->x) + SIZE, from_fixed(self->y) + SIZE))) { + if (self->velocity.x < 0) { + self->x += to_fixed(8) - ((self->x) % to_fixed(8)); // left + } else if (self->velocity.x == 0) { + //fputs("what?\n", stderr); + } else { + self->x -= ((self->x + to_fixed(SIZE)) % to_fixed(8)); // right + } + self->velocity.x = 0; + } + self->velocity.y += GRAVITY; + self->y += self->velocity.y; + //self->y += (input_down(input_now) - input_up(input_now)) * 8; + if (collision_solid(tilemap_area(tilemap, from_fixed(self->x), from_fixed(self->y), from_fixed(self->x) + SIZE, from_fixed(self->y) + SIZE))) { + if (self->velocity.y < 0) { + self->y += to_fixed(8) - ((self->y) % to_fixed(8)); // up + self->velocity.y = 0; + } else if (self->velocity.y == 0) { + //fputs("what?\n", stderr); + } else { + self->y -= ((self->y + to_fixed(SIZE)) % to_fixed(8)); // down + self->velocity.y = to_fixed(1); // crazy but it works + return true; + } + } + return false; +} + +static int player_update(struct entity *self) { + switch (self->state) { + case PLAYER_IDLE: + if (move(self) == true) { + if (input_a(input_now)) { + self->velocity.y = -30; + self->state = PLAYER_JUMP; + } + } else { + self->state = PLAYER_FALL; + } + break; + + case PLAYER_JUMP: + if (!input_a(input_now)) { + self->velocity.y /= 2; + self->state = PLAYER_FALL; + } + if (self->velocity.y > 0) { + self->state = PLAYER_FALL; + } + if (move(self) == true) { + self->state = PLAYER_IDLE; + } + break; + + case PLAYER_FALL: + if (move(self) == true) { + self->state = PLAYER_IDLE; + } + break; + } + return 0; +} + +static int player_hurt(struct entity *self, int damage) { + return 0; +} + +static int player_draw(struct entity *self, int camX, int camY) { + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderCopy(renderer, self->texture, &(SDL_Rect) {0, 0, 16, 16}, &(SDL_Rect) {from_fixed(self->x) - camX - 4, from_fixed(self->y) - camY - 4, 16, 16}); + return 0; +} + +struct entity *player_new(void) { + player[0] = (struct entity) { + .update = player_update, + .hurt = player_hurt, + .draw = player_draw, + .x = 0, .y = 0, + .velocity = {.x = 0, .y = 0}, + .hitbox = { + 0, 0, 0, 0, + }, + .state = PLAYER_IDLE, + .hp = 3, + .timer = 0, + .texture = NULL, + .ext = NULL, + }; + player[0].texture = res_get_texture("fywi").data; + return player + 0; +} + +int player_property(struct entity *const restrict self, char const *const restrict property, char const *const restrict value) { + if (strcmp(property, "x") == 0) { + self->x = to_fixed(atoi(value)); + } else if (strcmp(property, "y") == 0) { + self->y = to_fixed(atoi(value)); + } else { + return 1; + } + return 0; +} diff --git a/src/tilemap.c b/src/tilemap.c index af2c163..7dbc4dd 100644 --- a/src/tilemap.c +++ b/src/tilemap.c @@ -33,6 +33,56 @@ struct PACKED map { uint8_t tiles[]; }; +collision_T tilemap_tile_raw(struct tilemap *tilemap, int x, int y) { + return tilemap->collision[x + y * tilemap->width]; +} + +collision_T tilemap_tile(struct tilemap *tilemap, int x, int y) { + x /= 8; + y /= 8; + if (x < 0) { + x = 0; + } else if ((unsigned) x >= tilemap->width) { + x = tilemap->width - 1; + } + if (y < 0) { + y = 0; + } else if ((unsigned) y >= tilemap->height) { + y = tilemap->height - 1; + } + return tilemap_tile_raw(tilemap, x, y); +} + +collision_T tilemap_area_raw(struct tilemap *tilemap, int x1, int y1, int x2, int y2) { + collision_T value = 0; + for (int x = x1; x <= x2; x++) { + for (int y = y1; y <= y2; y++) { + value |= tilemap->collision[x + y * tilemap->width]; + } + } + return value; +} + +collision_T tilemap_area(struct tilemap *tilemap, int x1, int y1, int x2, int y2) { + x1 /= 8; + y1 /= 8; + x2 = (x2 - 1) / 8; + y2 = (y2 - 1) / 8; + if (x1 < 0) { + x1 = 0; + } + if (x2 >= tilemap->width) { + x2 = tilemap->width - 1; + } + if (y1 < 0) { + y1 = 0; + } + if (y2 >= tilemap->height) { + y2 = tilemap->height - 1; + } + return tilemap_area_raw(tilemap, x1, y1, x2, y2); +} + void tilemap_background(struct tilemap *tilemap, int x, int y, int w, int h) { SDL_SetRenderDrawColor(renderer, tilemap->backdrop.r, tilemap->backdrop.g, tilemap->backdrop.b, tilemap->backdrop.a); SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, w, h}); @@ -103,13 +153,20 @@ struct tilemap *tilemap_load(void *data, size_t size) { 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; + if (col.data != NULL) { // silence -fsanitize=undefined + 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)); } - memcpy(collision + y * 2, col.data, col.size * sizeof (collision_T)); y += height; + if (y + height > 0xf0) { + fputs("error: too many tiles\n", stderr); + tilemap_free(tilemap); + return NULL; + } str += len + 1; size -= len + 4 + 1; } diff --git a/src/tilemap.h b/src/tilemap.h index 912b67f..ae42c9c 100644 --- a/src/tilemap.h +++ b/src/tilemap.h @@ -19,6 +19,13 @@ extern struct tilemap { size_t input_bytes; } *tilemap, *next_tilemap; +// tilemap collision functions +collision_T tilemap_tile_raw(struct tilemap *tilemap, int x, int y); +collision_T tilemap_tile(struct tilemap *tilemap, int x, int y); + +collision_T tilemap_area_raw(struct tilemap *tilemap, int x1, int y1, int x2, int y2); +collision_T tilemap_area(struct tilemap *tilemap, int x1, int y1, int x2, int y2); + // render the fore/back ground of the tilemap to `renderer` void tilemap_background(struct tilemap *tilemap, int x, int y, int w, int h); void tilemap_foreground(struct tilemap *tilemap, int x, int y, int w, int h); -- cgit 1.4.1-2-gfad0