commit 5c726b8e20efec56b4900f87c8489a753ef0966d
parent d4a98d928be48c21ce048e7af94d33d7b6f126ec
Author: brookjeynes <me@brookjeynes.dev>
Date: Thu, 13 Aug 2026 13:48:35 +1000
feat: health values for enemies
Signed-off-by: brookjeynes <me@brookjeynes.dev>
Diffstat:
6 files changed, 79 insertions(+), 27 deletions(-)
diff --git a/src/constants.zig b/src/constants.zig
@@ -1,11 +1,26 @@
-pub const max_bullets: u8 = 255;
-pub const max_enemies: u8 = 255;
+// general
+pub const fps: u8 = 60;
+
+// screen
pub const screen_width: u16 = 800;
pub const screen_height: u16 = 1000;
pub const screen_title: [*]const u8 = "1.44mb game jam";
-pub const fps: u8 = 60;
-pub const blorb_spawn_time: f32 = 5.0;
-pub const grunt_spawn_time: f32 = 0.7;
+// bullets
+pub const max_bullets: u8 = 255;
+pub const max_enemies: u8 = 255;
+
+// enemies
+// -- blorb
+pub const blorb_health: u8 = 150;
+pub const blorb_bullet_damage: f32 = 80;
+pub const blorb_spawn_interval: f32 = 5.0;
+pub const blorb_spawn_after: f32 = 60;
+
+// -- grunt
+pub const grunt_health: u8 = 50;
+pub const grunt_bullet_damage: f32 = 30;
+pub const grunt_spawn_interval: f32 = 0.7;
-pub const spawn_blorb_after: f32 = 60;
+// player
+pub const player_bullet_damage: f32 = 50;
diff --git a/src/enemy_types/blorb.zig b/src/enemy_types/blorb.zig
@@ -3,8 +3,8 @@ const std = @import("std");
const raylib = @import("raylib");
const bullet = @import("../bullet.zig");
+const constants = @import("../constants.zig");
-pub const bullet_damage: f32 = 80.0;
pub const size: raylib.Vector2 = .{ .x = 60, .y = 60 };
pub const Blorb = @This();
@@ -14,6 +14,7 @@ bullet_speed: f32 = 50.0,
direction: raylib.Vector2 = .{},
position: raylib.Vector2 = .{},
shoot_offset: u2 = 0,
+health: f32 = constants.blorb_health,
bullet_pool: bullet.Pool,
@@ -41,7 +42,12 @@ 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, bullet_damage);
+ self.bullet_pool.spawn(
+ spawn_position,
+ bullet_velocity,
+ raylib.PURPLE,
+ constants.blorb_bullet_damage,
+ );
}
self.shoot_offset +%= 1;
@@ -55,6 +61,11 @@ pub fn setRandomDirection(self: *Blorb) void {
};
}
+pub fn handleDamage(self: *Blorb, damage: f32) bool {
+ self.health -= damage;
+ return self.health <= 0;
+}
+
pub fn handleMovement(self: *Blorb) void {
const delta: f32 = raylib.GetFrameTime();
diff --git a/src/enemy_types/grunt.zig b/src/enemy_types/grunt.zig
@@ -2,8 +2,8 @@ const raylib = @import("raylib");
const raymath = @import("raymath");
const bullet = @import("../bullet.zig");
+const constants = @import("../constants.zig");
-pub const bullet_damage: f32 = 50.0;
pub const size: raylib.Vector2 = .{ .x = 40, .y = 40 };
pub const Grunt = @This();
@@ -12,6 +12,7 @@ movement_speed: f32 = 40.0,
bullet_speed: f32 = 100.0,
direction: raylib.Vector2 = .{},
position: raylib.Vector2 = .{},
+health: f32 = constants.grunt_health,
bullet_pool: bullet.Pool,
@@ -30,7 +31,7 @@ pub fn shoot(self: *Grunt) void {
.y = self.direction.y * self.bullet_speed,
},
raylib.RED,
- bullet_damage,
+ constants.grunt_bullet_damage,
);
}
@@ -48,6 +49,11 @@ pub fn handleMovement(self: *Grunt, target: raylib.Vector2) void {
self.position.y = @max(0, @min(max_y, self.position.y));
}
+pub fn handleDamage(self: *Grunt, damage: f32) bool {
+ self.health -= damage;
+ return self.health <= 0;
+}
+
pub fn render(self: *Grunt) void {
raylib.DrawRectangleV(
self.position,
diff --git a/src/entity.zig b/src/entity.zig
@@ -16,6 +16,13 @@ pub const Entity = union(EntityType) {
}
}
+ pub fn handleDamage(entity: *Entity, damage: f32) bool {
+ return switch (entity.*) {
+ .grunt => |*grunt| grunt.handleDamage(damage),
+ .blorb => |*blorb| blorb.handleDamage(damage),
+ };
+ }
+
pub fn move(entity: *Entity, target_position: raylib.Vector2) void {
switch (entity.*) {
.grunt => |*grunt| grunt.handleMovement(target_position),
diff --git a/src/player.zig b/src/player.zig
@@ -2,6 +2,7 @@ const raylib = @import("raylib");
const raymath = @import("raymath");
const bullet = @import("./bullet.zig");
+const constants = @import("./constants.zig");
const Timer = @import("./timer.zig");
pub const Player = @This();
@@ -20,6 +21,7 @@ position: raylib.Vector2 = .{},
velocity: raylib.Vector2 = .{},
max_health: f32 = starting_max_health,
health: f32 = starting_max_health,
+
health_regen_timer: Timer = .{
.duration = 5.0,
},
@@ -108,6 +110,11 @@ 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, 1);
+ self.bullet_pool.spawn(
+ center,
+ bullet_vel,
+ raylib.BLUE,
+ constants.player_bullet_damage,
+ );
}
}
diff --git a/src/state.zig b/src/state.zig
@@ -28,8 +28,8 @@ pub const GameState = struct {
enemies: [constants.max_enemies]Entity,
enemy_count: u8,
- grunt_spawn_time: Timer = .{ .duration = constants.grunt_spawn_time },
- blorb_spawn_time: Timer = .{ .duration = constants.blorb_spawn_time },
+ grunt_spawn_time: Timer = .{ .duration = constants.grunt_spawn_interval },
+ blorb_spawn_time: Timer = .{ .duration = constants.blorb_spawn_interval },
orphaned_bullet_pool: Bullet.Pool,
@@ -89,8 +89,8 @@ pub const GameState = struct {
self.orphaned_bullet_pool.count = 0;
- self.grunt_spawn_time = .{ .duration = constants.grunt_spawn_time };
- self.blorb_spawn_time = .{ .duration = constants.blorb_spawn_time };
+ self.grunt_spawn_time = .{ .duration = constants.grunt_spawn_interval };
+ self.blorb_spawn_time = .{ .duration = constants.blorb_spawn_interval };
self.upgrades.apply(&self.player);
self.player.health = self.player.max_health;
@@ -109,8 +109,8 @@ pub const GameState = struct {
const delta = raylib.GetFrameTime();
self.time += delta;
- self.grunt_spawn_time.duration = @max(0.15, constants.grunt_spawn_time / difficulty);
- self.blorb_spawn_time.duration = @max(0.15, constants.blorb_spawn_time / difficulty);
+ self.grunt_spawn_time.duration = @max(0.15, constants.grunt_spawn_interval / difficulty);
+ self.blorb_spawn_time.duration = @max(0.15, constants.blorb_spawn_interval / difficulty);
self.player.tick();
if (self.player.health <= 0) {
@@ -133,12 +133,12 @@ pub const GameState = struct {
self.spawn_enemy(grunt);
}
- if (self.time > constants.spawn_blorb_after) {
+ if (self.time > constants.blorb_spawn_after) {
if (self.blorb_spawn_time.tick(delta)) {
const blorb = createEnemy(
.{ .x = constants.screen_width, .y = constants.screen_height },
self.player,
- difficulty - constants.spawn_blorb_after,
+ difficulty,
.blorb,
Blorb.size,
);
@@ -196,10 +196,13 @@ 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;
+
+ if (grunt.handleDamage(constants.player_bullet_damage)) {
+ self.orphaned_bullet_pool.transferFrom(&grunt.bullet_pool);
+ self.despawn_enemy(enemy_idx);
+ self.enemies_killed += 1;
+ continue :lbl;
+ }
}
}
},
@@ -246,11 +249,14 @@ 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;
- continue :lbl;
+
+ if (blorb.handleDamage(constants.player_bullet_damage)) {
+ self.orphaned_bullet_pool.transferFrom(&blorb.bullet_pool);
+ self.despawn_enemy(enemy_idx);
+ self.enemies_killed += 1;
+ continue :lbl;
+ }
}
}
},