From 45a781a5af1107c7511fba7d4b4b66588cbf008f Mon Sep 17 00:00:00 2001 From: zlago Date: Wed, 9 Oct 2024 06:10:39 +0200 Subject: start working on the first enemy --- src/funsinit.c | 3 + src/walker.c | 329 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 332 insertions(+) create mode 100644 src/walker.c (limited to 'src') diff --git a/src/funsinit.c b/src/funsinit.c index 25ba630..264a653 100644 --- a/src/funsinit.c +++ b/src/funsinit.c @@ -2,9 +2,12 @@ #include "loader.h" #include "main.h" +void *walker_new(struct entities *entities); +int walker_property(void *const restrict entity, char const *const restrict property, char const *const restrict value); void *warp_new(struct entities *entities); int warp_property(void *const restrict entity, char const *const restrict property, char const *const restrict value); void funs_init(void) { + res_push_fun(walker_new, walker_property, "walker"); res_push_fun(warp_new, warp_property, "warp"); } diff --git a/src/walker.c b/src/walker.c new file mode 100644 index 0000000..9a74816 --- /dev/null +++ b/src/walker.c @@ -0,0 +1,329 @@ +#include "main.h" +#include "entity.h" +#include "loader.h" +#include "input.h" +#include "tilemap.h" +#include + +#define SIZE 4 +#define ACCELERATION 2 +#define FRICTION 3 +#define MAX_SPEED 16 +#define GRAVITY 2 +#define JUMP 40 + +enum { + WALKER_NONE, + WALKER_IDLE, + WALKER_PATROL, + WALKER_ALERT, + WALKER_ATTACK, +}; + +enum { + WALKER_A_IDLE, + WALKER_A_IDLE2, + WALKER_A_WALK, + WALKER_A_WALK2, + WALKER_A_WALK3, + WALKER_A_WALK4, + WALKER_A_JUMP, + WALKER_A_FALL, + WALKER_A_FALL2, +}; + +struct anim walker_anims[] = { + {WALKER_A_IDLE2, {0, 0, 16, 16}, 300}, + {WALKER_A_IDLE, {0, 32, 16, 16}, 2}, + {WALKER_A_WALK2, {0, 0, 16, 16}, 6}, + {WALKER_A_WALK3, {16, 0, 16, 16}, 6}, + {WALKER_A_WALK4, {32, 0, 16, 16}, 6}, + {WALKER_A_WALK, {48, 0, 16, 16}, 6}, + {WALKER_A_JUMP, {16, 0, 16, 16}, 300}, + {WALKER_A_FALL2, {32, 0, 16, 16}, 15}, + {WALKER_A_FALL2, {48, 0, 16, 16}, 15}, +}; + +static int bullet_update(struct projectile *self) { + self->x += self->velocity.x; + if (collision_solid(tilemap_tile(tilemap, from_fixed(self->x), from_fixed(self->y)))) { + self->velocity.x = -self->velocity.x; + self->x += self->velocity.x; + } + + self->y += self->velocity.y; + if (collision_solid(tilemap_tile(tilemap, from_fixed(self->x), from_fixed(self->y)))) { + self->velocity.y = -self->velocity.y; + self->y += self->velocity.y; + } + + self->hp--; + int x = from_fixed(self->x); + int y = from_fixed(self->y); + self->hitbox = (struct hitbox) {.left = x, .right = x, .top = y, .bottom = y}; + #if 0 + struct particle *part = entities.particle + entities.particles; + part->x = self->x + to_fixed(self->facing >= 0? sin(self->hp): -sin(self->hp)) * 6; + part->y = self->y - to_fixed(cos(self->hp)) * 4; + part->velocity = (struct vec2) {0, 0}; + part->rect = (SDL_Rect) {0, 0, 4, 4}; + part->acceleration = (struct vec2) {0, 0}; + part->hp = 5; + entities.particles++; + #endif + if (self->hp == 0) { + return 1; + self->state = 0; + } + return 0; +} + +static int bullet_draw(struct projectile *self, int camX, int camY) { + SDL_Rect rect = {4, 0, 4, 4}; + SDL_RenderCopy(renderer, self->texture, &rect, &(SDL_Rect) {from_fixed(self->x) - camX - 1, from_fixed(self->y) - camY - 1, 4, 4}); + SDL_RenderCopy(renderer, self->texture, &rect, &(SDL_Rect) {from_fixed(self->x - self->velocity.x) - camX - 1, from_fixed(self->y - self->velocity.y) - camY - 1, 4, 4}); + //SDL_RenderFillRect(renderer, &(SDL_Rect) {from_fixed(self->x) - camX - 8, from_fixed(self->y) - camY - 12, 16, 16}); + return 0; +} + +static void bullet_free(struct projectile *self) {} + +static collision_T collide(struct entity *self) { + return tilemap_area(tilemap, from_fixed(self->x) - SIZE / 2, from_fixed(self->y) - SIZE, from_fixed(self->x) + SIZE / 2, from_fixed(self->y)); +} + +static int move(struct entity *self, signed direction) { + int on_ground = false; + int const dx = direction * ACCELERATION; + self->velocity.x += dx; + // deaccel + 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; + } + } + // speed cap + if (self->velocity.x > MAX_SPEED) { + self->velocity.x = MAX_SPEED; + } else if (self->velocity.x < -MAX_SPEED) { + self->velocity.x = -MAX_SPEED; + } + // x collision + self->x += self->velocity.x; + collision_T const cx = collide(self); + if (collision_solid(cx)) { + if (self->velocity.x < 0) { + self->x += to_fixed(8) - ((self->x - to_fixed(SIZE / 2)) % to_fixed(8)); // left + } else if (self->velocity.x == 0) { + //fputs("what?\n", stderr); + } else { + self->x -= ((self->x + to_fixed(SIZE / 2)) % to_fixed(8)); // right + } + self->velocity.x = 0; + } + if (self->velocity.x < 0) { + self->facing = -1; + } else if (self->velocity.x > 0) { + self->facing = +1; + } + self->velocity.y += GRAVITY; + // y collision + self->y += self->velocity.y; + collision_T const cy = collide(self); + if (collision_solid(cy)) { + if (self->velocity.y < 0) { + self->y += to_fixed(8) - ((self->y - to_fixed(SIZE)) % 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(8)); // down + self->velocity.y = to_fixed(1); // crazy but it works + on_ground = true; + } + } + + if (collision_hazard(cx | cy)) { + self->hurt(self, 1); + } + + self->hitbox.left = from_fixed(self->x) - SIZE / 2; + self->hitbox.right = from_fixed(self->x) + SIZE / 2; + self->hitbox.top = from_fixed(self->y) - SIZE; + self->hitbox.bottom = from_fixed(self->y); + return on_ground; +} + +static void anim(struct entity *self, unsigned anim) { + self->anim = walker_anims[anim]; +} + +static void attack(struct entity *self) { + entities.projectile[entities.projectiles] = (struct projectile) { + .update = bullet_update, + .draw = bullet_draw, + .free = bullet_free, + .x = self->x, .y = self->y - to_fixed(3), + .velocity = (struct vec2) {self->velocity.x + to_fixed(self->facing), 0}, + .hitbox = { + 0, 0, 0, 0, + }, + .state = WALKER_IDLE, + .hp = 300, + .timer = 0, + .facing = self->facing, + .faction = FACTION_ENEMY, + .iframes = 0, + .texture = NULL, + .ext = NULL, + }; + //anim(entities->projectile + entities->projectiles, WALKER_A_IDLE); + entities.projectile[entities.projectiles].texture = res_get_texture("particles").data; + entities.projectiles++; +} + +static int walker_update(struct entity *self) { + if (self->hp <= 0) { + self->state = 0; + entities.enemies--; + return 1; + } + switch (self->state) { + case WALKER_IDLE: + if (move(self, 0) == false) { + abort(); + self->velocity.y = 0; + anim(self, WALKER_A_FALL); + //self->state = WALKER_FALL; + } + self->timer--; + if (self->timer == 0) { + self->facing = -self->facing; + anim(self, WALKER_A_WALK); + self->state = WALKER_PATROL; + } + break; + + case WALKER_PATROL: + if (move(self, self->facing) == false) { + abort(); + self->velocity.y = 0; + anim(self, WALKER_A_FALL); + //self->state = WALKER_FALL; + } + if (collision_solid(tilemap_tile(tilemap, from_fixed(self->x) + self->facing * 8, from_fixed(self->y) - 4)) || + !collision_solid(tilemap_tile(tilemap, from_fixed(self->x) + self->facing * 8, from_fixed(self->y) + 4))) { + anim(self, WALKER_A_IDLE); + self->state = WALKER_IDLE; + self->timer = 30; + } + break; + + case WALKER_ALERT: + attack(self); + if (!input_a(input_held)) { + self->velocity.y /= 2; + anim(self, WALKER_A_FALL); + //self->state = WALKER_FALL; + } + if (self->velocity.y > 0) { + anim(self, WALKER_A_FALL); + //self->state = WALKER_FALL; + } + if (move(self, 0) == true) { + anim(self, WALKER_A_IDLE); + self->state = WALKER_IDLE; + } + break; + + case WALKER_ATTACK: + if (move(self, 0) == true) { + anim(self, WALKER_A_IDLE); + self->state = WALKER_IDLE; + } + break; + } + if (self->iframes > 0) { + self->iframes--; + } + self->anim.length--; + if (self->anim.length == 0) { + anim(self, self->anim.frame); + } + return 0; +} + +static int walker_hurt(struct entity *self, int damage) { + if (self->iframes == 0) { + self->hp -= damage; + self->iframes = 60; + for (int x = -1; x <= 1; x += 2) { + for (int y = -1; y <= 1; y += 2) { + struct particle *part = entities.particle + entities.particles; + part->x = self->x; + part->y = self->y; + part->velocity = (struct vec2) {to_fixed(x), to_fixed(y) - 8}; + part->rect = (SDL_Rect) {4, 0, 4, 4}; + part->acceleration = (struct vec2) {0, 1}; + part->hp = 30; + entities.particles++; + } + } + } + return 0; +} + +static int walker_draw(struct entity *self, int camX, int camY) { + if (!(self->iframes & 0x4)) { + SDL_Rect rect = self->anim.rect; + if (self->facing == -1) { + rect.y += 16; + } + SDL_RenderCopy(renderer, self->texture, &rect, &(SDL_Rect) {from_fixed(self->x) - camX - 8, from_fixed(self->y) - camY - 12, 16, 16}); + } + return 0; +} + +static void walker_free(struct entity *self) { + self->state = 0; +} + +struct entity *walker_new(struct entities *entities) { + entities->enemy[entities->enemies] = (struct entity) { + .update = walker_update, + .hurt = walker_hurt, + .draw = walker_draw, + .free = walker_free, + .x = 0, .y = 0, + .velocity = {.x = 0, .y = to_fixed(1)}, + .hitbox = { + 0, 0, 0, 0, + }, + .state = WALKER_PATROL, + .hp = 3, + .timer = 0, + .facing = 1, + .faction = FACTION_ENEMY, + .iframes = 0, + .texture = NULL, + .ext = NULL, + }; + anim(entities->enemy + entities->enemies, WALKER_A_IDLE); + entities->enemy[entities->enemies].texture = res_get_texture("fywi").data; + return entities->enemy + entities->enemies++; +} + +int walker_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; +} -- cgit 1.4.1-2-gfad0