add upgrades
This commit is contained in:
parent
46ca2e5e1e
commit
300c8c47e2
160
src/app.zig
160
src/app.zig
@ -36,6 +36,8 @@ entities_buffer: [max_entities]EntitySlotMap.Slot,
|
|||||||
entities: EntitySlotMap,
|
entities: EntitySlotMap,
|
||||||
eternal_flame_id: EntityId,
|
eternal_flame_id: EntityId,
|
||||||
|
|
||||||
|
upgrades: Upgrades,
|
||||||
|
|
||||||
font: Gfx.Font.Id,
|
font: Gfx.Font.Id,
|
||||||
idle_animations: AnimationDirections,
|
idle_animations: AnimationDirections,
|
||||||
walk_animations: AnimationDirections,
|
walk_animations: AnimationDirections,
|
||||||
@ -160,7 +162,6 @@ const Entity = struct {
|
|||||||
|
|
||||||
minion_state: MinionState = .wander,
|
minion_state: MinionState = .wander,
|
||||||
minion_chop_cooldown: Nanoseconds = 0,
|
minion_chop_cooldown: Nanoseconds = 0,
|
||||||
minion_chop_damage: u32 = 2,
|
|
||||||
minion_throw_cooldown: Nanoseconds = 0,
|
minion_throw_cooldown: Nanoseconds = 0,
|
||||||
minion_carried_wood: ?EntityId = null,
|
minion_carried_wood: ?EntityId = null,
|
||||||
|
|
||||||
@ -178,9 +179,6 @@ const Entity = struct {
|
|||||||
pos: Vec2 = .init(0, 0),
|
pos: Vec2 = .init(0, 0),
|
||||||
vel: Vec2 = .init(0, 0),
|
vel: Vec2 = .init(0, 0),
|
||||||
acc: Vec2 = .init(0, 0),
|
acc: Vec2 = .init(0, 0),
|
||||||
max_velocity: f32 = 0,
|
|
||||||
friction: f32 = 0,
|
|
||||||
max_walk_speed: f32 = 0,
|
|
||||||
|
|
||||||
animation: AnimationName = .idle,
|
animation: AnimationName = .idle,
|
||||||
animation_dir: AnimationDirection = .down,
|
animation_dir: AnimationDirection = .down,
|
||||||
@ -215,6 +213,28 @@ const Entity = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Upgrades = struct {
|
||||||
|
minion_chop_damage: u32 = 2,
|
||||||
|
minion_chop_rate: f32 = 1,
|
||||||
|
minion_throw_cooldown: Nanoseconds = std.time.ns_per_s,
|
||||||
|
minion_walk: MinionWalkStats = .{},
|
||||||
|
|
||||||
|
tree_health: u32 = 10,
|
||||||
|
tree_respawn_duration: Nanoseconds = std.time.ns_per_s,
|
||||||
|
tree_wood_amount: u32 = 1,
|
||||||
|
|
||||||
|
burn_max_stack_size: u32 = 10,
|
||||||
|
burn_speed: f32 = 10,
|
||||||
|
burn_wood_health: f32 = 20,
|
||||||
|
burn_heat_per_wood: u32 = 1,
|
||||||
|
|
||||||
|
const MinionWalkStats = struct {
|
||||||
|
friction: f32 = 0.998,
|
||||||
|
max_velocity: f32 = 50,
|
||||||
|
max_speed: f32 = 300,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
fn initImageDataFromSTB(img: STBImage) Gfx.ImageData {
|
fn initImageDataFromSTB(img: STBImage) Gfx.ImageData {
|
||||||
return Gfx.ImageData{
|
return Gfx.ImageData{
|
||||||
.width = img.width,
|
.width = img.width,
|
||||||
@ -272,6 +292,7 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
.camera_pos = .init(0, 0),
|
.camera_pos = .init(0, 0),
|
||||||
.font = font,
|
.font = font,
|
||||||
.eternal_flame_id = undefined,
|
.eternal_flame_id = undefined,
|
||||||
|
.upgrades = .{}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.spawnMinion(.init(0, 0));
|
self.spawnMinion(.init(0, 0));
|
||||||
@ -306,9 +327,6 @@ pub fn spawnMinion(self: *App, pos: Vec2) void {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
.friction = 0.998,
|
|
||||||
.max_velocity = 50,
|
|
||||||
.max_walk_speed = 300,
|
|
||||||
|
|
||||||
.animation = .idle,
|
.animation = .idle,
|
||||||
});
|
});
|
||||||
@ -337,7 +355,7 @@ fn spawnTree(self: *App, station_id: EntityId) void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const health = 10;
|
const health = self.upgrades.tree_health;
|
||||||
if (self.spawnEntity(Entity{
|
if (self.spawnEntity(Entity{
|
||||||
.type = .tree,
|
.type = .tree,
|
||||||
.tree_health = health,
|
.tree_health = health,
|
||||||
@ -353,13 +371,15 @@ fn destroyTree(self: *App, tree_id: EntityId) void {
|
|||||||
const tree = self.entities.get(tree_id) orelse return;
|
const tree = self.entities.get(tree_id) orelse return;
|
||||||
assert(tree.type == .tree);
|
assert(tree.type == .tree);
|
||||||
|
|
||||||
self.spawnWood(tree.pos);
|
for (0..self.upgrades.tree_wood_amount) |_| {
|
||||||
|
self.spawnWood(tree.pos);
|
||||||
|
}
|
||||||
|
|
||||||
self.entities.removeAssumeExists(tree_id);
|
self.entities.removeAssumeExists(tree_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawnWood(self: *App, pos: Vec2) void {
|
fn spawnWood(self: *App, pos: Vec2) void {
|
||||||
const health = 20;
|
const health = self.upgrades.burn_wood_health;
|
||||||
|
|
||||||
_ = self.spawnEntity(Entity{
|
_ = self.spawnEntity(Entity{
|
||||||
.type = .wood,
|
.type = .wood,
|
||||||
@ -522,6 +542,20 @@ fn drawProgressBar(progress: f32, center: Vec2, size: Vec2, color: Color) void {
|
|||||||
Gfx.drawLine(from, from.add(.init(size.x * progress, 0)), color, size.y);
|
Gfx.drawLine(from, from.add(.init(size.x * progress, 0)), color, size.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn countEternalFlameStackSize(self: *App) u32 {
|
||||||
|
var result: u32 = 0;
|
||||||
|
|
||||||
|
var wood_iter = self.initEntityIteratorByType(.wood);
|
||||||
|
while (wood_iter.next()) |wood_id| {
|
||||||
|
const wood = self.entities.getAssumeExists(wood_id);
|
||||||
|
if (wood.wood_burning) {
|
||||||
|
result += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
fn minionLogic(self: *App, plt: Platform.Frame, minion_id: EntityId) !void {
|
fn minionLogic(self: *App, plt: Platform.Frame, minion_id: EntityId) !void {
|
||||||
const minion = self.entities.getAssumeExists(minion_id);
|
const minion = self.entities.getAssumeExists(minion_id);
|
||||||
assert(minion.type == .minion);
|
assert(minion.type == .minion);
|
||||||
@ -549,11 +583,16 @@ fn minionLogic(self: *App, plt: Platform.Frame, minion_id: EntityId) !void {
|
|||||||
|
|
||||||
if (minion.pos.distance(tree.pos) < goal_distance) {
|
if (minion.pos.distance(tree.pos) < goal_distance) {
|
||||||
if (minion.minion_chop_cooldown == 0) {
|
if (minion.minion_chop_cooldown == 0) {
|
||||||
minion.minion_chop_cooldown = std.time.ns_per_ms * 500;
|
minion.minion_chop_cooldown = @intFromFloat(std.time.ns_per_s / self.upgrades.minion_chop_rate);
|
||||||
tree.tree_health -= minion.minion_chop_damage;
|
|
||||||
|
if (tree.tree_health >= self.upgrades.minion_chop_damage) {
|
||||||
|
tree.tree_health -= self.upgrades.minion_chop_damage;
|
||||||
|
} else {
|
||||||
|
tree.tree_health = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tree.tree_health <= 0) {
|
if (tree.tree_health == 0) {
|
||||||
self.unsetEntityTarget(minion_id);
|
self.unsetEntityTarget(minion_id);
|
||||||
self.destroyTree(tree_id);
|
self.destroyTree(tree_id);
|
||||||
minion.minion_state = .wander;
|
minion.minion_state = .wander;
|
||||||
@ -601,12 +640,13 @@ fn minionLogic(self: *App, plt: Platform.Frame, minion_id: EntityId) !void {
|
|||||||
if (minion.minion_carried_wood) |wood_id| {
|
if (minion.minion_carried_wood) |wood_id| {
|
||||||
const wood = self.entities.getAssumeExists(wood_id);
|
const wood = self.entities.getAssumeExists(wood_id);
|
||||||
const eternal_flame = self.entities.getAssumeExists(self.eternal_flame_id);
|
const eternal_flame = self.entities.getAssumeExists(self.eternal_flame_id);
|
||||||
|
if (self.countEternalFlameStackSize() < self.upgrades.burn_max_stack_size) {
|
||||||
wood.pos = eternal_flame.pos;
|
wood.pos = eternal_flame.pos;
|
||||||
wood.wood_burning = true;
|
wood.wood_burning = true;
|
||||||
wood.wood_carried_by = null;
|
wood.wood_carried_by = null;
|
||||||
minion.minion_carried_wood = null;
|
minion.minion_carried_wood = null;
|
||||||
minion.minion_throw_cooldown = std.time.ns_per_s;
|
minion.minion_throw_cooldown = self.upgrades.minion_throw_cooldown;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
minion.minion_throw_cooldown = @max(minion.minion_throw_cooldown - plt.dt, 0);
|
minion.minion_throw_cooldown = @max(minion.minion_throw_cooldown - plt.dt, 0);
|
||||||
if (minion.minion_throw_cooldown == 0) {
|
if (minion.minion_throw_cooldown == 0) {
|
||||||
@ -617,11 +657,12 @@ fn minionLogic(self: *App, plt: Platform.Frame, minion_id: EntityId) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (walk_goal) |pos| {
|
if (walk_goal) |pos| {
|
||||||
|
const stats = self.upgrades.minion_walk;
|
||||||
const diff = minion.pos.x - pos.x;
|
const diff = minion.pos.x - pos.x;
|
||||||
if (diff < -goal_distance) {
|
if (diff < -goal_distance) {
|
||||||
minion.acc = .init(minion.max_walk_speed, 0);
|
minion.acc = .init(stats.max_speed, 0);
|
||||||
} else if (diff > goal_distance) {
|
} else if (diff > goal_distance) {
|
||||||
minion.acc = .init(-minion.max_walk_speed, 0);
|
minion.acc = .init(-stats.max_speed, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -674,7 +715,7 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
if (wood_station.station_owned_tree) |station_owned_tree| {
|
if (wood_station.station_owned_tree) |station_owned_tree| {
|
||||||
if (!self.entities.exists(station_owned_tree)) {
|
if (!self.entities.exists(station_owned_tree)) {
|
||||||
wood_station.station_owned_tree = null;
|
wood_station.station_owned_tree = null;
|
||||||
wood_station.station_spawn_tree_cooldown = std.time.ns_per_s;
|
wood_station.station_spawn_tree_cooldown = self.upgrades.tree_respawn_duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -710,8 +751,6 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const burn_speed = 10;
|
|
||||||
|
|
||||||
var wood_iter = self.initEntityIteratorByType(.wood);
|
var wood_iter = self.initEntityIteratorByType(.wood);
|
||||||
while (wood_iter.next()) |wood_id| {
|
while (wood_iter.next()) |wood_id| {
|
||||||
const wood = self.entities.getAssumeExists(wood_id);
|
const wood = self.entities.getAssumeExists(wood_id);
|
||||||
@ -720,10 +759,10 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
|
|
||||||
// Apply burn
|
// Apply burn
|
||||||
if (wood.wood_burning) {
|
if (wood.wood_burning) {
|
||||||
wood.wood_health = @max(wood.wood_health - burn_speed * dt, 0);
|
wood.wood_health = @max(wood.wood_health - self.upgrades.burn_speed * dt, 0);
|
||||||
|
|
||||||
if (wood.wood_health == 0) {
|
if (wood.wood_health == 0) {
|
||||||
self.heat += 1;
|
self.heat += self.upgrades.burn_heat_per_wood;
|
||||||
self.entities.removeAssumeExists(wood_id);
|
self.entities.removeAssumeExists(wood_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,15 +920,21 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
|
|
||||||
if (e.flags.has_kinematics) {
|
if (e.flags.has_kinematics) {
|
||||||
e.vel = e.vel.add(e.acc.multiplyScalar(dt));
|
e.vel = e.vel.add(e.acc.multiplyScalar(dt));
|
||||||
e.vel = e.vel.limitLength(e.max_velocity);
|
|
||||||
e.pos = e.pos.add(e.vel.multiplyScalar(dt));
|
e.pos = e.pos.add(e.vel.multiplyScalar(dt));
|
||||||
|
|
||||||
const friction_force = std.math.pow(f32, 1 - e.friction, dt);
|
|
||||||
e.vel = e.vel.multiplyScalar(friction_force);
|
|
||||||
|
|
||||||
e.acc = .init(0, 0);
|
e.acc = .init(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.type == .minion) {
|
||||||
|
const stats = self.upgrades.minion_walk;
|
||||||
|
e.vel = e.vel.limitLength(stats.max_velocity);
|
||||||
|
|
||||||
|
if (0 <= stats.friction and stats.friction <= 1) {
|
||||||
|
const friction_force = std.math.pow(f32, 1 - stats.friction, dt);
|
||||||
|
e.vel = e.vel.multiplyScalar(friction_force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (e.flags.has_animation) {
|
if (e.flags.has_animation) {
|
||||||
const animations = switch (e.animation) {
|
const animations = switch (e.animation) {
|
||||||
.idle => self.idle_animations,
|
.idle => self.idle_animations,
|
||||||
@ -958,6 +1003,11 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
const eternal_flame = self.entities.getAssumeExists(id);
|
const eternal_flame = self.entities.getAssumeExists(id);
|
||||||
|
|
||||||
Gfx.drawRectangle(eternal_flame.pos.sub(.init(10, 50)), .init(30, 50), .rgb(150, 30, 20));
|
Gfx.drawRectangle(eternal_flame.pos.sub(.init(10, 50)), .init(30, 50), .rgb(150, 30, 20));
|
||||||
|
Gfx.drawText(self.font, .{
|
||||||
|
.text = try std.fmt.allocPrint(plt.arena, "Stack: {}", .{self.countEternalFlameStackSize()}),
|
||||||
|
.pos = eternal_flame.pos.sub(.init(10, 80)),
|
||||||
|
.height = 24
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,12 +1026,58 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
.text = try std.fmt.allocPrint(plt.arena, "Heat: {}", .{self.heat}),
|
.text = try std.fmt.allocPrint(plt.arena, "Heat: {}", .{self.heat}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ImGUI.beginWindow(.{ .name = "Debug", .size = .init(200, 100) })) {
|
if (ImGUI.beginWindow(.{ .name = "Debug", .alpha = 0.8, .size = .init(500, 200) })) {
|
||||||
defer ImGUI.endWindow();
|
defer ImGUI.endWindow();
|
||||||
|
|
||||||
if (ImGUI.button("spawn")) {
|
if (ImGUI.button("spawn minion")) {
|
||||||
self.spawnMinion(.init(32, 0));
|
self.spawnMinion(.init(32, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var heat: u32 = @intCast(self.heat);
|
||||||
|
if (ImGUI.inputU32("heat", &heat)) {
|
||||||
|
self.heat = @intCast(heat);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGUI.separator();
|
||||||
|
_ = ImGUI.text("Minion upgrades", .{});
|
||||||
|
_ = ImGUI.inputU32("chop_damage", &self.upgrades.minion_chop_damage);
|
||||||
|
_ = ImGUI.inputF32Drag(.{
|
||||||
|
.label = "chop_rate",
|
||||||
|
.value = &self.upgrades.minion_chop_rate
|
||||||
|
});
|
||||||
|
_ = ImGUI.inputDuration("throw_cooldown", &self.upgrades.minion_throw_cooldown);
|
||||||
|
_ = ImGUI.inputF32Drag(.{
|
||||||
|
.label = "walk_max_speed",
|
||||||
|
.value = &self.upgrades.minion_walk.max_speed
|
||||||
|
});
|
||||||
|
_ = ImGUI.inputF32Drag(.{
|
||||||
|
.label = "walk_max_vel",
|
||||||
|
.value = &self.upgrades.minion_walk.max_velocity
|
||||||
|
});
|
||||||
|
_ = ImGUI.inputF32Drag(.{
|
||||||
|
.label = "walk_friction",
|
||||||
|
.value = &self.upgrades.minion_walk.friction,
|
||||||
|
.ex = .{ .min = 0, .max = 1, .speed = 0.0001 }
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGUI.separator();
|
||||||
|
_ = ImGUI.text("Tree upgrades", .{});
|
||||||
|
_ = ImGUI.inputU32("health", &self.upgrades.tree_health);
|
||||||
|
_ = ImGUI.inputU32("wood_amount", &self.upgrades.tree_wood_amount);
|
||||||
|
_ = ImGUI.inputDuration("respawn_duration", &self.upgrades.tree_respawn_duration);
|
||||||
|
|
||||||
|
ImGUI.separator();
|
||||||
|
_ = ImGUI.text("Burn upgrades", .{});
|
||||||
|
_ = ImGUI.inputF32Drag(.{
|
||||||
|
.label = "speed",
|
||||||
|
.value = &self.upgrades.burn_speed
|
||||||
|
});
|
||||||
|
_ = ImGUI.inputF32(.{
|
||||||
|
.label = "wood_health",
|
||||||
|
.value = &self.upgrades.burn_wood_health
|
||||||
|
});
|
||||||
|
_ = ImGUI.inputU32("heat_per_wood", &self.upgrades.burn_heat_per_wood);
|
||||||
|
_ = ImGUI.inputU32("max_stack_size", &self.upgrades.burn_max_stack_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
124
src/imgui.zig
124
src/imgui.zig
@ -15,6 +15,8 @@ const simgui = sokol.imgui;
|
|||||||
|
|
||||||
const ig = @import("cimgui");
|
const ig = @import("cimgui");
|
||||||
|
|
||||||
|
const Nanoseconds = @import("./platform.zig").Nanoseconds;
|
||||||
|
|
||||||
const ImGUI = @This();
|
const ImGUI = @This();
|
||||||
|
|
||||||
const State = struct {
|
const State = struct {
|
||||||
@ -150,6 +152,7 @@ pub const WindowOptions = struct {
|
|||||||
size: ?Vec2 = null,
|
size: ?Vec2 = null,
|
||||||
collapsed: ?bool = null,
|
collapsed: ?bool = null,
|
||||||
open: ?*bool = null,
|
open: ?*bool = null,
|
||||||
|
alpha: f32 = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn beginWindow(opts: WindowOptions) bool {
|
pub fn beginWindow(opts: WindowOptions) bool {
|
||||||
@ -175,7 +178,7 @@ pub fn beginWindow(opts: WindowOptions) bool {
|
|||||||
ig.igSetNextWindowCollapsed(collapsed, ig.ImGuiCond_Once);
|
ig.igSetNextWindowCollapsed(collapsed, ig.ImGuiCond_Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
ig.igSetNextWindowBgAlpha(1);
|
ig.igSetNextWindowBgAlpha(opts.alpha);
|
||||||
|
|
||||||
const frame = g_state.frame.?;
|
const frame = g_state.frame.?;
|
||||||
const namez = frame.dupeSentinel(u8, opts.name, 0) catch blk: {
|
const namez = frame.dupeSentinel(u8, opts.name, 0) catch blk: {
|
||||||
@ -264,6 +267,125 @@ pub fn slider(opts: SliderOptions) bool {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InputF32Options = struct {
|
||||||
|
label: []const u8,
|
||||||
|
value: *f32,
|
||||||
|
ex: ?struct {
|
||||||
|
step: f32,
|
||||||
|
step_fast: f32,
|
||||||
|
format: [*c]const u8 = null,
|
||||||
|
} = null
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn inputF32(opts: InputF32Options) bool {
|
||||||
|
if (!build_options.has_imgui) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const self = &g_state;
|
||||||
|
if (!self.enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.ex) |ex| {
|
||||||
|
return ig.igInputFloatEx(
|
||||||
|
formatString("{s}", .{opts.label}),
|
||||||
|
opts.value,
|
||||||
|
ex.step,
|
||||||
|
ex.step_fast,
|
||||||
|
ex.format,
|
||||||
|
ig.ImGuiInputTextFlags_None
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return ig.igInputFloat(
|
||||||
|
formatString("{s}", .{opts.label}),
|
||||||
|
opts.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputF32DragOptions = struct {
|
||||||
|
label: []const u8,
|
||||||
|
value: *f32,
|
||||||
|
ex: ?struct {
|
||||||
|
speed: f32 = 1,
|
||||||
|
min: f32 = 0,
|
||||||
|
max: f32 = 10
|
||||||
|
} = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn inputF32Drag(opts: InputF32DragOptions) bool {
|
||||||
|
if (!build_options.has_imgui) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const self = &g_state;
|
||||||
|
if (!self.enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.ex) |ex| {
|
||||||
|
return ig.igDragFloatEx(
|
||||||
|
formatString("{s}", .{opts.label}),
|
||||||
|
opts.value,
|
||||||
|
ex.speed,
|
||||||
|
ex.min,
|
||||||
|
ex.max,
|
||||||
|
null,
|
||||||
|
ig.ImGuiSliderFlags_None
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return ig.igDragFloat(
|
||||||
|
formatString("{s}", .{opts.label}),
|
||||||
|
opts.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inputDuration(label: []const u8, duration_ns: *Nanoseconds) bool {
|
||||||
|
const duration_ms: f32 = @floatFromInt(@divTrunc(duration_ns.*, std.time.ns_per_ms));
|
||||||
|
var duration_s = duration_ms / std.time.ms_per_s;
|
||||||
|
if (ImGUI.inputF32(.{
|
||||||
|
.label = label,
|
||||||
|
.value = &duration_s,
|
||||||
|
.ex = .{
|
||||||
|
.step = 0.01,
|
||||||
|
.step_fast = 0.1,
|
||||||
|
.format = "%0.3f s"
|
||||||
|
}
|
||||||
|
})) {
|
||||||
|
duration_ns.* = @trunc(duration_s * std.time.ns_per_s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inputI32(label: []const u8, value: *i32) bool {
|
||||||
|
if (!build_options.has_imgui) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const self = &g_state;
|
||||||
|
if (!self.enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ig.igInputInt(
|
||||||
|
formatString("{s}", .{label}),
|
||||||
|
value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inputU32(label: []const u8, value: *u32) bool {
|
||||||
|
var value_i32: i32 = @intCast(value.*);
|
||||||
|
if (inputI32(label, &value_i32)) {
|
||||||
|
if (value_i32 >= 0) {
|
||||||
|
value.* = @intCast(value_i32);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn checkbox(label: []const u8, value: *bool) bool {
|
pub fn checkbox(label: []const u8, value: *bool) bool {
|
||||||
if (!build_options.has_imgui) {
|
if (!build_options.has_imgui) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -164,68 +164,101 @@ fn PlatformType(App: type) type {
|
|||||||
|
|
||||||
// TODO: I don't like the names of these 'event' related functions.
|
// TODO: I don't like the names of these 'event' related functions.
|
||||||
// All of them "append an event", but they do different things.
|
// All of them "append an event", but they do different things.
|
||||||
fn applyEventToState(self: *Self, e: Input.Event) void {
|
fn applyEventToState(self: *Self, e: Input.Event) bool {
|
||||||
const input = &self.input;
|
const input = &self.input;
|
||||||
|
|
||||||
switch (e) {
|
switch (e) {
|
||||||
.key_pressed => |key| {
|
.key_pressed => |key| {
|
||||||
assert(!input.isKeyDown(key));
|
if (input.isKeyDown(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.keyboard.press(key);
|
input.keyboard.press(key);
|
||||||
self.last_key_pressed = key;
|
self.last_key_pressed = key;
|
||||||
},
|
},
|
||||||
.key_released => |key| {
|
.key_released => |key| {
|
||||||
assert(input.isKeyDown(key));
|
if (!input.isKeyDown(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.keyboard.release(key);
|
input.keyboard.release(key);
|
||||||
},
|
},
|
||||||
.mouse_pressed => |button| {
|
.mouse_pressed => |button| {
|
||||||
assert(input.mouse_position != null);
|
if (input.mouse_position == null or input.isMouseDown(button)) {
|
||||||
assert(!input.isMouseDown(button));
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.mouse_buttons.press(button);
|
input.mouse_buttons.press(button);
|
||||||
},
|
},
|
||||||
.mouse_released => |button| {
|
.mouse_released => |button| {
|
||||||
assert(input.mouse_position != null);
|
if (input.mouse_position == null or !input.isMouseDown(button)) {
|
||||||
assert(input.isMouseDown(button));
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.mouse_buttons.release(button);
|
input.mouse_buttons.release(button);
|
||||||
},
|
},
|
||||||
.mouse_enter => |pos| {
|
.mouse_enter => |pos| {
|
||||||
assert(input.mouse_position == null);
|
if (input.mouse_position != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.mouse_position = pos;
|
input.mouse_position = pos;
|
||||||
},
|
},
|
||||||
.mouse_move => |pos| {
|
.mouse_move => |pos| {
|
||||||
assert(input.mouse_position != null);
|
if (input.mouse_position == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.mouse_position = pos;
|
input.mouse_position = pos;
|
||||||
},
|
},
|
||||||
.mouse_leave => {
|
.mouse_leave => {
|
||||||
assert(input.mouse_position != null);
|
if (input.mouse_position == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.mouse_position = null;
|
input.mouse_position = null;
|
||||||
},
|
},
|
||||||
.char => |char| {
|
.char => |char| {
|
||||||
// A 'key_pressed' event always occurs before a 'char' event.
|
// A 'key_pressed' event always occurs before a 'char' event.
|
||||||
// This allows us to differentiate between keycodes and scan codes.
|
// This allows us to differentiate between keycodes and scan codes.
|
||||||
// And how to map key codes to character codes.
|
// And how to map key codes to character codes.
|
||||||
assert(self.last_key_pressed != null);
|
if (self.last_key_pressed == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.key_code_mapping.put(self.last_key_pressed.?, char);
|
input.key_code_mapping.put(self.last_key_pressed.?, char);
|
||||||
self.last_key_pressed = null;
|
self.last_key_pressed = null;
|
||||||
},
|
},
|
||||||
.mouse_scroll => |offset| {
|
.mouse_scroll => |offset| {
|
||||||
assert(input.mouse_position != null);
|
if (input.mouse_position == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.mouse_scroll = input.mouse_scroll.add(offset);
|
input.mouse_scroll = input.mouse_scroll.add(offset);
|
||||||
},
|
},
|
||||||
.window_resize => |window_size| {
|
.window_resize => |window_size| {
|
||||||
self.input.window_size = window_size;
|
self.input.window_size = window_size;
|
||||||
},
|
},
|
||||||
.focused => {
|
.focused => {
|
||||||
assert(!input.focused);
|
if (input.focused) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
input.focused = true;
|
input.focused = true;
|
||||||
},
|
},
|
||||||
.unfocused => {
|
.unfocused => {
|
||||||
assert(input.focused);
|
if (!input.focused) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
assert(input.mouse_position == null);
|
assert(input.mouse_position == null);
|
||||||
assert(input.keyboard.down.eql(.empty));
|
assert(input.keyboard.down.eql(.empty));
|
||||||
assert(input.mouse_buttons.down.eql(.empty));
|
assert(input.mouse_buttons.down.eql(.empty));
|
||||||
input.focused = false;
|
input.focused = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn appendEvent(self: *Self, e: Input.Event) void {
|
fn appendEvent(self: *Self, e: Input.Event) void {
|
||||||
@ -237,8 +270,9 @@ fn PlatformType(App: type) type {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.events.appendAssumeCapacity(e);
|
if (self.applyEventToState(e)) {
|
||||||
self.applyEventToState(e);
|
self.events.appendAssumeCapacity(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pushEvent(self: *Self, e: Input.Event) void {
|
fn pushEvent(self: *Self, e: Input.Event) void {
|
||||||
@ -249,16 +283,6 @@ fn PlatformType(App: type) type {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e == .key_pressed and input.isKeyDown(e.key_pressed)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (e == .key_released and !input.isKeyDown(e.key_released)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (e == .mouse_move and input.mouse_position.?.eql(e.mouse_move)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e == .unfocused) {
|
if (e == .unfocused) {
|
||||||
var key_iter = input.keyboard.down.iterator();
|
var key_iter = input.keyboard.down.iterator();
|
||||||
while (key_iter.next()) |key| {
|
while (key_iter.next()) |key| {
|
||||||
@ -268,9 +292,7 @@ fn PlatformType(App: type) type {
|
|||||||
while (mouse_buttons_iter.next()) |button| {
|
while (mouse_buttons_iter.next()) |button| {
|
||||||
self.appendEvent(.{ .mouse_released = button });
|
self.appendEvent(.{ .mouse_released = button });
|
||||||
}
|
}
|
||||||
if (input.mouse_position != null) {
|
self.appendEvent(.{ .mouse_leave = {} });
|
||||||
self.appendEvent(.{ .mouse_leave = {} });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -287,13 +309,6 @@ fn PlatformType(App: type) type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e == .mouse_leave and input.mouse_position == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (e == .mouse_enter and input.mouse_position != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.appendEvent(e);
|
self.appendEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user