From 280552fa4750b5dac9243782f9c0a7e0b7eea6f8 Mon Sep 17 00:00:00 2001 From: quou Date: Fri, 5 May 2023 09:25:39 +1000 Subject: Add a basic enemy. --- Makefile | 1 + asset.c | 3 +- asset.h | 3 +- bullet.c | 37 ++++++++++++++++++ bullet.h | 8 ++++ components.h | 15 ++++++- enemy.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ enemy.h | 8 ++++ game_config.h | 6 +++ intermediate/enemy.bmp | Bin 0 -> 8330 bytes main.c | 4 ++ player.c | 4 +- sprite.c | 40 +++++++++++++++++++ sprite.h | 10 ++++- standard.c | 14 +++++++ standard.h | 4 ++ systems.h | 2 + world.h | 3 +- 18 files changed, 258 insertions(+), 7 deletions(-) create mode 100644 enemy.c create mode 100644 enemy.h create mode 100644 intermediate/enemy.bmp diff --git a/Makefile b/Makefile index 02a40ff..581c027 100644 --- a/Makefile +++ b/Makefile @@ -89,6 +89,7 @@ sources = \ animation_system.c \ asset.c \ bullet.c \ + enemy.c \ main.c \ malware.c \ platform.c \ diff --git a/asset.c b/asset.c index b6e408b..5ae5419 100644 --- a/asset.c +++ b/asset.c @@ -8,7 +8,8 @@ static const char* const asset_vpaths[] = { /* asset_id_usr */ "data/usr.img", /* asset_id_char */ "data/char.img", - /* asset_id_bullet */ "data/bullet.img" + /* asset_id_bullet */ "data/bullet.img", + /* asset_id_enemy */ "data/enemy.img" }; static struct { diff --git a/asset.h b/asset.h index e60ff4b..8c6e201 100644 --- a/asset.h +++ b/asset.h @@ -3,12 +3,13 @@ #include "render.h" -#define bitmap_asset_count 3 +#define bitmap_asset_count 4 typedef enum { asset_id_usr = 0, asset_id_char, asset_id_bullet, + asset_id_enemy, asset_count } Asset_ID; diff --git a/bullet.c b/bullet.c index 9acefc2..a2f1c66 100644 --- a/bullet.c +++ b/bullet.c @@ -60,6 +60,43 @@ Entity new_player_bullet( return e; } +int new_enemy_bullet( + struct World* world, + int x, + int y, + int vx, + int vy +) { + Entity e; + CBullet* bullet; + CPosition* pos; + CSprite* sprite; + + e = new_entity(world); + + add_components( + world, + e, + ctype_sprite | + ctype_position | + ctype_bullet | + ctype_enemy_bullet + ); + pos = &world->positions[e]; + sprite = &world->sprites[e]; + bullet = &world->bullets[e]; + pos->x = x; + pos->y = y; + + bullet->vx = vx; + bullet->vy = vy; + bullet->life = 500; + + init_csprite(sprite, sprite_enemy_bullet); + + return e; +} + void bullet_system(World* world) { int i; unsigned bits; diff --git a/bullet.h b/bullet.h index cd7a436..2c84840 100644 --- a/bullet.h +++ b/bullet.h @@ -12,4 +12,12 @@ int new_player_bullet( int life ); +int new_enemy_bullet( + struct World* world, + int x, + int y, + int vx, + int vy +); + #endif diff --git a/components.h b/components.h index 66304df..d288ac5 100644 --- a/components.h +++ b/components.h @@ -29,13 +29,26 @@ typedef struct { int vx, vy; } CBullet; +typedef struct { + int hp; + int backpedal; + int shoot_timer; +} CEnemy; + +typedef struct { + int vx, vy; +} CDebris; + typedef enum { ctype_sprite = 1 << 0, ctype_position = 1 << 1, ctype_animated = 1 << 2, ctype_bullet = 1 << 3, ctype_player_bullet = 1 << 4, - ctype_enemy_bullet = 1 << 5 + ctype_enemy_bullet = 1 << 5, + ctype_enemy = 1 << 6, + ctype_skull = 1 << 7, + ctype_debris = 1 << 8 } CType; #endif diff --git a/enemy.c b/enemy.c new file mode 100644 index 0000000..9a67cba --- /dev/null +++ b/enemy.c @@ -0,0 +1,103 @@ +#include "bullet.h" +#include "components.h" +#include "game_config.h" +#include "sprite.h" +#include "standard.h" +#include "world.h" + +Entity new_skull(World* world, int x, int y) { + CSprite* sprite; + CPosition* pos; + CEnemy* enemy; + Entity e; + + e = new_entity(world); + add_components( + world, + e, + ctype_position | + ctype_sprite | + ctype_enemy | + ctype_skull + ); + pos = &world->positions[e]; + sprite = &world->sprites[e]; + enemy = &world->enemies[e]; + + pos->x = x; + pos->y = y; + + init_csprite(sprite, sprite_skull_right); + + enemy->hp = skull_hp; + enemy->shoot_timer = 0; + + return e; +} + +void enemy_system(World* world) { + /* Skulls. */ + int i; + unsigned bits; + CPosition* pos; + CEnemy* enemy; + Player* player; + CPosition* ppos; + int dpx, dpy, tpx, tpy, d; + char buf[32]; + + player = &world->player; + ppos = &world->positions[player->entity]; + + for (i = 0; i < world->entity_count; i++) { + bits = world->bitmask[i]; + if ( + (bits & ctype_position) && + (bits & ctype_enemy) && + (bits & ctype_skull) + ) { + pos = &world->positions[i]; + enemy = &world->enemies[i]; + + dpx = (ppos->x - pos->x) >> 4; + dpy = (ppos->y - pos->y) >> 4; + tpx = dpx; + tpy = dpy; + d = ((dpx * dpx) >> fbits) + ((dpy * dpy) >> fbits); + + if (d < 10 << fbits) { + dpx = -dpx; + dpy = -dpy; + enemy->backpedal = 1; + } else if (enemy->backpedal) { + if (d > 30 << fbits) { + enemy->backpedal = 0; + } else { + dpx = -dpx; + dpy = -dpy; + } + } + + dpx = (dpx < 0 ? -1 : 1); + dpy = (dpy < 0 ? -1 : 1); + + pos->x += dpx * skull_speed; + pos->y += dpy * skull_speed; + + if (enemy->shoot_timer > skull_shoot_cooldown) { + vec_nrmise(&tpx, &tpy); + + new_enemy_bullet( + world, + pos->x, + pos->y, + tpx * enemy_bullet_speed, + tpy * enemy_bullet_speed + ); + enemy->shoot_timer = 0; + } + + enemy->shoot_timer++; + } + } +} diff --git a/enemy.h b/enemy.h new file mode 100644 index 0000000..f968864 --- /dev/null +++ b/enemy.h @@ -0,0 +1,8 @@ +#ifndef enemy_h +#define enemy_h + +struct World; + +int new_skull(struct World* world, int x, int y); + +#endif diff --git a/game_config.h b/game_config.h index 7bb6cdd..0c97a8d 100644 --- a/game_config.h +++ b/game_config.h @@ -4,4 +4,10 @@ #define player_move_speed (3 << fbits) #define player_bullet_speed (10 << fbits) +#define skull_hp 3 +#define skull_speed (1 << fbits) + +#define skull_shoot_cooldown 15 +#define enemy_bullet_speed 10 + #endif diff --git a/intermediate/enemy.bmp b/intermediate/enemy.bmp new file mode 100644 index 0000000..da1e068 Binary files /dev/null and b/intermediate/enemy.bmp differ diff --git a/main.c b/main.c index e1fd29b..ef757b2 100644 --- a/main.c +++ b/main.c @@ -4,6 +4,7 @@ #include "standard.h" #include "systems.h" #include "world.h" +#include "enemy.h" World world; @@ -17,11 +18,14 @@ void on_init(int argc, char** argv) { init_world(&world); init_player(&world.player, &world); + + new_skull(&world, 0, 0); } void on_update() { renderer_begin_frame(); update_player(&world.player, &world); + enemy_system(&world); bullet_system(&world); animation_system(&world); sprite_system(&world); diff --git a/player.c b/player.c index cadb0dc..b723849 100644 --- a/player.c +++ b/player.c @@ -26,8 +26,8 @@ void init_player(Player* player, World* world) { sprite = &world->sprites[e]; animated = &world->animateds[e]; - pos->x = 32; - pos->y = 70; + pos->x = 32 << fbits; + pos->y = 70 << fbits; sprite->id = asset_id_char; sprite->rect = make_rect(0, 16, 16, 16); diff --git a/sprite.c b/sprite.c index 8289fd2..c14f717 100644 --- a/sprite.c +++ b/sprite.c @@ -20,6 +20,46 @@ static const Sprite sprites[] = { { asset_id_bullet, { 14, 14, 14, 9 } + }, + /* sprite_skull_left */ + { + asset_id_enemy, + { 16, 0, 16, 16 } + }, + /* sprite_skull_right */ + { + asset_id_enemy, + { 0, 0, 16, 16 } + }, + /* sprite_skull_debris_1 */ + { + asset_id_enemy, + { 32, 0, 5, 8 } + }, + /* sprite_skull_debris_2 */ + { + asset_id_enemy, + { 38, 0, 6, 6 } + }, + /* sprite_skull_debris_3 */ + { + asset_id_enemy, + { 32, 8, 5, 8 } + }, + /* sprite_skull_debris_4 */ + { + asset_id_enemy, + { 38, 11, 5, 5 } + }, + /* sprite_skull_debris_5 */ + { + asset_id_enemy, + { 44, 10, 3, 6 } + }, + /* sprite_enemy_bullet */ + { + asset_id_bullet, + { 18, 0, 5, 5 } } }; diff --git a/sprite.h b/sprite.h index a520b99..cf9d6e8 100644 --- a/sprite.h +++ b/sprite.h @@ -9,7 +9,15 @@ typedef enum { sprite_player_bullet_left = 0, sprite_player_bullet_right, sprite_player_bullet_up, - sprite_player_bullet_down + sprite_player_bullet_down, + sprite_skull_left, + sprite_skull_right, + sprite_skull_debris_1, + sprite_skull_debris_2, + sprite_skull_debris_3, + sprite_skull_debris_4, + sprite_skull_debris_5, + sprite_enemy_bullet } Sprite_ID; typedef struct { diff --git a/standard.c b/standard.c index 5e464f6..9a87342 100644 --- a/standard.c +++ b/standard.c @@ -135,6 +135,20 @@ int flerp(int a, int b, int t) { return a + ((t * (b - a)) >> fbits); } +void vec_minise(int* x, int* y) { + if ( + absolute(*x) <= fscale_lower_limit || + absolute(*y) <= fscale_lower_limit) { + *x *= fscale_factor; + *y *= fscale_factor; + } else if ( + absolute(*x) > fscale_upper_limit || + absolute(*y) > fscale_upper_limit) { + *x /= fscale_factor; + *y /= fscale_factor; + } +} + void vec_nrmise(int* x, int* y) { int l; diff --git a/standard.h b/standard.h index 6f56ebc..88918af 100644 --- a/standard.h +++ b/standard.h @@ -4,6 +4,9 @@ int string_equal(const char* a, const char* b); #define fbits 9 +#define fscale_lower_limit 16 +#define fscale_upper_limit 900 +#define fscale_factor 16 #define mini(a_, b_) ((a_) < (b_) ? (a_) : (b_)) #define maxi(a_, b_) ((a_) > (b_) ? (a_) : (b_)) @@ -15,6 +18,7 @@ int ftan(int t); int flerp(int a, int b, int t); int fsqrt(int v); +void vec_minise(int* x, int* y); void vec_nrmise(int* x, int* y); void seed_rng(unsigned seed); diff --git a/systems.h b/systems.h index 0e405dd..0cc55ec 100644 --- a/systems.h +++ b/systems.h @@ -6,5 +6,7 @@ void animation_system(World* world); void bullet_system(World* world); void sprite_system(const World* world); +void enemy_system(World* world); + #endif diff --git a/world.h b/world.h index d9995ab..9709337 100644 --- a/world.h +++ b/world.h @@ -13,13 +13,14 @@ struct World { int entity_count; int recycle_bin_count; - unsigned char bitmask[max_entities]; + unsigned short bitmask[max_entities]; Entity recycle_bin[max_entities]; CSprite sprites [max_entities]; CPosition positions [max_entities]; CAnimated animateds [max_entities]; CBullet bullets [max_entities]; + CEnemy enemies [max_entities]; Player player; }; -- cgit v1.2.3-54-g00ecf