pause menu progress
This commit is contained in:
parent
dbae325cdb
commit
05698200d2
BIN
assets/kenney-ui/Font/Kenney Future Narrow.ttf
Normal file
BIN
assets/kenney-ui/Font/Kenney Future Narrow.ttf
Normal file
Binary file not shown.
22
assets/kenney-ui/License.txt
Normal file
22
assets/kenney-ui/License.txt
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
|
||||
UI Pack (2.0)
|
||||
|
||||
Created/distributed by Kenney (www.kenney.nl)
|
||||
Creation date: 12-06-2024
|
||||
|
||||
------------------------------
|
||||
|
||||
License: (Creative Commons Zero, CC0)
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
This content is free to use in personal, educational and commercial projects.
|
||||
Support us by crediting Kenney or www.kenney.nl (this is not mandatory)
|
||||
|
||||
------------------------------
|
||||
|
||||
Donate: http://support.kenney.nl
|
||||
Patreon: http://patreon.com/kenney/
|
||||
|
||||
Follow on Twitter for updates:
|
||||
http://twitter.com/KenneyNL
|
||||
@ -1,93 +0,0 @@
|
||||
Copyright 2011 The Roboto Project Authors (https://github.com/googlefonts/roboto-classic)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -145,7 +145,7 @@ fn buildProject(ctx: Context, target: Build.ResolvedTarget, optimize: std.builti
|
||||
const asset_files = [_][]const u8{
|
||||
"sokoban/sokoban_tilesheet.png",
|
||||
"sokoban/sokoban_tilesheet@2.png",
|
||||
"roboto-font/Roboto-Regular.ttf",
|
||||
"kenney-ui/Font/Kenney Future Narrow.ttf",
|
||||
"tiled/map.tmx",
|
||||
"tiled/tileset.tsx",
|
||||
"impact-sounds/footstep_concrete_000.ogg"
|
||||
|
||||
94
src/app.zig
94
src/app.zig
@ -334,14 +334,6 @@ const BoxSprites = struct {
|
||||
};
|
||||
};
|
||||
|
||||
const GameScene = struct {
|
||||
world: World,
|
||||
undo_stack: std.ArrayList(UndoFrame) = .empty,
|
||||
current_level: u32 = 0,
|
||||
animation_timer: Platform.Nanoseconds = 0,
|
||||
paused: bool = false,
|
||||
};
|
||||
|
||||
levels: std.ArrayList(World),
|
||||
|
||||
roboto_font: Font,
|
||||
@ -355,15 +347,20 @@ footstep_sound: Audio.SoundId = .nil,
|
||||
|
||||
sfx_bus: Audio.BusId,
|
||||
|
||||
game_scene: GameScene,
|
||||
in_main_menu: bool = true,
|
||||
main_menu_state: UI.State = .empty,
|
||||
ui_state: UI.State = .empty,
|
||||
|
||||
world: World,
|
||||
undo_stack: std.ArrayList(UndoFrame) = .empty,
|
||||
current_level: u32 = 0,
|
||||
animation_timer: Platform.Nanoseconds = 0,
|
||||
menu_shown: bool = false,
|
||||
|
||||
pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
||||
const roboto_font = try Font.init(plt.gpa, .{
|
||||
var roboto_font = try Font.init(plt.gpa, .{
|
||||
.spritesheet = Gfx.initSpritesheet(.{ .format = .r8 }),
|
||||
.ttf_data = plt.assets.readFile("roboto-font/Roboto-Regular.ttf")
|
||||
.ttf_data = plt.assets.readFile("kenney-ui/Font/Kenney Future Narrow.ttf")
|
||||
});
|
||||
roboto_font.prepareASCII(80);
|
||||
|
||||
const tilesheet1_png = try STBImage.load(plt.assets.readFile("sokoban/sokoban_tilesheet.png"));
|
||||
const tilesheet2_png = try STBImage.load(plt.assets.readFile("sokoban/sokoban_tilesheet@2.png"));
|
||||
@ -452,13 +449,11 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
||||
.sfx_bus = Audio.addBus(.{ .label = "sfx" }),
|
||||
.levels = .empty,
|
||||
|
||||
.game_scene = .{
|
||||
.world = undefined,
|
||||
}
|
||||
};
|
||||
|
||||
self.levels = try self.loadLevels(plt.gpa, plt.assets);
|
||||
self.game_scene.world.copy(self.levels.items[0]);
|
||||
self.world.copy(self.levels.items[0]);
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -703,29 +698,29 @@ pub fn drawWorld(self: *App, world: *World) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frameGameScene(self: *App, plt: *Platform.Frame) !void {
|
||||
pub fn frame(self: *App, plt: *Platform.Frame) !void {
|
||||
Gfx.setClearColor(clear_color);
|
||||
Gfx.setDefaultSampler(.linear);
|
||||
|
||||
const dt = plt.deltaTime();
|
||||
|
||||
if (plt.input.isKeyPressed(.ESCAPE)) {
|
||||
self.game_scene.paused = !self.game_scene.paused;
|
||||
self.menu_shown = !self.menu_shown;
|
||||
}
|
||||
|
||||
var world = &self.game_scene.world;
|
||||
var world = &self.world;
|
||||
|
||||
if (!self.game_scene.paused) {
|
||||
if (!self.menu_shown) {
|
||||
const input = getPlayerInput(plt.input);
|
||||
|
||||
if (input.undo) {
|
||||
if (self.game_scene.undo_stack.pop()) |undo_frame| {
|
||||
if (self.undo_stack.pop()) |undo_frame| {
|
||||
undo_frame.apply(world);
|
||||
}
|
||||
}
|
||||
|
||||
if (input.restart) {
|
||||
self.setWorldByLevel(self.game_scene.current_level);
|
||||
self.setWorldByLevel(self.current_level);
|
||||
}
|
||||
|
||||
var tick_context: TickContext = .{ .world = world };
|
||||
@ -764,14 +759,14 @@ pub fn frameGameScene(self: *App, plt: *Platform.Frame) !void {
|
||||
const frames = self.player_sprites.getDirection(entity.player_direction);
|
||||
|
||||
if (target_visual_pos.sub(entity.visual_pos).length() > 0.1) {
|
||||
self.game_scene.animation_timer += plt.input.delta_time;
|
||||
self.animation_timer += plt.input.delta_time;
|
||||
const animatin_time = std.time.ns_per_s / 5;
|
||||
while (self.game_scene.animation_timer >= animatin_time) {
|
||||
while (self.animation_timer >= animatin_time) {
|
||||
entity.player_frame_index = (entity.player_frame_index + 1) % @as(u32, @intCast(frames.len));
|
||||
self.game_scene.animation_timer -= animatin_time;
|
||||
self.animation_timer -= animatin_time;
|
||||
}
|
||||
} else {
|
||||
self.game_scene.animation_timer = 0;
|
||||
self.animation_timer = 0;
|
||||
entity.player_frame_index = 0;
|
||||
}
|
||||
}
|
||||
@ -779,7 +774,7 @@ pub fn frameGameScene(self: *App, plt: *Platform.Frame) !void {
|
||||
}
|
||||
|
||||
if (!tick_context.undo_frame.isEmpty()) {
|
||||
try self.game_scene.undo_stack.append(plt.gpa, tick_context.undo_frame);
|
||||
try self.undo_stack.append(plt.gpa, tick_context.undo_frame);
|
||||
}
|
||||
|
||||
{
|
||||
@ -804,9 +799,9 @@ pub fn frameGameScene(self: *App, plt: *Platform.Frame) !void {
|
||||
}
|
||||
}
|
||||
|
||||
if (goal_count > 0 and goal_count == box_at_goal_count and self.game_scene.current_level+1 < self.levels.items.len) {
|
||||
self.game_scene.current_level += 1;
|
||||
self.setWorldByLevel(self.game_scene.current_level);
|
||||
if (goal_count > 0 and goal_count == box_at_goal_count and self.current_level+1 < self.levels.items.len) {
|
||||
self.current_level += 1;
|
||||
self.setWorldByLevel(self.current_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -818,27 +813,23 @@ pub fn frameGameScene(self: *App, plt: *Platform.Frame) !void {
|
||||
canvas.push();
|
||||
defer canvas.pop(clear_color);
|
||||
|
||||
try self.drawWorld(&self.game_scene.world);
|
||||
try self.drawWorld(world);
|
||||
|
||||
if (self.game_scene.paused) {
|
||||
if (self.menu_shown) {
|
||||
var color = clear_color;
|
||||
color.a = 0.8;
|
||||
Gfx.drawRectangle(.init(0, 0), canvas.size, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frameMainMenu(self: *App, plt: *Platform.Frame) !void {
|
||||
Gfx.setClearColor(clear_color);
|
||||
Gfx.setDefaultSampler(.linear);
|
||||
|
||||
if (self.menu_shown) {
|
||||
var canvas = CanvasScaler{
|
||||
.size = Vec2.initFromInt(usize, 1920, 1080)
|
||||
};
|
||||
canvas.push();
|
||||
defer canvas.pop(clear_color);
|
||||
defer canvas.pop(null);
|
||||
|
||||
var ui = UI.init(&self.main_menu_state, plt.input);
|
||||
var ui = UI.init(&self.ui_state, plt.input);
|
||||
ui.beginFrame();
|
||||
defer ui.endFrame();
|
||||
|
||||
@ -850,13 +841,17 @@ pub fn frameMainMenu(self: *App, plt: *Platform.Frame) !void {
|
||||
ui_frame.container = Rect{ .pos = .init(0, 0), .size = canvas.size };
|
||||
ui_frame.container = ui_frame.container.shrinkPercent(0.1);
|
||||
|
||||
ui_frame.padding.addHorizontal(100);
|
||||
ui_frame.padding.addVertical(50);
|
||||
ui_frame.padding.addHorizontal(150);
|
||||
ui_frame.padding.addVertical(80);
|
||||
|
||||
var layout = UI.VerticalLayout{ .ui = &ui, .gap = 30 };
|
||||
|
||||
if (layout.textButton("Play")) {
|
||||
log.debug("press play", .{});
|
||||
if (layout.textButton("Continue")) {
|
||||
self.menu_shown = false;
|
||||
}
|
||||
|
||||
if (layout.textButton("Level select")) {
|
||||
self.menu_shown = false;
|
||||
}
|
||||
|
||||
if (layout.textButton("Settings")) {
|
||||
@ -868,18 +863,11 @@ pub fn frameMainMenu(self: *App, plt: *Platform.Frame) !void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame(self: *App, plt: *Platform.Frame) !void {
|
||||
if (self.in_main_menu) {
|
||||
try self.frameMainMenu(plt);
|
||||
} else {
|
||||
try self.frameGameScene(plt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setWorldByLevel(self: *App, index: u32) void {
|
||||
self.game_scene.world.copy(self.levels.items[index]);
|
||||
self.game_scene.undo_stack.clearRetainingCapacity();
|
||||
self.world.copy(self.levels.items[index]);
|
||||
self.undo_stack.clearRetainingCapacity();
|
||||
}
|
||||
|
||||
pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
||||
@ -887,5 +875,5 @@ pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
||||
Gfx.deinitSpritesheet(self.roboto_font.spritesheet);
|
||||
|
||||
self.levels.deinit(plt.gpa);
|
||||
self.game_scene.undo_stack.deinit(plt.gpa);
|
||||
self.undo_stack.deinit(plt.gpa);
|
||||
}
|
||||
|
||||
@ -36,9 +36,10 @@ pub fn push(self: Canvas) void {
|
||||
Gfx.transformScale(.init(scale, scale));
|
||||
}
|
||||
|
||||
pub fn pop(self: Canvas, color: Color) void {
|
||||
pub fn pop(self: Canvas, maybe_color: ?Color) void {
|
||||
Gfx.transformPop();
|
||||
|
||||
if (maybe_color) |color| {
|
||||
const scale = self.getScale();
|
||||
const window_size = Gfx.getWindowSize();
|
||||
const scaled_canvas = self.size.multiplyScalar(scale);
|
||||
@ -68,3 +69,4 @@ pub fn pop(self: Canvas, color: Color) void {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
src/font.zig
22
src/font.zig
@ -46,6 +46,22 @@ pub fn deinit(self: *Font, gpa: Allocator) void {
|
||||
self.cache.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn prepareASCII(font: *Font, height: f32) void {
|
||||
font.prepareGlyphs(height, 32, 127);
|
||||
}
|
||||
|
||||
pub fn prepareGlyphs(font: *Font, height: f32, first_codepoint: u21, last_codepoint: u21) void {
|
||||
const scale = font.stb.scaleForPixelHeight(height);
|
||||
const scale_x = scale;
|
||||
const scale_y = scale;
|
||||
|
||||
for (first_codepoint..last_codepoint) |i| {
|
||||
const codepoint: u21 = @intCast(i);
|
||||
const glyph_index = font.getGlyphIndex(codepoint) orelse continue;
|
||||
_ = font.getGlyph(glyph_index, scale_x, scale_y);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getGlyphIndex(font: *Font, codepoint: u21) ?Glyph.Index {
|
||||
if (font.stb.findGlyphIndex(codepoint)) |index| {
|
||||
return index;
|
||||
@ -126,6 +142,12 @@ pub fn getAscent(font: *Font, height: f32) f32 {
|
||||
return @as(f32, @floatFromInt(vmetrics.ascent)) * scale;
|
||||
}
|
||||
|
||||
pub fn getDescent(font: *Font, height: f32) f32 {
|
||||
const vmetrics = font.stb.getFontVMetrics();
|
||||
const scale = font.stb.scaleForPixelHeight(height);
|
||||
return @as(f32, @floatFromInt(vmetrics.descent)) * scale;
|
||||
}
|
||||
|
||||
pub fn getAscentDescent(font: *Font, height: f32) f32 {
|
||||
const vmetrics = font.stb.getFontVMetrics();
|
||||
const scale = font.stb.scaleForPixelHeight(height);
|
||||
|
||||
@ -753,9 +753,7 @@ pub fn setTexture(id: Texture.Id, opts: SetTextureOptions) void {
|
||||
texture.image = new_image;
|
||||
texture.updated_at = null;
|
||||
|
||||
log.debug("is dynamic {f}, {}", .{id, texture.dynamic});
|
||||
if (texture.dynamic) {
|
||||
log.debug("update texture {f}", .{id});
|
||||
sg.updateImage(new_image, image_data);
|
||||
texture.updated_at = self.frame.index;
|
||||
}
|
||||
|
||||
@ -78,7 +78,10 @@ pub const VerticalLayout = struct {
|
||||
const frame = self.ui.top();
|
||||
const font = frame.font orelse return false;
|
||||
|
||||
var button_size = font.measureText(text, frame.text_height).size;
|
||||
var button_size = Vec2{
|
||||
.x = font.measureText(text, frame.text_height).size.x,
|
||||
.y = font.getAscent(frame.text_height)
|
||||
};
|
||||
button_size = button_size.add(frame.padding.toVec2());
|
||||
|
||||
const row_rect = self.next(button_size.y);
|
||||
@ -319,9 +322,7 @@ pub fn textButton(self: *UI, rect: Rect, text: []const u8) bool {
|
||||
Gfx.drawRectangle(rect.pos, rect.size, .white);
|
||||
}
|
||||
|
||||
var content_size = rect.size.sub(frame.padding.toVec2());
|
||||
content_size.x = @max(content_size.x, 0);
|
||||
content_size.y = @max(content_size.y, 0);
|
||||
const content_size = rect.size.sub(frame.padding.toVec2());
|
||||
|
||||
self.drawText(
|
||||
rect.pos
|
||||
|
||||
Loading…
Reference in New Issue
Block a user