aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--animation.c10
-rw-r--r--animation.h3
-rw-r--r--animation_system.c5
-rw-r--r--bullet.c27
-rw-r--r--collision_system.c105
-rw-r--r--components.h25
-rw-r--r--enemy.c29
-rw-r--r--fx.c40
-rw-r--r--fx.h14
-rw-r--r--intermediate/bullet.bmpbin2714 -> 6026 bytes
-rw-r--r--main.c1
-rw-r--r--player.c11
-rw-r--r--rect.c25
-rw-r--r--rect.h13
-rw-r--r--systems.h4
-rw-r--r--world.h1
17 files changed, 294 insertions, 21 deletions
diff --git a/Makefile b/Makefile
index 581c027..4fe54fd 100644
--- a/Makefile
+++ b/Makefile
@@ -89,7 +89,9 @@ sources = \
animation_system.c \
asset.c \
bullet.c \
+ collision_system.c \
enemy.c \
+ fx.c \
main.c \
malware.c \
platform.c \
diff --git a/animation.c b/animation.c
index 6dbb08f..6cf2584 100644
--- a/animation.c
+++ b/animation.c
@@ -43,6 +43,16 @@ static const Animation animations[] = {
1,
1
},
+ /* animation_enemy_bullet_explode */
+ {
+ {
+ { 24, 0, 7, 7 },
+ { 31, 0, 7, 7 },
+ { 38, 0, 7, 7 }
+ },
+ 3,
+ 5
+ }
};
const Animation* get_animation(Animation_ID id) {
diff --git a/animation.h b/animation.h
index e9e1399..65956a6 100644
--- a/animation.h
+++ b/animation.h
@@ -8,7 +8,8 @@ typedef enum {
animation_player_walk_left = 0,
animation_player_walk_right,
animation_player_idle_left,
- animation_player_idle_right
+ animation_player_idle_right,
+ animation_enemy_bullet_explode
} Animation_ID;
typedef struct {
diff --git a/animation_system.c b/animation_system.c
index 22317ac..8411e64 100644
--- a/animation_system.c
+++ b/animation_system.c
@@ -23,6 +23,11 @@ void animation_system(World* world) {
}
if (animated->frame >= animation->frame_count) {
+ if (bits & ctype_destroy_on_anim_done) {
+ destroy_entity(world, i);
+ continue;
+ }
+
animated->frame = 0;
animated->timer = 0;
}
diff --git a/bullet.c b/bullet.c
index a2f1c66..b3182ea 100644
--- a/bullet.c
+++ b/bullet.c
@@ -3,6 +3,7 @@
#include "error.h"
#include "platform.h"
#include "sprite.h"
+#include "standard.h"
#include "world.h"
Entity new_player_bullet(
@@ -17,6 +18,7 @@ Entity new_player_bullet(
CBullet* bullet;
CPosition* pos;
CSprite* sprite;
+ CCollider* col;
Sprite_ID sprid;
e = new_entity(world);
@@ -27,11 +29,13 @@ Entity new_player_bullet(
ctype_sprite |
ctype_position |
ctype_bullet |
- ctype_player_bullet
+ ctype_player_bullet |
+ ctype_collider
);
pos = &world->positions[e];
sprite = &world->sprites[e];
bullet = &world->bullets[e];
+ col = &world->colliders[e];
pos->x = x;
pos->y = y;
@@ -39,14 +43,25 @@ Entity new_player_bullet(
bullet->vy = vy;
bullet->life = life;
+ col->x = 0;
+ col->y = 0;
+
if (vx < 0) {
sprid = sprite_player_bullet_left;
+ col->w = 9 << fbits;
+ col->h = 14 << fbits;
} else if (vx > 0) {
sprid = sprite_player_bullet_right;
+ col->w = 9 << fbits;
+ col->h = 14 << fbits;
} else if (vy < 0) {
sprid = sprite_player_bullet_up;
+ col->w = 9 << fbits;
+ col->h = 14 << fbits;
} else if (vy > 0) {
sprid = sprite_player_bullet_down;
+ col->w = 9 << fbits;
+ col->h = 14 << fbits;
}
#ifdef DEBUG
else {
@@ -71,6 +86,7 @@ int new_enemy_bullet(
CBullet* bullet;
CPosition* pos;
CSprite* sprite;
+ CCollider* col;
e = new_entity(world);
@@ -80,11 +96,13 @@ int new_enemy_bullet(
ctype_sprite |
ctype_position |
ctype_bullet |
- ctype_enemy_bullet
+ ctype_enemy_bullet |
+ ctype_collider
);
pos = &world->positions[e];
sprite = &world->sprites[e];
bullet = &world->bullets[e];
+ col = &world->colliders[e];
pos->x = x;
pos->y = y;
@@ -92,6 +110,11 @@ int new_enemy_bullet(
bullet->vy = vy;
bullet->life = 500;
+ col->x = 1 << fbits;
+ col->y = 1 << fbits;
+ col->w = 3 << fbits;
+ col->h = 3 << fbits;
+
init_csprite(sprite, sprite_enemy_bullet);
return e;
diff --git a/collision_system.c b/collision_system.c
new file mode 100644
index 0000000..abd5dc9
--- /dev/null
+++ b/collision_system.c
@@ -0,0 +1,105 @@
+#ifndef systems_h
+#define systems_h
+
+#include "config.h"
+#include "fx.h"
+#include "rect.h"
+#include "world.h"
+
+static void handle_bullet_vs_player(
+ World* world,
+ Entity bullet,
+ Entity player
+) {
+ const CPosition* pos;
+
+ pos = &world->positions[bullet];
+
+ destroy_entity(world, bullet);
+ new_enemy_bullet_explosion(world, pos->x, pos->y);
+}
+
+static void handle_bullet_vs_enemy(
+ World* world,
+ Entity bullet,
+ Entity enemy
+) {
+ CEnemy* e;
+
+ e = &world->enemies[enemy];
+ e->hp--;
+ destroy_entity(world, bullet);
+}
+
+static void handle(World* world, Entity a, Entity b) {
+ unsigned ab, bb;
+
+ ab = world->bitmask[a];
+ bb = world->bitmask[b];
+
+ if ((ab & ctype_enemy_bullet) && (bb & ctype_player)) {
+ handle_bullet_vs_player(world, a, b);
+ return;
+ }
+
+ if ((ab & ctype_player) && (bb & ctype_enemy_bullet)) {
+ handle_bullet_vs_player(world, b, a);
+ return;
+ }
+
+ if ((ab & ctype_player_bullet) && (bb & ctype_enemy)) {
+ handle_bullet_vs_enemy(world, a, b);
+ return;
+ }
+
+ if ((ab & ctype_enemy) && (bb & ctype_player_bullet)) {
+ handle_bullet_vs_enemy(world, b, a);
+ return;
+ }
+}
+
+void collision_system(World* world) {
+ int i, j, p0x, p0y;
+ unsigned bits;
+ const CPosition* pos0, * pos1;
+ const CCollider* col0, * col1;
+
+ for (i = 0; i < world->entity_count; i++) {
+ bits = world->bitmask[i];
+ if (
+ !(bits & ctype_collider) ||
+ !(bits & ctype_position)
+ ) { continue; }
+
+ pos0 = &world->positions[i];
+ col0 = &world->colliders[i];
+ p0x = pos0->x + col0->x;
+ p0y = pos0->y + col0->y;
+
+ for (j = i + 1; j < world->entity_count; j++) {
+ bits = world->bitmask[j];
+ if (
+ !(bits & ctype_collider) ||
+ !(bits & ctype_position)
+ ) { continue; }
+
+ pos1 = &world->positions[j];
+ col1 = &world->colliders[j];
+
+ if (rects_overlap2(
+ p0x,
+ p0y,
+ col0->w,
+ col0->h,
+ pos1->x + col1->x,
+ pos1->y + col1->y,
+ col1->w,
+ col1->h
+ )) {
+ handle(world, i, j);
+ }
+ }
+ }
+}
+
+#endif
diff --git a/components.h b/components.h
index d288ac5..f23b35e 100644
--- a/components.h
+++ b/components.h
@@ -39,16 +39,23 @@ typedef struct {
int vx, vy;
} CDebris;
+typedef struct {
+ int x, y, w, h;
+} CCollider;
+
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 = 1 << 6,
- ctype_skull = 1 << 7,
- ctype_debris = 1 << 8
+ 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 = 1 << 6,
+ ctype_skull = 1 << 7,
+ ctype_debris = 1 << 8,
+ ctype_collider = 1 << 9,
+ ctype_player = 1 << 10,
+ ctype_destroy_on_anim_done = 1 << 11
} CType;
#endif
diff --git a/enemy.c b/enemy.c
index 9a67cba..6729862 100644
--- a/enemy.c
+++ b/enemy.c
@@ -9,6 +9,7 @@ Entity new_skull(World* world, int x, int y) {
CSprite* sprite;
CPosition* pos;
CEnemy* enemy;
+ CCollider* col;
Entity e;
e = new_entity(world);
@@ -18,15 +19,22 @@ Entity new_skull(World* world, int x, int y) {
ctype_position |
ctype_sprite |
ctype_enemy |
- ctype_skull
+ ctype_skull |
+ ctype_collider
);
pos = &world->positions[e];
sprite = &world->sprites[e];
enemy = &world->enemies[e];
+ col = &world->colliders[e];
pos->x = x;
pos->y = y;
+ col->x = 2 << fbits;
+ col->y = 2 << fbits;
+ col->w = 14 << fbits;
+ col->h = 14 << fbits;
+
init_csprite(sprite, sprite_skull_right);
enemy->hp = skull_hp;
@@ -44,13 +52,22 @@ void enemy_system(World* world) {
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_enemy) {
+ enemy = &world->enemies[i];
+ if (enemy->hp <= 0) {
+ destroy_entity(world, i);
+ }
+ }
+ }
+
+ for (i = 0; i < world->entity_count; i++) {
+ bits = world->bitmask[i];
if (
(bits & ctype_position) &&
(bits & ctype_enemy) &&
@@ -59,8 +76,8 @@ void enemy_system(World* world) {
pos = &world->positions[i];
enemy = &world->enemies[i];
- dpx = (ppos->x - pos->x) >> 4;
- dpy = (ppos->y - pos->y) >> 4;
+ dpx = ((ppos->x - pos->x) >> 4) + 256;
+ dpy = ((ppos->y - pos->y) >> 4) + 256;
tpx = dpx;
tpy = dpy;
d = ((dpx * dpx) >> fbits) + ((dpy * dpy) >> fbits);
@@ -89,8 +106,8 @@ void enemy_system(World* world) {
new_enemy_bullet(
world,
- pos->x,
- pos->y,
+ pos->x + 2560,
+ pos->y + 2560,
tpx * enemy_bullet_speed,
tpy * enemy_bullet_speed
);
diff --git a/fx.c b/fx.c
new file mode 100644
index 0000000..f2a5f54
--- /dev/null
+++ b/fx.c
@@ -0,0 +1,40 @@
+#include "components.h"
+#include "fx.h"
+#include "world.h"
+
+int new_enemy_bullet_explosion(
+ World* world,
+ int x,
+ int y
+) {
+ Entity e;
+ CPosition* pos;
+ CSprite* sprite;
+ CAnimated* animated;
+
+ e = new_entity(world);
+ add_components(
+ world,
+ e,
+ ctype_sprite |
+ ctype_position |
+ ctype_animated |
+ ctype_destroy_on_anim_done
+ );
+
+ pos = &world->positions[e];
+ sprite = &world->sprites[e];
+ animated = &world->animateds[e];
+
+ pos->x = x;
+ pos->y = y;
+
+ sprite->id = asset_id_bullet;
+ sprite->rect = make_rect(0, 0, 16, 16);
+
+ animated->id = animation_enemy_bullet_explode;
+ animated->frame = 0;
+ animated->timer = 0;
+
+ return e;
+}
diff --git a/fx.h b/fx.h
new file mode 100644
index 0000000..acbde30
--- /dev/null
+++ b/fx.h
@@ -0,0 +1,14 @@
+#ifndef fx_h
+#define fx_h
+
+#include "animation.h"
+
+struct World;
+
+int new_enemy_bullet_explosion(
+ struct World* world,
+ int x,
+ int y
+);
+
+#endif
diff --git a/intermediate/bullet.bmp b/intermediate/bullet.bmp
index e6735ce..e92d3fb 100644
--- a/intermediate/bullet.bmp
+++ b/intermediate/bullet.bmp
Binary files differ
diff --git a/main.c b/main.c
index ef757b2..9d2aff8 100644
--- a/main.c
+++ b/main.c
@@ -27,6 +27,7 @@ void on_update() {
update_player(&world.player, &world);
enemy_system(&world);
bullet_system(&world);
+ collision_system(&world);
animation_system(&world);
sprite_system(&world);
}
diff --git a/player.c b/player.c
index b723849..b2dbf29 100644
--- a/player.c
+++ b/player.c
@@ -11,6 +11,7 @@ void init_player(Player* player, World* world) {
CSprite* sprite;
CPosition* pos;
CAnimated* animated;
+ CCollider* col;
Entity e;
e = new_entity(world);
@@ -20,11 +21,14 @@ void init_player(Player* player, World* world) {
e,
ctype_sprite |
ctype_position |
- ctype_animated
+ ctype_animated |
+ ctype_collider |
+ ctype_player
);
pos = &world->positions[e];
sprite = &world->sprites[e];
animated = &world->animateds[e];
+ col = &world->colliders[e];
pos->x = 32 << fbits;
pos->y = 70 << fbits;
@@ -36,6 +40,11 @@ void init_player(Player* player, World* world) {
animated->frame = 0;
animated->timer = 0;
+ col->x = 3 << fbits;
+ col->y = 1 << fbits;
+ col->w = 10 << fbits;
+ col->h = 15 << fbits;
+
player->face = 0;
player->shoot_cooldown = 15;
player->shoot_countdown = 0;
diff --git a/rect.c b/rect.c
index ec755e2..aafa645 100644
--- a/rect.c
+++ b/rect.c
@@ -8,3 +8,28 @@ Rectangle make_rect(int x, int y, int w, int h) {
r.h = h;
return r;
}
+
+int rects_overlap(const Rectangle* a, const Rectangle* b) {
+ return
+ a->x + a->w > b->x &&
+ a->y + a->h > b->y &&
+ a->x < b->x + b->w &&
+ a->y < b->y + b->h;
+}
+
+int rects_overlap2(
+ int x0,
+ int y0,
+ int w0,
+ int h0,
+ int x1,
+ int y1,
+ int w1,
+ int h1
+) {
+ return
+ x0 + w0 > x1 &&
+ y0 + h0 > y1 &&
+ x0 < x1 + w1 &&
+ y0 < y1 + h1;
+}
diff --git a/rect.h b/rect.h
index 6f45705..bf494b2 100644
--- a/rect.h
+++ b/rect.h
@@ -7,4 +7,17 @@ typedef struct {
Rectangle make_rect(int x, int y, int w, int h);
+int rects_overlap(const Rectangle* a, const Rectangle* b);
+
+int rects_overlap2(
+ int x0,
+ int y0,
+ int w0,
+ int h0,
+ int x1,
+ int y1,
+ int w1,
+ int h1
+);
+
#endif
diff --git a/systems.h b/systems.h
index 0cc55ec..6bf4edc 100644
--- a/systems.h
+++ b/systems.h
@@ -5,8 +5,8 @@
void animation_system(World* world);
void bullet_system(World* world);
-void sprite_system(const World* world);
+void collision_system(World* world);
void enemy_system(World* world);
-
+void sprite_system(const World* world);
#endif
diff --git a/world.h b/world.h
index 9709337..923dc90 100644
--- a/world.h
+++ b/world.h
@@ -21,6 +21,7 @@ struct World {
CAnimated animateds [max_entities];
CBullet bullets [max_entities];
CEnemy enemies [max_entities];
+ CCollider colliders [max_entities];
Player player;
};