summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzlago2024-09-29 22:45:59 +0200
committerzlago2024-09-30 08:00:53 +0200
commit5ead22e91fe1165f3a9208c0d1c965b3edd104be (patch)
treee65535660d507fcfd17cfa75bf59ddc58ae46c94 /src
parente304b0a4acc3f0870f55e6b584c464096333dfdc (diff)
player entity
Diffstat (limited to 'src')
-rw-r--r--src/main.c22
-rw-r--r--src/main.h26
-rw-r--r--src/player.c142
-rw-r--r--src/tilemap.c65
-rw-r--r--src/tilemap.h7
5 files changed, 252 insertions, 10 deletions
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 <SDL2/SDL.h>
-extern void /*SDL_Window*/ *window;
-extern void /*SDL_Renderer*/ *renderer;
+#include <SDL2/SDL.h>
+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 <stdbool.h>
+
+#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);