commit d4a98d928be48c21ce048e7af94d33d7b6f126ec
parent 195ad8e997bf6ecf910a3ee185ecbbdb89f69cd4
Author: brookjeynes <me@brookjeynes.dev>
Date: Thu, 13 Aug 2026 13:07:38 +1000
fix: don't despawn bullets after enemy dies
Signed-off-by: brookjeynes <me@brookjeynes.dev>
Diffstat:
6 files changed, 54 insertions(+), 6 deletions(-)
diff --git a/src/bullet.zig b/src/bullet.zig
@@ -11,6 +11,7 @@ pub const Bullet = struct {
position: raylib.Vector2,
velocity: raylib.Vector2,
color: raylib.Color,
+ damage: f32,
};
pub const Pool = struct {
@@ -27,12 +28,14 @@ pub const Pool = struct {
position: raylib.Vector2,
velocity: raylib.Vector2,
colour: raylib.Color,
+ damage: f32,
) void {
if (self.count == self.bullets.len) return;
self.bullets[self.count] = .{
.position = position,
.velocity = velocity,
.color = colour,
+ .damage = damage,
};
self.count += 1;
}
@@ -68,4 +71,11 @@ pub const Pool = struct {
i += 1;
}
}
+
+ pub fn transferFrom(self: *Pool, src: *Pool) void {
+ const n = @min(src.count, self.bullets.len - self.count);
+ @memcpy(self.bullets[self.count .. self.count + n], src.bullets[0..n]);
+ self.count += n;
+ src.count = 0;
+ }
};
diff --git a/src/enemy_types/blorb.zig b/src/enemy_types/blorb.zig
@@ -41,7 +41,7 @@ pub fn shoot(self: *Blorb) void {
2 => .{ .x = 0, .y = self.bullet_speed },
else => .{ .x = -self.bullet_speed, .y = 0 },
};
- self.bullet_pool.spawn(spawn_position, bullet_velocity, raylib.PURPLE);
+ self.bullet_pool.spawn(spawn_position, bullet_velocity, raylib.PURPLE, bullet_damage);
}
self.shoot_offset +%= 1;
diff --git a/src/enemy_types/grunt.zig b/src/enemy_types/grunt.zig
@@ -30,6 +30,7 @@ pub fn shoot(self: *Grunt) void {
.y = self.direction.y * self.bullet_speed,
},
raylib.RED,
+ bullet_damage,
);
}
diff --git a/src/main.zig b/src/main.zig
@@ -178,6 +178,8 @@ pub fn main() !void {
game_state.enemies[idx].render();
}
+ game_state.orphaned_bullet_pool.render(.{ .x = constants.screen_width, .y = constants.screen_height });
+
// Health overlay
const health_percent: f32 = @max(
0,
diff --git a/src/player.zig b/src/player.zig
@@ -108,6 +108,6 @@ pub fn shoot(self: *Player) void {
.x = dir.x * self.bullet_speed,
.y = dir.y * self.bullet_speed,
};
- self.bullet_pool.spawn(center, bullet_vel, raylib.BLUE);
+ self.bullet_pool.spawn(center, bullet_vel, raylib.BLUE, 1);
}
}
diff --git a/src/state.zig b/src/state.zig
@@ -3,8 +3,8 @@ const raymath = @import("raymath");
const Bullet = @import("./bullet.zig");
const constants = @import("./constants.zig");
-const Grunt = @import("./enemy_types/grunt.zig");
const Blorb = @import("./enemy_types/blorb.zig");
+const Grunt = @import("./enemy_types/grunt.zig");
const Entity = @import("./entity.zig").Entity;
const EntityType = @import("./entity.zig").EntityType;
const Player = @import("./player.zig");
@@ -31,11 +31,20 @@ pub const GameState = struct {
grunt_spawn_time: Timer = .{ .duration = constants.grunt_spawn_time },
blorb_spawn_time: Timer = .{ .duration = constants.blorb_spawn_time },
+ orphaned_bullet_pool: Bullet.Pool,
+
pub fn init() GameState {
return .{
.screen = .title,
.time = 0,
+ .orphaned_bullet_pool = .{
+ .bullets = undefined,
+ .fire_timer = .{
+ .duration = 0,
+ },
+ },
+
.player = .{
.bullet_pool = .{
.bullets = undefined,
@@ -78,6 +87,8 @@ pub const GameState = struct {
self.enemy_count = 0;
self.enemies_killed = 0;
+ self.orphaned_bullet_pool.count = 0;
+
self.grunt_spawn_time = .{ .duration = constants.grunt_spawn_time };
self.blorb_spawn_time = .{ .duration = constants.blorb_spawn_time };
@@ -160,7 +171,7 @@ pub const GameState = struct {
if (is_collision) {
grunt.bullet_pool.despawn(enemy_bullet_idx);
- self.player.handleDamage(Grunt.bullet_damage);
+ self.player.handleDamage(bullet.damage);
}
}
@@ -185,6 +196,7 @@ pub const GameState = struct {
if (is_collision) {
self.player.bullet_pool.despawn(player_bullet_idx);
+ self.orphaned_bullet_pool.transferFrom(&grunt.bullet_pool);
self.despawn_enemy(enemy_idx);
self.enemies_killed += 1;
continue :lbl;
@@ -210,7 +222,7 @@ pub const GameState = struct {
if (is_collision) {
blorb.bullet_pool.despawn(enemy_bullet_idx);
- self.player.handleDamage(Blorb.bullet_damage);
+ self.player.handleDamage(bullet.damage);
}
}
@@ -234,6 +246,7 @@ pub const GameState = struct {
);
if (is_collision) {
+ self.orphaned_bullet_pool.transferFrom(&blorb.bullet_pool);
self.player.bullet_pool.despawn(player_bullet_idx);
self.despawn_enemy(enemy_idx);
self.enemies_killed += 1;
@@ -245,6 +258,28 @@ pub const GameState = struct {
enemy_idx += 1;
}
+
+ var enemy_bullet_idx = self.orphaned_bullet_pool.count;
+ while (enemy_bullet_idx > 0) {
+ enemy_bullet_idx -= 1;
+
+ const bullet = self.orphaned_bullet_pool.bullets[enemy_bullet_idx];
+ const is_collision = raylib.CheckCollisionCircleRec(
+ .{ .x = bullet.position.x, .y = bullet.position.y },
+ Bullet.radius,
+ .{
+ .x = self.player.position.x,
+ .y = self.player.position.y,
+ .width = self.player.size.x,
+ .height = self.player.size.y,
+ },
+ );
+
+ if (is_collision) {
+ self.orphaned_bullet_pool.despawn(enemy_bullet_idx);
+ self.player.handleDamage(bullet.damage);
+ }
+ }
}
};
@@ -311,7 +346,7 @@ fn createEnemy(
blorb.movement_speed = @min(160.0, 40.0 * difficulty);
blorb.bullet_speed = @min(300.0, 100.0 * difficulty);
- blorb.bullet_pool.fire_timer.duration = @max(0.3, 2.0 / difficulty);
+ blorb.bullet_pool.fire_timer.duration = @max(0.3, 4.0 / difficulty);
blorb.setRandomDirection();
break :lbl .{ .blorb = blorb };