tree lerped health bar

This commit is contained in:
Rokas Puzonas 2026-07-19 03:42:07 +03:00
parent df7bbf087e
commit 096a082ac7

View File

@ -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})
});
}
}
}