summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
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);