implement shop
This commit is contained in:
parent
365c7a0163
commit
8d5e7da6a6
@ -2,6 +2,7 @@ const std = @import("std");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const Assets = @import("./assets.zig");
|
const Assets = @import("./assets.zig");
|
||||||
|
const State = @import("./state.zig");
|
||||||
|
|
||||||
const Engine = @import("./engine/root.zig");
|
const Engine = @import("./engine/root.zig");
|
||||||
const Nanoseconds = Engine.Nanoseconds;
|
const Nanoseconds = Engine.Nanoseconds;
|
||||||
@ -40,7 +41,6 @@ const Kinetic = struct {
|
|||||||
|
|
||||||
const Player = struct {
|
const Player = struct {
|
||||||
kinetic: Kinetic = .{},
|
kinetic: Kinetic = .{},
|
||||||
money: u32 = 0,
|
|
||||||
health: u32 = 0,
|
health: u32 = 0,
|
||||||
max_health: u32 = 0,
|
max_health: u32 = 0,
|
||||||
last_shot_at: ?Nanoseconds = null,
|
last_shot_at: ?Nanoseconds = null,
|
||||||
@ -117,7 +117,7 @@ wave_timer: Nanoseconds = 0,
|
|||||||
waves: std.ArrayList(Wave) = .empty,
|
waves: std.ArrayList(Wave) = .empty,
|
||||||
spawned_waves: std.ArrayList(usize) = .empty,
|
spawned_waves: std.ArrayList(usize) = .empty,
|
||||||
|
|
||||||
pub fn init(gpa: Allocator, seed: u64, assets: *Assets) CombatScreen {
|
pub fn init(gpa: Allocator, seed: u64, assets: *Assets, state: State) CombatScreen {
|
||||||
var rng = RNGState.init(seed);
|
var rng = RNGState.init(seed);
|
||||||
|
|
||||||
const next_pickup_spawn_at_s = pickup_spawn_duration_s.random(rng.random());
|
const next_pickup_spawn_at_s = pickup_spawn_duration_s.random(rng.random());
|
||||||
@ -129,10 +129,10 @@ pub fn init(gpa: Allocator, seed: u64, assets: *Assets) CombatScreen {
|
|||||||
.next_pickup_spawn_at = next_pickup_spawn_at,
|
.next_pickup_spawn_at = next_pickup_spawn_at,
|
||||||
.player = .{
|
.player = .{
|
||||||
.kinetic = .{
|
.kinetic = .{
|
||||||
.pos = .init(50, 50),
|
.pos = world_size.divideScalar(2)
|
||||||
},
|
},
|
||||||
.health = 3,
|
.health = state.max_health,
|
||||||
.max_health = 3
|
.max_health = state.max_health,
|
||||||
},
|
},
|
||||||
.rng = rng
|
.rng = rng
|
||||||
};
|
};
|
||||||
@ -197,11 +197,21 @@ pub fn spawnPickup(self: *CombatScreen) !void {
|
|||||||
.pos = pos,
|
.pos = pos,
|
||||||
.kind = .money
|
.kind = .money
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(self: *CombatScreen, frame: *Engine.Frame) !void {
|
const TickResult = struct {
|
||||||
|
player_died: bool,
|
||||||
|
player_finished: bool
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResult {
|
||||||
const dt = frame.deltaTime();
|
const dt = frame.deltaTime();
|
||||||
|
|
||||||
|
var result = TickResult{
|
||||||
|
.player_died = false,
|
||||||
|
.player_finished = false,
|
||||||
|
};
|
||||||
|
|
||||||
self.wave_timer += frame.dt_ns;
|
self.wave_timer += frame.dt_ns;
|
||||||
const wave_timer_s = @divFloor(self.wave_timer, std.time.ns_per_s);
|
const wave_timer_s = @divFloor(self.wave_timer, std.time.ns_per_s);
|
||||||
|
|
||||||
@ -383,7 +393,7 @@ pub fn tick(self: *CombatScreen, frame: *Engine.Frame) !void {
|
|||||||
if (pickup_rect.hasOverlap(self.player.getRect())) {
|
if (pickup_rect.hasOverlap(self.player.getRect())) {
|
||||||
switch (pickup.kind) {
|
switch (pickup.kind) {
|
||||||
.money => {
|
.money => {
|
||||||
self.player.money += 1;
|
state.money += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
destroy = true;
|
destroy = true;
|
||||||
@ -432,8 +442,15 @@ pub fn tick(self: *CombatScreen, frame: *Engine.Frame) !void {
|
|||||||
@mod(wave_timer_s, 60)
|
@mod(wave_timer_s, 60)
|
||||||
});
|
});
|
||||||
|
|
||||||
frame.drawTextFormat(.init(10, 30), text_opts, "{d}", .{ self.player.money });
|
frame.drawTextFormat(.init(10, 30), text_opts, "{d}", .{ state.money });
|
||||||
frame.drawTextFormat(.init(10, 50), text_opts, "{d}/{d}", .{ self.player.health, self.player.max_health });
|
frame.drawTextFormat(.init(10, 50), text_opts, "{d}/{d}", .{ self.player.health, self.player.max_health });
|
||||||
|
|
||||||
|
result.player_died = (self.player.health == 0);
|
||||||
|
if (self.enemies.items.len == 0 and self.waves.items.len == 0 and self.spawned_waves.items.len == wave_infos.len) {
|
||||||
|
result.player_finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getCenteredRect(pos: Vec2, size: f32) Rect {
|
fn getCenteredRect(pos: Vec2, size: f32) Rect {
|
||||||
|
|||||||
@ -30,11 +30,13 @@ pub const Input = struct {
|
|||||||
keyboard: InputSystem.ButtonStateSet(KeyCode),
|
keyboard: InputSystem.ButtonStateSet(KeyCode),
|
||||||
mouse_button: InputSystem.ButtonStateSet(MouseButton),
|
mouse_button: InputSystem.ButtonStateSet(MouseButton),
|
||||||
mouse_position: ?Vec2,
|
mouse_position: ?Vec2,
|
||||||
|
mouse_delta: Vec2,
|
||||||
|
|
||||||
pub const empty = Input{
|
pub const empty = Input{
|
||||||
.keyboard = .empty,
|
.keyboard = .empty,
|
||||||
.mouse_button = .empty,
|
.mouse_button = .empty,
|
||||||
.mouse_position = null,
|
.mouse_position = null,
|
||||||
|
.mouse_delta = .zero,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -87,6 +87,8 @@ pub const Event = union(enum) {
|
|||||||
char: u21,
|
char: u21,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub var mouse_position: ?Vec2 = null;
|
||||||
|
|
||||||
pub fn processEvent(frame: *Frame, event: Event) void {
|
pub fn processEvent(frame: *Frame, event: Event) void {
|
||||||
const input = &frame.input;
|
const input = &frame.input;
|
||||||
|
|
||||||
@ -102,21 +104,21 @@ pub fn processEvent(frame: *Frame, event: Event) void {
|
|||||||
.mouse_leave => {
|
.mouse_leave => {
|
||||||
input.keyboard.releaseAll();
|
input.keyboard.releaseAll();
|
||||||
|
|
||||||
input.mouse_position = null;
|
mouse_position = null;
|
||||||
input.mouse_button = .empty;
|
input.mouse_button = .empty;
|
||||||
},
|
},
|
||||||
.mouse_enter => |pos| {
|
.mouse_enter => |pos| {
|
||||||
input.mouse_position = pos;
|
mouse_position = pos;
|
||||||
},
|
},
|
||||||
.mouse_move => |pos| {
|
.mouse_move => |pos| {
|
||||||
input.mouse_position = pos;
|
mouse_position = pos;
|
||||||
},
|
},
|
||||||
.mouse_pressed => |opts| {
|
.mouse_pressed => |opts| {
|
||||||
input.mouse_position = opts.position;
|
mouse_position = opts.position;
|
||||||
input.mouse_button.press(opts.button, frame.time_ns);
|
input.mouse_button.press(opts.button, frame.time_ns);
|
||||||
},
|
},
|
||||||
.mouse_released => |opts| {
|
.mouse_released => |opts| {
|
||||||
input.mouse_position = opts.position;
|
mouse_position = opts.position;
|
||||||
input.mouse_button.release(opts.button);
|
input.mouse_button.release(opts.button);
|
||||||
},
|
},
|
||||||
else => {}
|
else => {}
|
||||||
|
|||||||
@ -167,16 +167,6 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
|
|
||||||
const screen_size = Vec2.init(sapp.widthf(), sapp.heightf());
|
const screen_size = Vec2.init(sapp.widthf(), sapp.heightf());
|
||||||
|
|
||||||
var revert_mouse_position: ?Vec2 = null;
|
|
||||||
if (self.canvas_size) |canvas_size| {
|
|
||||||
if (self.frame.input.mouse_position) |mouse| {
|
|
||||||
const transform = ScreenScalar.init(screen_size, canvas_size);
|
|
||||||
|
|
||||||
revert_mouse_position = mouse;
|
|
||||||
self.frame.input.mouse_position = mouse.sub(transform.translation).divideScalar(transform.scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
_ = frame.arena.reset(.retain_capacity);
|
_ = frame.arena.reset(.retain_capacity);
|
||||||
const arena = frame.arena.allocator();
|
const arena = frame.arena.allocator();
|
||||||
@ -197,6 +187,20 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
frame.dt_ns = time_passed - self.last_frame_at;
|
frame.dt_ns = time_passed - self.last_frame_at;
|
||||||
frame.hide_cursor = false;
|
frame.hide_cursor = false;
|
||||||
|
|
||||||
|
var mouse_position = Input.mouse_position;
|
||||||
|
if (self.canvas_size) |canvas_size| {
|
||||||
|
if (mouse_position) |mouse| {
|
||||||
|
const transform = ScreenScalar.init(screen_size, canvas_size);
|
||||||
|
|
||||||
|
mouse_position = mouse.sub(transform.translation).divideScalar(transform.scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame.input.mouse_delta = .zero;
|
||||||
|
if (mouse_position != null and frame.input.mouse_position != null) {
|
||||||
|
frame.input.mouse_delta = frame.input.mouse_position.?.sub(mouse_position.?);
|
||||||
|
}
|
||||||
|
frame.input.mouse_position = mouse_position;
|
||||||
|
|
||||||
try self.game.tick(&self.frame);
|
try self.game.tick(&self.frame);
|
||||||
|
|
||||||
frame.input.keyboard.pressed = .initEmpty();
|
frame.input.keyboard.pressed = .initEmpty();
|
||||||
@ -238,10 +242,6 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
for (frame.audio.commands.items) |command| {
|
for (frame.audio.commands.items) |command| {
|
||||||
try Audio.mixer.commands.push(command);
|
try Audio.mixer.commands.push(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (revert_mouse_position) |pos| {
|
|
||||||
self.frame.input.mouse_position = pos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn showDebugWindow(frame: *Frame) !void {
|
fn showDebugWindow(frame: *Frame) !void {
|
||||||
|
|||||||
64
src/game.zig
64
src/game.zig
@ -25,7 +25,9 @@ const Sprite = Engine.Graphics.Sprite;
|
|||||||
|
|
||||||
const RaycastTileIterator = @import("./raycast_tile_iterator.zig");
|
const RaycastTileIterator = @import("./raycast_tile_iterator.zig");
|
||||||
|
|
||||||
|
const State = @import("./state.zig");
|
||||||
const CombatScreen = @import("./combat_screen.zig");
|
const CombatScreen = @import("./combat_screen.zig");
|
||||||
|
const ShopScreen = @import("./shop_screen.zig");
|
||||||
|
|
||||||
const Game = @This();
|
const Game = @This();
|
||||||
const world_size = Vec2.init(20 * 16, 15 * 16);
|
const world_size = Vec2.init(20 * 16, 15 * 16);
|
||||||
@ -35,27 +37,56 @@ const RNGState = std.Random.DefaultPrng;
|
|||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
gpa: Allocator,
|
gpa: Allocator,
|
||||||
assets: *Assets,
|
assets: *Assets,
|
||||||
|
rng: RNGState,
|
||||||
|
|
||||||
|
state: State,
|
||||||
|
|
||||||
combat_screen: CombatScreen,
|
combat_screen: CombatScreen,
|
||||||
|
shop_screen: ShopScreen,
|
||||||
|
|
||||||
|
show_shop: bool = false,
|
||||||
|
|
||||||
pub fn init(gpa: Allocator, seed: u64, assets: *Assets) !Game {
|
pub fn init(gpa: Allocator, seed: u64, assets: *Assets) !Game {
|
||||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
|
|
||||||
|
var rng = RNGState.init(seed);
|
||||||
|
|
||||||
|
var state = State.init();
|
||||||
|
errdefer state.deinit();
|
||||||
|
|
||||||
|
var combat_screen = CombatScreen.init(gpa, rng.next(), assets, state);
|
||||||
|
errdefer combat_screen.deinit();
|
||||||
|
|
||||||
|
var shop_screen = try ShopScreen.init(gpa, assets);
|
||||||
|
errdefer shop_screen.deinit();
|
||||||
|
|
||||||
return Game{
|
return Game{
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
.gpa = gpa,
|
.gpa = gpa,
|
||||||
.assets = assets,
|
.assets = assets,
|
||||||
|
.rng = rng,
|
||||||
|
|
||||||
.combat_screen = .init(gpa, seed, assets),
|
.state = state,
|
||||||
|
|
||||||
|
.combat_screen = combat_screen,
|
||||||
|
.shop_screen = shop_screen,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Game) void {
|
pub fn deinit(self: *Game) void {
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
|
self.state.deinit();
|
||||||
self.combat_screen.deinit();
|
self.combat_screen.deinit();
|
||||||
|
self.shop_screen.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn restartAndShowCombatScreen(self: *Game) !void {
|
||||||
|
self.combat_screen.deinit();
|
||||||
|
self.combat_screen = .init(self.gpa, self.rng.next(), self.assets, self.state);
|
||||||
|
self.show_shop = false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
||||||
if (frame.isKeyPressed(.ESCAPE)) {
|
if (frame.isKeyPressed(.ESCAPE)) {
|
||||||
sapp.requestQuit();
|
sapp.requestQuit();
|
||||||
@ -65,7 +96,22 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
|||||||
frame.show_debug = !frame.show_debug;
|
frame.show_debug = !frame.show_debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.combat_screen.tick(frame);
|
if (frame.isKeyPressed(.F2)) {
|
||||||
|
self.show_shop = !self.show_shop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.show_shop) {
|
||||||
|
const result = try self.shop_screen.tick(&self.state, frame);
|
||||||
|
if (result.back_to_combat) {
|
||||||
|
try self.restartAndShowCombatScreen();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const result = try self.combat_screen.tick(&self.state, frame);
|
||||||
|
|
||||||
|
if (result.player_finished or result.player_died) {
|
||||||
|
self.show_shop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug(self: *Game) !void {
|
pub fn debug(self: *Game) !void {
|
||||||
@ -82,6 +128,20 @@ pub fn debug(self: *Game) !void {
|
|||||||
try self.combat_screen.spawnEnemy();
|
try self.combat_screen.spawnEnemy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (imgui.button("Restart")) {
|
||||||
|
try self.restartAndShowCombatScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.show_shop) {
|
||||||
|
if (imgui.button("Swap to combat")) {
|
||||||
|
self.show_shop = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (imgui.button("Swap to shop")) {
|
||||||
|
self.show_shop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const screen = &self.combat_screen;
|
const screen = &self.combat_screen;
|
||||||
|
|
||||||
const time_left_til_pickup = screen.next_pickup_spawn_at - screen.wave_timer;
|
const time_left_til_pickup = screen.next_pickup_spawn_at - screen.wave_timer;
|
||||||
|
|||||||
181
src/shop_screen.zig
Normal file
181
src/shop_screen.zig
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const State = @import("./state.zig");
|
||||||
|
const Assets = @import("./assets.zig");
|
||||||
|
|
||||||
|
const Engine = @import("./engine/root.zig");
|
||||||
|
const Frame = Engine.Frame;
|
||||||
|
const Vec2 = Engine.Vec2;
|
||||||
|
const Vec4 = Engine.Math.Vec4;
|
||||||
|
const rgb = Engine.Math.rgb;
|
||||||
|
const Rect = Engine.Math.Rect;
|
||||||
|
|
||||||
|
const ShopScreen = @This();
|
||||||
|
|
||||||
|
const canvas_size = Vec2.init(20 * 16, 15 * 16);
|
||||||
|
const canvas_bounds = Rect.init(-200, -200, 400, 400);
|
||||||
|
const node_size = Vec2.init(10, 10);
|
||||||
|
|
||||||
|
const Upgrade = union(enum) {
|
||||||
|
unlock_pistol,
|
||||||
|
increase_health,
|
||||||
|
|
||||||
|
pub fn apply(self: Upgrade, state: *State) void {
|
||||||
|
switch (self) {
|
||||||
|
.unlock_pistol => {
|
||||||
|
state.has_pistol_unlocked = true;
|
||||||
|
},
|
||||||
|
.increase_health => {
|
||||||
|
const max_health: f32 = @floatFromInt(state.max_health);
|
||||||
|
state.max_health = @intFromFloat(max_health * 1.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const UpgradeNode = struct {
|
||||||
|
pos: Vec2,
|
||||||
|
money_cost: u32,
|
||||||
|
upgrade: Upgrade,
|
||||||
|
dependency: ?usize = null,
|
||||||
|
bought: bool = false
|
||||||
|
};
|
||||||
|
|
||||||
|
gpa: Allocator,
|
||||||
|
assets: *Assets,
|
||||||
|
nodes: std.ArrayList(UpgradeNode) = .empty,
|
||||||
|
camera_pos: Vec2 = .zero,
|
||||||
|
|
||||||
|
pub fn init(gpa: Allocator, assets: *Assets) !ShopScreen {
|
||||||
|
var nodes: std.ArrayList(UpgradeNode) = .empty;
|
||||||
|
errdefer nodes.deinit(gpa);
|
||||||
|
|
||||||
|
try nodes.append(gpa, UpgradeNode{
|
||||||
|
.pos = .init(0, 0),
|
||||||
|
.upgrade = .unlock_pistol,
|
||||||
|
.money_cost = 1
|
||||||
|
});
|
||||||
|
|
||||||
|
try nodes.append(gpa, UpgradeNode{
|
||||||
|
.pos = .init(20, 0),
|
||||||
|
.upgrade = .increase_health,
|
||||||
|
.money_cost = 10,
|
||||||
|
.dependency = 0
|
||||||
|
});
|
||||||
|
|
||||||
|
return ShopScreen{
|
||||||
|
.gpa = gpa,
|
||||||
|
.nodes = nodes,
|
||||||
|
.assets = assets
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *ShopScreen) void {
|
||||||
|
self.nodes.deinit(self.gpa);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TickResult = struct {
|
||||||
|
back_to_combat: bool
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn tick(self: *ShopScreen, state: *State, frame: *Frame) !TickResult {
|
||||||
|
frame.graphics.canvas_size = canvas_size;
|
||||||
|
|
||||||
|
var result = TickResult{
|
||||||
|
.back_to_combat = false
|
||||||
|
};
|
||||||
|
|
||||||
|
const camera_offset = self.camera_pos.add(canvas_size.divideScalar(2));
|
||||||
|
var mouse: ?Vec2 = null;
|
||||||
|
if (frame.input.mouse_position) |mouse_position| {
|
||||||
|
mouse = mouse_position.sub(camera_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.drawRectangle(.{
|
||||||
|
.rect = .init(0, 0, canvas_size.x, canvas_size.y),
|
||||||
|
.color = rgb(20, 20, 20)
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
frame.pushTransform(camera_offset, .init(1, 1));
|
||||||
|
defer frame.popTransform();
|
||||||
|
|
||||||
|
frame.drawRectanglOutline(
|
||||||
|
canvas_bounds.pos,
|
||||||
|
canvas_bounds.size,
|
||||||
|
rgb(255, 255, 255),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (frame.isMouseDown(.left)) {
|
||||||
|
self.camera_pos = self.camera_pos.sub(frame.input.mouse_delta);
|
||||||
|
|
||||||
|
self.camera_pos.x = std.math.clamp(
|
||||||
|
self.camera_pos.x - canvas_size.x/2,
|
||||||
|
canvas_bounds.left(),
|
||||||
|
canvas_bounds.right() - canvas_size.x,
|
||||||
|
) + canvas_size.x/2;
|
||||||
|
|
||||||
|
self.camera_pos.y = std.math.clamp(
|
||||||
|
self.camera_pos.y - canvas_size.y/2,
|
||||||
|
canvas_bounds.top(),
|
||||||
|
canvas_bounds.bottom() - canvas_size.y,
|
||||||
|
) + canvas_size.y/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.nodes.items) |node| {
|
||||||
|
if (node.dependency) |dependency_index| {
|
||||||
|
const dependency = self.nodes.items[dependency_index];
|
||||||
|
frame.drawLine(node.pos, dependency.pos, rgb(200, 200, 200), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.nodes.items) |*node| {
|
||||||
|
const node_rect = Rect.initCentered(node.pos.x, node.pos.y, node_size.x, node_size.y);
|
||||||
|
|
||||||
|
const is_mouse_inside = mouse != null and node_rect.isInside(mouse.?);
|
||||||
|
const has_enough_money = state.money >= node.money_cost;
|
||||||
|
|
||||||
|
if (has_enough_money and is_mouse_inside and frame.isMousePressed(.left)) {
|
||||||
|
node.upgrade.apply(state);
|
||||||
|
node.bought = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var color: Vec4 = undefined;
|
||||||
|
if (node.bought) {
|
||||||
|
color = rgb(255, 255, 255);
|
||||||
|
} else if (is_mouse_inside) {
|
||||||
|
if (has_enough_money) {
|
||||||
|
color = rgb(200, 200, 20);
|
||||||
|
} else {
|
||||||
|
color = rgb(200, 20, 20);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
color = rgb(200, 200, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.drawRectangle(.{
|
||||||
|
.rect = node_rect,
|
||||||
|
.color = color
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const text_opts = Engine.Frame.DrawTextOptions{
|
||||||
|
.font = self.assets.font_id.get(.regular)
|
||||||
|
};
|
||||||
|
frame.drawTextFormat(.init(10, 30), text_opts, "Money: {d}", .{ state.money });
|
||||||
|
|
||||||
|
const back_rect = Rect.init(10, 10, 100, 15);
|
||||||
|
frame.drawRectangle(.{
|
||||||
|
.rect = back_rect,
|
||||||
|
.color = rgb(255, 255, 255)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (frame.input.mouse_position != null and back_rect.isInside(frame.input.mouse_position.?) and frame.isMousePressed(.left)) {
|
||||||
|
result.back_to_combat = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
15
src/state.zig
Normal file
15
src/state.zig
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const State = @This();
|
||||||
|
|
||||||
|
money: u32 = 0,
|
||||||
|
|
||||||
|
max_health: u32 = 3,
|
||||||
|
has_pistol_unlocked: bool = false,
|
||||||
|
|
||||||
|
pub fn init() State {
|
||||||
|
return State{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *State) void {
|
||||||
|
_ = self; // autofix
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user