game-2025-12-13/src/timer.zig

82 lines
2.1 KiB
Zig

const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Entity = @import("./entity.zig");
const GenerationalArrayList = @import("./generational_array_list.zig").GenerationalArrayList;
const Timer = @This();
const ArrayList = GenerationalArrayList(Timer);
pub const Id = ArrayList.Id;
pub const Options = struct {
duration: f64,
entity: ?Entity.Id = null
};
started_at: f64,
finishes_at: f64,
entity: ?Entity.Id,
pub const List = struct {
array_list: GenerationalArrayList(Timer),
now: f64,
pub const empty = List{
.array_list = .empty,
.now = 0
};
pub fn deinit(self: *List, gpa: Allocator) void {
self.array_list.deinit(gpa);
}
pub fn clone(self: *List, gpa: Allocator) !List {
const array_list = try self.array_list.clone(gpa);
errdefer array_list.deinit(gpa);
return List{
.now = self.now,
.array_list = array_list
};
}
pub fn start(self: *List, gpa: Allocator, opts: Options) !Id {
assert(opts.duration > 0);
return try self.array_list.insert(gpa, .{
.started_at = self.now,
.finishes_at = self.now + opts.duration,
.entity = opts.entity
});
}
pub fn stop(self: *List, id: Id) void {
_ = self.array_list.remove(id);
}
pub fn running(self: *List, id: Id) bool {
const timer = self.array_list.get(id) orelse return false;
return timer.finishes_at > self.now;
}
pub fn percent_passed(self: *List, id: Id) f32 {
const timer = self.array_list.get(id) orelse return 0;
const time_passed = self.now - timer.started_at;
const duration = timer.finishes_at - timer.started_at;
return @floatCast(std.math.clamp(time_passed / duration, 0, 1));
}
pub fn finished(self: *List, id: Id) bool {
const timer = self.array_list.get(id) orelse return false;
if (timer.finishes_at > self.now) {
return false;
}
self.array_list.removeAssumeExists(id);
return true;
}
};