diff options
author | quou <quou@disroot.org> | 2024-09-30 22:13:31 +1000 |
---|---|---|
committer | quou <quou@disroot.org> | 2024-09-30 22:13:31 +1000 |
commit | ee655819d44307d974fb27e1fa04d079a3810d63 (patch) | |
tree | faa7c7c833dab0ed83dece311576b53bd2e4b840 | |
parent | de9a4fd93343d4654dfe7e2a566704644a9f306f (diff) |
enemy
-rw-r--r-- | 1bitjam.c | 1 | ||||
-rw-r--r-- | Makefile | 13 | ||||
-rw-r--r-- | config.h | 5 | ||||
-rw-r--r-- | deathzone.c | 23 | ||||
-rw-r--r-- | enemy.c | 207 | ||||
-rw-r--r-- | intermediate/demon_fly_left.anm | 2 | ||||
-rw-r--r-- | intermediate/demon_fly_right.anm | 2 | ||||
-rw-r--r-- | intermediate/demon_idle_left.anm | 5 | ||||
-rw-r--r-- | intermediate/demon_idle_right.anm | 5 | ||||
-rw-r--r-- | intermediate/demon_jump_left.anm | 5 | ||||
-rw-r--r-- | intermediate/demon_jump_right.anm | 5 | ||||
-rw-r--r-- | intermediate/demon_walk_left.anm | 5 | ||||
-rw-r--r-- | intermediate/demon_walk_right.anm | 5 | ||||
-rw-r--r-- | intermediate/npc.bmp | bin | 0 -> 37002 bytes | |||
-rw-r--r-- | map.c | 3 | ||||
-rw-r--r-- | obj.h | 35 | ||||
-rw-r--r-- | player.c | 10 | ||||
-rw-r--r-- | world.c | 39 | ||||
-rw-r--r-- | world.h | 24 |
19 files changed, 390 insertions, 4 deletions
@@ -27,6 +27,7 @@ int entrypoint(int argc, const char** argv, Arena* m) { world = arena_alloc(m, sizeof world); init_world(world); generate_floor(&world->map, 0); + inst_enemy(world, enemy_demon, 100 << fbits, 100 << fbits); while (a->o) { fps_begin(&f); while (f.now >= f.next && a->o) { @@ -46,6 +46,8 @@ sources = \ 1bitjam.c \ animation.c \ asset.c \ + deathzone.c \ + enemy.c \ map.c \ maths.c \ memory.c \ @@ -59,11 +61,20 @@ sources = \ image_sources = \ $(int_dir)/arms.bmp \ + $(int_dir)/npc.bmp \ $(int_dir)/guy.bmp \ $(int_dir)/map.bmp \ $(int_dir)/mask.bmp \ anim_sources = \ + $(int_dir)/demon_fly_left.anm \ + $(int_dir)/demon_fly_right.anm \ + $(int_dir)/demon_idle_left.anm \ + $(int_dir)/demon_idle_right.anm \ + $(int_dir)/demon_jump_left.anm \ + $(int_dir)/demon_jump_right.anm \ + $(int_dir)/demon_walk_left.anm \ + $(int_dir)/demon_walk_right.anm \ $(int_dir)/guy_fall_left.anm \ $(int_dir)/guy_fall_right.anm \ $(int_dir)/guy_idle_left.anm \ @@ -74,8 +85,8 @@ anim_sources = \ $(int_dir)/guy_run_right.anm \ $(int_dir)/guy_slash_left.anm \ $(int_dir)/guy_slash_right.anm \ - $(int_dir)/slash_right.anm \ $(int_dir)/slash_left.anm \ + $(int_dir)/slash_right.anm \ objects = $(sources:%.c=%.o) images = $(image_sources:$(int_dir)/%.bmp=$(data_dir)/%.img) @@ -38,5 +38,10 @@ #define player_shoot_cooldown 20 #define player_attack_frames 10 #define player_lunge_force (f1) +#define player_slash_damage 1 + +#define enemy_demon_move_force 32 +#define enemy_demon_attack_dist f1 +#define enemy_demon_jump_force (5 << fbits) #endif diff --git a/deathzone.c b/deathzone.c new file mode 100644 index 0000000..cbc0215 --- /dev/null +++ b/deathzone.c @@ -0,0 +1,23 @@ +#include "obj.h" + +void init_deathzone( + Deathzone* d, + const Rect* r, + int vx, + int vy, + int hp, + int life, + int friendly +) { + d->r = *r; + d->vx = vx; + d->vy = vy; + d->hp = hp; + d->life = life; + d->friendly = friendly; +} + +int update_deathzone(Deathzone* d) { + d->life--; + return d->life <= 0; +} @@ -0,0 +1,207 @@ +#include "animation.h" +#include "asset.h" +#include "config.h" +#include "maths.h" +#include "obj.h" +#include "physics.h" +#include "render.h" +#include "world.h" + +enum { + enemy_state_patrol, + enemy_state_approach, + enemy_state_approach2, + enemy_state_attack +}; + +int get_enemy_hp(Enemy_Type t) { + switch (t) { + case enemy_demon: + return 3; + } + return 0; +} + +void get_enemy_rect(Enemy_Type t, Rect* d) { + switch (t) { + case enemy_demon: + d->x = 2; + d->y = 2; + d->w = 12; + d->h = 14; + break; + } +} + +void init_enemy(Enemy* e, Enemy_Type t, int x, int y) { + e->t = t; + e->x = x; + e->y = y; + e->vx = 0; + e->vy = 0; + e->hp = get_enemy_hp(t); + e->frame = 0; + e->anim = asset_id_demon_idle_left_anm; + e->face = face_left; + e->state = enemy_state_patrol; +} + +void update_enemy_anim(Enemy* e) { + int done; + const Animation* anim = get_animation(e->anim); + done = update_anim(anim, &e->frame, &e->rect); + if ( + done && + e->t == enemy_demon && + e->state == enemy_state_approach + ) { + e->state = enemy_state_approach2; + } +} + +void update_enemy_phys(Enemy* e, const Map* map) { + Rect r; + get_enemy_rect(e->t, &r); + r.x <<= fbits; + r.y <<= fbits; + r.w <<= fbits; + r.h <<= fbits; + update_body( + map, + &e->x, + &e->y, + &e->vx, + &e->vy, + &e->grounded, + &e->headbutted, + &e->on_ramp, + &r + ); +} + +void update_enemy_hurt(Enemy* e, const World* w) { + Rect a; + int i; + get_enemy_rect(e->t, &a); + a.x += e->x >> fbits; + a.y += e->y >> fbits; + for (i = 0; i < w->deathzone_count; i++) { + const Deathzone* dz = &w->deathzones[i]; + if (rects_overlap(&a, &dz->r)) { + e->hp -= dz->hp; + e->vx -= dz->vx; + e->vy -= dz->vy; + } + } +} + +int tile_at(const Map* m, int x, int y) { + return + x < 0 || + y < 0 || + x >= map_w || + y >= map_h || + m->collision[x + y * map_w] == 1; +} + +void update_demon_move(Enemy* e, const World* w) { + int nanim = e->anim; + const Player* p = &w->player; + if (e->state == enemy_state_patrol) { + int dx = e->x - p->x; + int dy = e->y - p->y; + int dx2 = dx >> fbits; + int dy2 = dy >> fbits; + int dist = fxsqrt(dx * dx2 + dy * dy2) >> fbits; + if (e->grounded < 3) { + int tx, ty = + ((e->y >> fbits) - (map_tile_size >> 1)) / + map_tile_size; + int ty2 = ty + 2; + if (e->face == face_left) { + tx = ( + (e->x >> fbits) - (map_tile_size >> 1)) / + map_tile_size; + } else { + tx = ( + (e->x >> fbits) + map_tile_size + + (map_tile_size >> 1)) / + map_tile_size; + } + if ( + tile_at(&w->map, tx, ty) || + (ty2 < map_h && !tile_at(&w->map, tx, ty2)) + ) + e->face = !e->face; + if (e->face == face_left) { + e->vx -= enemy_demon_move_force; + } else { + e->vx += enemy_demon_move_force; + } + } + if (dist < enemy_demon_attack_dist) { + e->state = enemy_state_approach; + } + } else if (e->state == enemy_state_approach) { + if (p->x < e->x) + e->face = face_left; + else + e->face = face_right; + } else if (e->state == enemy_state_approach2) { + if (e->grounded < 3) { + e->vx = (p->x - e->vx) / 100; + if (e->face == face_left) + e->vx = -e->vx; + e->vy = -enemy_demon_jump_force; + e->grounded = 100; + e->state = enemy_state_attack; + } + } else if (e->state == enemy_state_attack) { + if (e->grounded < 3) { + e->state = enemy_state_patrol; + } + } + switch (e->face) { + case face_left: + nanim = + e->state == enemy_state_patrol? + asset_id_demon_walk_left_anm: + e->state == enemy_state_approach? + asset_id_demon_jump_left_anm: + asset_id_demon_idle_left_anm; + break; + case face_right: + nanim = + e->state == enemy_state_patrol? + asset_id_demon_walk_right_anm: + e->state == enemy_state_approach? + asset_id_demon_jump_right_anm: + asset_id_demon_idle_right_anm; + break; + } + if (nanim != e->anim) { + e->frame = 0; + e->anim = nanim; + } +} + +void update_enemy_move(Enemy* e, const World* w) { + switch (e->t) { + case enemy_demon: + update_demon_move(e, w); + break; + } +} + +int update_enemy(Enemy* e, World* w) { + update_enemy_anim(e); + update_enemy_hurt(e, w); + update_enemy_move(e, w); + update_enemy_phys(e, &w->map); + return e->hp <= 0; +} + +void ren_enemy(const Enemy* e, struct Renderer* r) { + const Bitmap* b = get_bitmap(asset_id_npc_img); + ren_map(r, e->x >> fbits, e->y >> fbits, &e->rect, b); +} diff --git a/intermediate/demon_fly_left.anm b/intermediate/demon_fly_left.anm new file mode 100644 index 0000000..686a35f --- /dev/null +++ b/intermediate/demon_fly_left.anm @@ -0,0 +1,2 @@ +1 +{ 64, 64, 16, 16 } diff --git a/intermediate/demon_fly_right.anm b/intermediate/demon_fly_right.anm new file mode 100644 index 0000000..8a62ff3 --- /dev/null +++ b/intermediate/demon_fly_right.anm @@ -0,0 +1,2 @@ +1 +{ 64, 80, 16, 16 } diff --git a/intermediate/demon_idle_left.anm b/intermediate/demon_idle_left.anm new file mode 100644 index 0000000..0a4ac8d --- /dev/null +++ b/intermediate/demon_idle_left.anm @@ -0,0 +1,5 @@ +15 +{ 0, 0, 16, 16 } +{ 16, 0, 16, 16 } +{ 32, 0, 16, 16 } +{ 48, 0, 16, 16 } diff --git a/intermediate/demon_idle_right.anm b/intermediate/demon_idle_right.anm new file mode 100644 index 0000000..a8edeb0 --- /dev/null +++ b/intermediate/demon_idle_right.anm @@ -0,0 +1,5 @@ +15 +{ 0, 16, 16, 16 } +{ 16, 16, 16, 16 } +{ 32, 16, 16, 16 } +{ 48, 16, 16, 16 } diff --git a/intermediate/demon_jump_left.anm b/intermediate/demon_jump_left.anm new file mode 100644 index 0000000..da710dd --- /dev/null +++ b/intermediate/demon_jump_left.anm @@ -0,0 +1,5 @@ +7 +{ 0, 64, 16, 16 } +{ 16, 64, 16, 16 } +{ 32, 64, 16, 16 } +{ 48, 64, 16, 16 } diff --git a/intermediate/demon_jump_right.anm b/intermediate/demon_jump_right.anm new file mode 100644 index 0000000..bb01bbd --- /dev/null +++ b/intermediate/demon_jump_right.anm @@ -0,0 +1,5 @@ +7 +{ 0, 80, 16, 16 } +{ 16, 80, 16, 16 } +{ 32, 80, 16, 16 } +{ 48, 80, 16, 16 } diff --git a/intermediate/demon_walk_left.anm b/intermediate/demon_walk_left.anm new file mode 100644 index 0000000..8a86a59 --- /dev/null +++ b/intermediate/demon_walk_left.anm @@ -0,0 +1,5 @@ +15 +{ 0, 32, 16, 16 } +{ 16, 32, 16, 16 } +{ 32, 32, 16, 16 } +{ 16, 32, 16, 16 } diff --git a/intermediate/demon_walk_right.anm b/intermediate/demon_walk_right.anm new file mode 100644 index 0000000..5312b7a --- /dev/null +++ b/intermediate/demon_walk_right.anm @@ -0,0 +1,5 @@ +15 +{ 0, 48, 16, 16 } +{ 16, 48, 16, 16 } +{ 32, 48, 16, 16 } +{ 16, 48, 16, 16 } diff --git a/intermediate/npc.bmp b/intermediate/npc.bmp Binary files differnew file mode 100644 index 0000000..9a961a7 --- /dev/null +++ b/intermediate/npc.bmp @@ -34,6 +34,9 @@ void generate_floor(Map* m, int seed) { set(2, 11); set(3, 11); set(4, 11); + set(6, 11); + set(7, 11); + set(8, 11); set(19, 13); set(19, 12); set(19, 11); @@ -43,4 +43,39 @@ void init_particle(Particle* p, int x, int y, int anim, int bmp); int update_particle(Particle* p); void ren_particle(const Particle* p, struct Renderer* r); +typedef enum { + enemy_demon +} Enemy_Type; + +typedef struct { + Enemy_Type t; + int x, y, vx, vy; + int hp, frame, anim; + int grounded, headbutted, on_ramp; + int state; + Face face; + Rect rect; +} Enemy; + +void init_enemy(Enemy* e, Enemy_Type t, int x, int y); +int update_enemy(Enemy* e, struct World* w); +void ren_enemy(const Enemy* e, struct Renderer* r); + +typedef struct { + Rect r; + int vx, vy; + int hp, life, friendly; +} Deathzone; + +void init_deathzone( + Deathzone* d, + const Rect* r, + int vx, + int vy, + int hp, + int life, + int friendly +); +int update_deathzone(Deathzone* d); + #endif @@ -94,18 +94,26 @@ void update_player_move(Player* p, const App* a, World* w) { play_sound(500); } if (p->cooldown <= 0 && btn_just_pressed(a, btn_shoot)) { - int sx, sy; + int sx, sy, vx; int anim; + Rect dz; if (p->face == face_left) { anim = asset_id_slash_left_anm; sx = (p->x >> fbits) - 45; sy = (p->y >> fbits); + vx = f1 * 3; } else { anim = asset_id_slash_right_anm; sx = (p->x >> fbits) + 16; sy = (p->y >> fbits); + vx = -f1 * 3; } + dz.x = sx; + dz.y = sy; + dz.w = 45; + dz.h = 17; inst_particle(w, sx, sy, anim, asset_id_arms_img); + inst_deathzone(w, &dz, vx, 0, player_slash_damage, 1, 1); p->cooldown = 10; p->slashing = get_animation(asset_id_guy_slash_left_anm)->fc; } @@ -3,6 +3,8 @@ void init_world(World* w) { w->particle_count = 0; + w->enemy_count = 0; + w->deathzone_count = 0; init_player(&w->player); } @@ -20,12 +22,47 @@ Particle* inst_particle( return p; } +Enemy* inst_enemy( + World* w, + Enemy_Type t, + int x, + int y +) { + Enemy* e; + assert(w->enemy_count < max_enemies); + e = &w->enemies[w->enemy_count++]; + init_enemy(e, t, x, y); + return e; +} + +Deathzone* inst_deathzone( + World* w, + const Rect* r, + int vx, + int vy, + int hp, + int life, + int friendly +) { + Deathzone* d; + assert(w->deathzone_count < max_deathzones); + d = &w->deathzones[w->deathzone_count++]; + init_deathzone(d, r, vx, vy, hp, life, friendly); + return d; +} + void update_world(World* w, const App* a) { int i; update_player(&w->player, w, a, &w->map); for (i = w->particle_count - 1; i >= 0; i--) if (update_particle(&w->particles[i])) w->particles[i] = w->particles[--w->particle_count]; + for (i = w->enemy_count - 1; i >= 0; i--) + if (update_enemy(&w->enemies[i], w)) + w->enemies[i] = w->enemies[--w->enemy_count]; + for (i = w->deathzone_count - 1; i >= 0; i--) + if (update_deathzone(&w->deathzones[i])) + w->deathzones[i] = w->deathzones[--w->deathzone_count]; } void ren_world(const World* w, struct Renderer* r) { @@ -34,4 +71,6 @@ void ren_world(const World* w, struct Renderer* r) { render_map(&w->map, r); for (i = 0; i < w->particle_count; i++) ren_particle(&w->particles[i], r); + for (i = 0; i < w->enemy_count; i++) + ren_enemy(&w->enemies[i], r); } @@ -5,12 +5,17 @@ #include "obj.h" #define max_particles 32 +#define max_enemies 16 +#define max_deathzones 16 struct Renderer; typedef struct World { Particle particles[max_particles]; - int particle_count; + Enemy enemies[max_enemies]; + Deathzone deathzones[max_deathzones]; + int particle_count, enemy_count; + int deathzone_count; Player player; Map map; } World; @@ -23,7 +28,22 @@ Particle* inst_particle( int anim, int bmp ); -void update_world(World* w, const App* a); +Enemy* inst_enemy( + World* w, + Enemy_Type t, + int x, + int y +); +Deathzone* inst_deathzone( + World* w, + const Rect* r, + int vx, + int vy, + int hp, + int life, + int friendly +); +void update_world(World* w, const struct App* a); void ren_world(const World* w, struct Renderer* r); #endif |