From 096a082ac7545942c8478abe3cccf23260c6e6e3 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sun, 19 Jul 2026 03:42:07 +0300 Subject: [PATCH] tree lerped health bar --- src/app.zig | 141 +++++++++++++++++++++++++++------------------------- 1 file changed, 74 insertions(+), 67 deletions(-) diff --git a/src/app.zig b/src/app.zig index 86b52dd..a426731 100644 --- a/src/app.zig +++ b/src/app.zig @@ -180,6 +180,7 @@ const Entity = struct { minion_wander_cooldown: Nanoseconds = 0, tree_health: u32 = 0, + tree_visual_health: f32 = 0, tree_max_health: u32 = 0, station_spawn_tree_cooldown: Nanoseconds = 0, @@ -717,6 +718,7 @@ fn spawnTree(self: *App, station_id: EntityId) void { if (self.spawnEntity(Entity{ .type = .tree, .tree_health = health, + .tree_visual_health = @floatFromInt(health), .tree_max_health = health, .seed = rng.int(u64), @@ -1015,12 +1017,6 @@ fn minionLogic(self: *App, plt: Platform.Frame, minion_id: EntityId) !void { tree.tree_health = 0; } } - - if (tree.tree_health == 0) { - self.unsetEntityTarget(minion_id); - self.destroyTree(tree_id); - minion.minion_state = .wander; - } } else { walk_goal = tree.pos; } @@ -1467,64 +1463,75 @@ fn showDebug(self: *App, plt: Platform.Frame) !void { } } -fn drawTree(self: *App, seed: u64, pos: Vec2) void { +fn drawTree(self: *App, seed: u64, pos: Vec2, health_percent: f32) void { var prng = Prng.init(seed); const rng = prng.random(); Gfx.transformPush(); defer Gfx.transformPop(); - Gfx.transformTranslate(pos.sub(.init(terrain_tile_size.x/2, terrain_tile_size.y))); - Gfx.transformScale(terrain_tile_size); + Gfx.transformTranslate(pos); + Gfx.transformTranslate(.init((rng.float(f32)-0.5) * terrain_tile_size.x, 0)); - Gfx.transformTranslate(.init(rng.float(f32)-0.5, 0)); + { + Gfx.transformPush(); + defer Gfx.transformPop(); - const tree_middle = &[_]Gfx.Sprite.Id{ - self.terrain_sheet.get(125, 41), - self.terrain_sheet.get(125, 40), - self.terrain_sheet.get(125, 39), - }; + Gfx.transformTranslate(.init(-terrain_tile_size.x/2, -terrain_tile_size.y)); + Gfx.transformScale(terrain_tile_size); - const trunk_height = rng.uintAtMost(u32, 4) + 2; + const tree_middle = &[_]Gfx.Sprite.Id{ + self.terrain_sheet.get(125, 41), + self.terrain_sheet.get(125, 40), + self.terrain_sheet.get(125, 39), + }; - Gfx.drawSprite(self.terrain_sheet.get(125, 42), .init(0, 0), .init(1, 1), .white); - for (0..trunk_height) |i| { - const sprite = tree_middle[rng.uintLessThan(u32, tree_middle.len)]; - var trunk_pos = Vec2.init(0, -@as(f32, @floatFromInt(i))); - trunk_pos.x += (rng.float(f32)-0.5)*2 * 0.15; - Gfx.drawSprite(sprite, trunk_pos, .init(1, 1), .white); + const trunk_height = rng.uintAtMost(u32, 4) + 2; + + Gfx.drawSprite(self.terrain_sheet.get(125, 42), .init(0, 0), .init(1, 1), .white); + for (0..trunk_height) |i| { + const sprite = tree_middle[rng.uintLessThan(u32, tree_middle.len)]; + var trunk_pos = Vec2.init(0, -@as(f32, @floatFromInt(i))); + trunk_pos.x += (rng.float(f32)-0.5)*2 * 0.15; + Gfx.drawSprite(sprite, trunk_pos, .init(1, 1), .white); + } + Gfx.transformTranslate(Vec2.initFromInt(u32, 0, trunk_height).multiplyScalar(-1)); + Gfx.drawSprite( + self.terrain_sheet.get(125, 38), + .init(0, 0), + .init(1, 1), + .white + ); + + const inner_leaves = self.terrain_sheet.get(123, 42); + const bottom_leaves = self.terrain_sheet.get(124, 39); + const left_leaves = self.terrain_sheet.get(123, 38); + const corner_leaves = self.terrain_sheet.get(123, 39); + + Gfx.drawSprite(bottom_leaves, .init(0, -1), .init(1, 1), .white); + Gfx.drawSprite(corner_leaves, .init(-1, -1), .init(1, 1), .white); + Gfx.drawSprite(corner_leaves, .init(2, -1), .init(-1, 1), .white); + + const leaves_height = rng.uintAtMost(u32, 3) + 1; + + for (0..leaves_height) |i| { + var base = Vec2.initFromInt(usize, 0, i).multiplyScalar(-1); + base.x += (rng.float(f32)-0.5)*2 * 0.2; + Gfx.drawSprite(inner_leaves, base.add(.init(0, -2)), .init(1, 1), .white); + Gfx.drawSprite(left_leaves, base.add(.init(2, -2)), .init(-1, 1), .white); + Gfx.drawSprite(left_leaves, base.add(.init(-1, -2)), .init(1, 1), .white); + } + Gfx.transformTranslate(Vec2.initFromInt(u32, 0, leaves_height).multiplyScalar(-1)); + + Gfx.drawSprite(bottom_leaves, .init(0, -1), .init(1, -1), .white); + Gfx.drawSprite(corner_leaves, .init(-1, -1), .init(1, -1), .white); + Gfx.drawSprite(corner_leaves, .init(2, -1), .init(-1, -1), .white); } - Gfx.transformTranslate(Vec2.initFromInt(u32, 0, trunk_height).multiplyScalar(-1)); - Gfx.drawSprite( - self.terrain_sheet.get(125, 38), - .init(0, 0), - .init(1, 1), - .white - ); - const inner_leaves = self.terrain_sheet.get(123, 42); - const bottom_leaves = self.terrain_sheet.get(124, 39); - const left_leaves = self.terrain_sheet.get(123, 38); - const corner_leaves = self.terrain_sheet.get(123, 39); - - Gfx.drawSprite(bottom_leaves, .init(0, -1), .init(1, 1), .white); - Gfx.drawSprite(corner_leaves, .init(-1, -1), .init(1, 1), .white); - Gfx.drawSprite(corner_leaves, .init(2, -1), .init(-1, 1), .white); - - const leaves_height = rng.uintAtMost(u32, 3) + 1; - - for (0..leaves_height) |i| { - var base = Vec2.initFromInt(usize, 0, i).multiplyScalar(-1); - base.x += (rng.float(f32)-0.5)*2 * 0.2; - Gfx.drawSprite(inner_leaves, base.add(.init(0, -2)), .init(1, 1), .white); - Gfx.drawSprite(left_leaves, base.add(.init(2, -2)), .init(-1, 1), .white); - Gfx.drawSprite(left_leaves, base.add(.init(-1, -2)), .init(1, 1), .white); + if (health_percent < 1) { + drawProgressBar(1, .init(0, 20), .init(terrain_tile_size.x, 10), .black); + drawProgressBar(health_percent, .init(0, 20), .init(terrain_tile_size.x, 10), .white); } - Gfx.transformTranslate(Vec2.initFromInt(u32, 0, leaves_height).multiplyScalar(-1)); - - Gfx.drawSprite(bottom_leaves, .init(0, -1), .init(1, -1), .white); - Gfx.drawSprite(corner_leaves, .init(-1, -1), .init(1, -1), .white); - Gfx.drawSprite(corner_leaves, .init(2, -1), .init(-1, -1), .white); } pub fn frame(self: *App, plt: Platform.Frame) !void { @@ -1553,7 +1560,6 @@ pub fn frame(self: *App, plt: Platform.Frame) !void { Gfx.transformTranslate(self.camera_pos.multiplyScalar(-1)); Gfx.setClearColor(.rgb(40, 40, 40)); - Gfx.drawLine(.init(-4000, 0), .init(4000, 0), .white, 5); { // Spawn in or delete minions based on self.upgrades.minion_count var minion_count: u32 = 0; @@ -1585,7 +1591,7 @@ pub fn frame(self: *App, plt: Platform.Frame) !void { } } - const wood_station_first_pos = -100; + const wood_station_first_pos = -200; const wood_station_step = -70; if (station_count > self.upgrades.tree_station_count) { @@ -1849,10 +1855,22 @@ pub fn frame(self: *App, plt: Platform.Frame) !void { while (tree_iter.next()) |id| { const e = self.entities.getAssumeExists(id); - self.drawTree(e.seed, e.pos); + e.tree_visual_health = std.math.lerp( + e.tree_visual_health, + @as(f32, @floatFromInt(e.tree_health)), + 0.05, + ); - const progress = @as(f32, @floatFromInt(e.tree_health)) / @as(f32, @floatFromInt(e.tree_max_health)); - drawProgressBar(progress, e.pos.add(.init(0, 20)), .init(40, 10), .rgb(0, 100, 20)); + const health_percent = e.tree_visual_health / @as(f32, @floatFromInt(e.tree_max_health)); + self.drawTree( + e.seed, + e.pos, + health_percent + ); + + if (e.tree_visual_health < 0.1) { + self.destroyTree(id); + } } } @@ -1917,11 +1935,6 @@ pub fn frame(self: *App, plt: Platform.Frame) !void { pos.x -= character_size.x/2; } - Gfx.drawRectangle( - e.pos.sub(.init(5, 5)), - .init(10, 10), - .white - ); Gfx.drawSprite(sprite, pos, size, .white); if (e.type == .minion and e.minion_state == .burn_wood and e.minion_throw_cooldown > 0) { @@ -1931,12 +1944,6 @@ pub fn frame(self: *App, plt: Platform.Frame) !void { if (e.type == .burn_station) { Gfx.drawRectangle(e.pos.sub(.init(5, 5)), .init(10, 10), .rgb(200, 20, 20)); - } else if (e.type == .minion) { - Gfx.drawText(self.font, .{ - .pos = e.pos.sub(.init(20, 50)), - .height = 16, - .text = try std.fmt.allocPrint(plt.arena, "{}", .{e.minion_state}) - }); } } }