From a488218d0e932af0e3d71965d54dc3e9a4a2493a Mon Sep 17 00:00:00 2001 From: Daniel Hill <9439488+blazkowolf@users.noreply.github.com> Date: Sun, 14 Apr 2024 14:26:29 -0400 Subject: [PATCH] feat(examples): `core/basic_screen_manager` & `core/window_flags` (#78) * feat(examples): add `core/basic_screen_manager` * feat(examples): add WIP `core/window_flags` * fix(examples): get `core/window_flags` working correctly --- build.zig | 10 + examples/core/basic_screen_manager.zig | 172 ++++++++++++++ examples/core/window_flags.zig | 311 +++++++++++++++++++++++++ 3 files changed, 493 insertions(+) create mode 100644 examples/core/basic_screen_manager.zig create mode 100644 examples/core/window_flags.zig diff --git a/build.zig b/build.zig index 89e6cda..5529204 100755 --- a/build.zig +++ b/build.zig @@ -117,6 +117,11 @@ pub fn build(b: *std.Build) !void { const optimize = b.standardOptimizeOption(.{}); const examples = [_]Program{ + .{ + .name = "basic_screen_manager", + .path = "examples/core/basic_screen_manager.zig", + .desc = "Illustrates simple screen manager based on a state machine", + }, .{ .name = "basic_window", .path = "examples/core/basic_window.zig", @@ -152,6 +157,11 @@ pub fn build(b: *std.Build) !void { .path = "examples/core/3d_camera_first_person.zig", .desc = "Simple first person demo", }, + .{ + .name = "window_flags", + .path = "examples/core/window_flags.zig", + .desc = "Demonstrates various flags used during and after window creation", + }, .{ .name = "texture_outline", .path = "examples/shaders/texture_outline.zig", diff --git a/examples/core/basic_screen_manager.zig b/examples/core/basic_screen_manager.zig new file mode 100644 index 0000000..1bef7f6 --- /dev/null +++ b/examples/core/basic_screen_manager.zig @@ -0,0 +1,172 @@ +//! # raylib-zig [core] examples - basic screen manager +//! +//! NOTE: This example illustrates a very simple screen manager based on a +//! states machines +//! +//! Example originally created with raylib-zig 5.0, last time updated with +//! raylib-zig 5.0 +//! +//! Copyright (c) Nikolas Wipper 2024 + +const rl = @import("raylib"); + +const screen_width = 800; +const screen_height = 450; + +/// Valid game states used in the state machine +const GameScreen = enum { + logo, + title, + gameplay, + ending, +}; + +pub fn main() anyerror!void { + // Initialization + // ------------------------------------------------------------------------- + rl.initWindow( + screen_width, + screen_height, + "raylib-zig [core] example - basic screen height", + ); + defer rl.closeWindow(); // Close window and OpenGL context + + // TODO: Initialize all required variables and load all required data here! + + var current_screen: GameScreen = .logo; + + var frames_counter: i32 = 0; // Useful to count frames + + rl.setTargetFPS(60); // Set desired framerate + + // Main game loop + while (!rl.windowShouldClose()) { // Detect window close button or ESC key + // Update + // --------------------------------------------------------------------- + switch (current_screen) { + .logo => { + // TODO: Update `logo` state variables here! + + frames_counter += 1; // Count frames + + // Wait for 2 seconds (120 frames) before jumping to `title` screen + if (frames_counter > 120) current_screen = .title; + }, + .title => { + // TODO: Update `title` state variables here! + + // Press ENTER to change to `gameplay` state + if (rl.isKeyPressed(.key_enter) or rl.isGestureDetected(.gesture_tap)) { + current_screen = .gameplay; + } + }, + .gameplay => { + // TODO: Update `gameplay` state variables here! + + // Press ENTER to change to `ending` state + if (rl.isKeyPressed(.key_enter) or rl.isGestureDetected(.gesture_tap)) { + current_screen = .ending; + } + }, + .ending => { + // TODO: Update `ending` state variables here! + + // Press ENTER to return to `title` state + if (rl.isKeyPressed(.key_enter) or rl.isGestureDetected(.gesture_tap)) { + current_screen = .title; + } + }, + } + // --------------------------------------------------------------------- + + // Draw + // --------------------------------------------------------------------- + { + rl.beginDrawing(); + defer rl.endDrawing(); + + rl.clearBackground(rl.Color.ray_white); + + switch (current_screen) { + .logo => { + // TODO: Draw `logo` state here! + rl.drawText("LOGO SCREEN", 20, 20, 40, rl.Color.light_gray); + rl.drawText( + "WAIT for 2 SECONDS...", + 290, + 220, + 20, + rl.Color.gray, + ); + }, + .title => { + // TODO: Draw `title` state here! + rl.drawRectangle( + 0, + 0, + screen_width, + screen_height, + rl.Color.green, + ); + rl.drawText( + "TITLE SCREEN", + 20, + 20, + 40, + rl.Color.dark_green, + ); + rl.drawText( + "PRESS ENTER or TAP to JUMP to GAMEPLAY SCREEN", + 120, + 220, + 20, + rl.Color.dark_green, + ); + }, + .gameplay => { + // TODO: Draw `gameplay` state here! + rl.drawRectangle( + 0, + 0, + screen_width, + screen_height, + rl.Color.purple, + ); + rl.drawText("GAMEPLAY SCREEN", 20, 20, 40, rl.Color.maroon); + rl.drawText( + "PRESS ENTER or TAP to JUMP to ENDING SCREEN", + 130, + 220, + 20, + rl.Color.maroon, + ); + }, + .ending => { + // TODO: Draw `ending` state here! + rl.drawRectangle( + 0, + 0, + screen_width, + screen_height, + rl.Color.blue, + ); + rl.drawText( + "ENDING SCREEN", + 20, + 20, + 40, + rl.Color.dark_blue, + ); + rl.drawText( + "PRESS ENTER or TAP to RETURN to TITLE SCREEN", + 120, + 220, + 20, + rl.Color.dark_blue, + ); + }, + } + } + // --------------------------------------------------------------------- + } +} diff --git a/examples/core/window_flags.zig b/examples/core/window_flags.zig new file mode 100644 index 0000000..7be231f --- /dev/null +++ b/examples/core/window_flags.zig @@ -0,0 +1,311 @@ +//! # raylib-zig [core] example - window flags +//! +//! Example originally created with raylib-zig 5.0, last time updated with +//! raylib-zig 5.0 +//! +//! Example licensed under an unmodified zlib/libpng license, which is an +//! OSI-certified, BSD-like license that allows static linking with closed +//! source software +//! +//! Copyright (c) Nikolas Wipper 2024 + +const rl = @import("raylib"); +const rlm = @import("raylib-math"); + +const screen_width = 800; +const screen_height = 450; + +pub fn main() anyerror!void { + // Initialization + // ------------------------------------------------------------------------- + + // Possible window flags + // flag_vsync_hint + // flag_fullscreen_mode -> not working properly -> wrong scaling! + // flag_window_resizable + // flag_window_undecorated + // flag_window_transparent + // flag_window_hidden + // flag_window_minimized -> Not supported on window creation + // flag_window_maximized -> Not supported on window creation + // flag_window_unfocused + // flag_window_topmost + // flag_window_highdpi -> errors after minimize-resize, fb size is recalculated + // flag_window_always_run + // flag_msaa_4x_hint + + // Set configuration flags for window creation + // rl.setConfigFlags( + // @enumFromInt(@intFromEnum(rl.ConfigFlags.flag_vsync_hint) | @intFromEnum(rl.ConfigFlags.flag_msaa_4x_hint) | @intFromEnum(rl.ConfigFlags.flag_window_highdpi)), + // ); + rl.initWindow( + screen_width, + screen_height, + "raylib-zig [core] example - window flags", + ); + defer rl.closeWindow(); // Close window and OpenGL context + + var ball_position = rl.Vector2.init( + @floatFromInt(@divFloor(rl.getScreenWidth(), 2)), + @floatFromInt(@divFloor(rl.getScreenHeight(), 2)), + ); + var ball_speed = rl.Vector2.init(5, 4); + const ball_radius: f32 = 20; + + var frames_counter: i32 = 0; + + rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second + + while (!rl.windowShouldClose()) { + // Update + // --------------------------------------------------------------------- + if (rl.isKeyPressed(.key_f)) rl.toggleFullscreen(); // Modifies window size when scaling! + + if (rl.isKeyPressed(.key_r)) { + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_resizable))) { + rl.clearWindowState(.flag_window_resizable); + } else { + rl.setWindowState(.flag_window_resizable); + } + } + + if (rl.isKeyPressed(.key_d)) { + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_undecorated))) { + rl.clearWindowState(.flag_window_undecorated); + } else { + rl.setWindowState(.flag_window_undecorated); + } + } + + if (rl.isKeyPressed(.key_h)) { + if (!rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_hidden))) { + rl.setWindowState(.flag_window_hidden); + } + frames_counter = 0; + } + + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_hidden))) { + frames_counter += 1; + if (frames_counter >= 240) rl.clearWindowState(.flag_window_hidden); // Show window after 3 seconds + } + + if (rl.isKeyPressed(.key_n)) { + if (!rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_minimized))) { + rl.minimizeWindow(); + } + frames_counter = 0; + } + + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_minimized))) { + frames_counter += 1; + if (frames_counter >= 240) rl.restoreWindow(); // Restore window after 3 seconds + } + + if (rl.isKeyPressed(.key_m)) { + // NOTE: Requires `flag_window_resizable` enabled! + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_maximized))) { + rl.restoreWindow(); + } else rl.maximizeWindow(); + } + + if (rl.isKeyPressed(.key_u)) { + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_unfocused))) { + rl.clearWindowState(.flag_window_unfocused); + } else rl.setWindowState(.flag_window_unfocused); + } + + if (rl.isKeyPressed(.key_t)) { + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_topmost))) { + rl.clearWindowState(.flag_window_topmost); + } else rl.setWindowState(.flag_window_topmost); + } + + if (rl.isKeyPressed(.key_a)) { + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_always_run))) { + rl.clearWindowState(.flag_window_always_run); + } else rl.setWindowState(.flag_window_always_run); + } + + if (rl.isKeyPressed(.key_v)) { + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_vsync_hint))) { + rl.clearWindowState(.flag_vsync_hint); + } else rl.setWindowState(.flag_vsync_hint); + } + + // Bouncing ball logic + ball_position = rlm.vector2Add(ball_position, ball_speed); + + if (ball_position.x >= (@as(f32, @floatFromInt(rl.getScreenWidth())) - ball_radius) or ball_position.x <= ball_radius) { + ball_speed.x *= -1; + } + if (ball_position.y >= (@as(f32, @floatFromInt(rl.getScreenHeight())) - ball_radius) or ball_position.y <= ball_radius) { + ball_speed.y *= -1; + } + // --------------------------------------------------------------------- + + // Draw + // --------------------------------------------------------------------- + { + rl.beginDrawing(); + defer rl.endDrawing(); + + if (rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_transparent))) { + rl.clearBackground(rl.Color.blank); + } else rl.clearBackground(rl.Color.ray_white); + + rl.drawCircleV(ball_position, ball_radius, rl.Color.maroon); + rl.drawRectangleLinesEx( + rl.Rectangle.init(0, 0, @floatFromInt(rl.getScreenWidth()), @floatFromInt(rl.getScreenHeight())), + 4, + rl.Color.ray_white, + ); + + rl.drawCircleV(rl.getMousePosition(), 10, rl.Color.dark_blue); + + rl.drawFPS(10, 10); + + rl.drawText( + rl.textFormat("Screen Size: [%i, %i]", .{ rl.getScreenWidth(), rl.getScreenHeight() }), + 10, + 40, + 10, + rl.Color.green, + ); + + // Draw window state info + rl.drawText( + "Following flags can be set after window creation:", + 10, + 60, + 10, + rl.Color.gray, + ); + rl.drawText( + rl.textFormat("[F] flag_fullscreen_mode: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_fullscreen_mode)))), + }), + 10, + 80, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("[R] flag_window_resizable: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_resizable)))), + }), + 10, + 100, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("[D] flag_window_undecorated: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_undecorated)))), + }), + 10, + 120, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("[H] flag_window_hidden: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_hidden)))), + }), + 10, + 140, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("[N] flag_window_minimized: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_minimized)))), + }), + 10, + 160, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("[M] flag_window_maximized: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_maximized)))), + }), + 10, + 180, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("[U] flag_window_unfocused: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_unfocused)))), + }), + 10, + 200, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("[T] flag_window_topmost: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_topmost)))), + }), + 10, + 220, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("[A] flag_window_always_run: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_always_run)))), + }), + 10, + 240, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("[V] flag_vsync_hint: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_vsync_hint)))), + }), + 10, + 260, + 10, + rl.Color.lime, + ); + + rl.drawText( + "Following flags can only be set before window creation:", + 10, + 300, + 10, + rl.Color.gray, + ); + rl.drawText( + rl.textFormat("flag_window_highdpi: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_highdpi)))), + }), + 10, + 320, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("flag_window_transparent: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_window_transparent)))), + }), + 10, + 340, + 10, + rl.Color.lime, + ); + rl.drawText( + rl.textFormat("flag_msaa_4x_hint: %d", .{ + @as(i32, @intFromBool(rl.isWindowState(@intFromEnum(rl.ConfigFlags.flag_msaa_4x_hint)))), + }), + 10, + 360, + 10, + rl.Color.lime, + ); + } + // --------------------------------------------------------------------- + } +}