Consolidated scenes for neatness.

This commit is contained in:
2026-09-15 05:41:25 +02:00
parent fb1702190d
commit 0000ca4f12
2 changed files with 131 additions and 89 deletions
+113 -76
View File
@@ -3,98 +3,135 @@ package game
import rl "vendor:raylib"
// ------------------------------------------------------------------------------
// Scene & Overlay Definitions
// Scene Definitions
// ------------------------------------------------------------------------------
Scene_Gameplay :: struct {
level: Level,
Scene_Type :: enum {
Main_Menu,
Gameplay,
Pause_Menu,
Game_Over,
}
Scene_Menu :: struct {
// @todo: ui_canvas layout state
}
Scene_PauseMenu :: struct {
// @todo: pause option state
}
Scene :: union {
Scene_Menu,
Scene_Gameplay,
}
Overlay_Scene :: union {
Scene_PauseMenu,
Scene :: struct {
type: Scene_Type,
level: Maybe(Level),
canvas: Maybe(UI_Canvas),
winner_is_player: bool, // Store win state for rendering
}
// ------------------------------------------------------------------------------
// Base Scene Dispatchers
// UI Definitions
// ------------------------------------------------------------------------------
scene_update :: proc(game: ^Game, input: Input_Event, dt: f32) {
switch &s in game.scene {
case Scene_Menu: // update_menu(&s, game, input, dt)
case Scene_Gameplay: update_gameplay(&s, game, input, dt)
}
}
scene_render :: proc(game: ^Game) {
switch &s in game.scene {
case Scene_Menu: // render_menu(s)
case Scene_Gameplay: render_gameplay(s)
}
UI_Canvas :: struct {
bounds: rl.Rectangle,
padding: f32,
item_height: f32,
item_spaceing: f32,
}
// ------------------------------------------------------------------------------
// Overlay Scene Dispatchers
// Scene Constructors
// ------------------------------------------------------------------------------
overlay_update :: proc(game: ^Game, input: Input_Event, dt: f32) -> bool {
overlay := game.overlay_scene.? or_return
switch &o in overlay {
case Scene_PauseMenu:
if input.pause_pressed {
game.overlay_scene = nil
return true
}
// @todo: handle overlay menu option selection (resume, settings, quit)
}
return true
}
overlay_render :: proc(game: ^Game) -> bool {
overlay := game.overlay_scene.? or_return
switch &o in overlay {
case Scene_PauseMenu:
// Translucent dark tint across virtual canvas space
rl.DrawRectangleRec(rl.Rectangle{0, 0, VIEWPORT_W, VIEWPORT_H}, rl.Color{0, 0, 0, 140})
// Pause Menu UI elements
rl.DrawText("PAUSED", VIEWPORT_W / 2 - 80, VIEWPORT_H / 2 - 40, 40, rl.WHITE)
rl.DrawText("Press Q to Quit to Menu", VIEWPORT_W / 2 - 110, VIEWPORT_H / 2 + 10, 20, rl.LIGHTGRAY)
}
return true
}
// ------------------------------------------------------------------------------
// Gameplay Scene Procedures
// ------------------------------------------------------------------------------
init_gameplay_scene :: proc() -> Scene_Gameplay {
return Scene_Gameplay{
make_gameplay_scene :: proc() -> Scene {
return Scene{
type = .Gameplay,
level = init_level(),
}
}
update_gameplay :: proc(scene: ^Scene_Gameplay, game: ^Game, input: Input_Event, dt: f32) {
if input.pause_pressed {
game.overlay_scene = Scene_PauseMenu{}
return
make_pause_overlay :: proc() -> Scene {
return Scene{
type = .Pause_Menu,
canvas = UI_Canvas{},
}
update_level(&scene.level, input, dt)
}
render_gameplay :: proc(scene: Scene_Gameplay) {
render_level(scene.level)
render_hud(scene.level)
make_main_menu :: proc() -> Scene {
return Scene{
type = .Main_Menu,
canvas = UI_Canvas{},
}
}
make_game_over_overlay :: proc(winner_is_player: bool) -> Scene {
return Scene{
type = .Game_Over,
canvas = UI_Canvas{},
winner_is_player = winner_is_player,
}
}
// ------------------------------------------------------------------------------
// Unified Scene Dispatchers
// ------------------------------------------------------------------------------
scene_update :: proc(scene: ^Scene, game: ^Game, input: Input_Event, dt: f32) {
// mutate level state through pointer if level exists
if level, ok := &scene.level.?; ok {
update_level(level, input, dt)
}
// dispatch scene behavior
#partial switch scene.type {
case .Gameplay:
if input.pause_pressed {
game.overlay_scene = make_pause_overlay()
}
case .Pause_Menu:
if input.pause_pressed {
game.overlay_scene = nil
}
case .Game_Over:
if input.pause_pressed { // Press P or your start key to restart
game.overlay_scene = nil
game.scene = make_gameplay_scene() // Reset the base level
}
case .Main_Menu:
// @todo: handle menu selection / start game
}
// Loop over global frame events
for event in GLOBAL_EVENTS {
#partial switch event.type {
case .Game_Over:
game.overlay_scene = make_game_over_overlay(event.winner_is_player)
}
}
}
scene_render :: proc(scene: ^Scene) {
// render gameplay field & hud if present
if level, ok := scene.level.?; ok {
render_level(level)
render_hud(level)
}
// render scene/overlay ui elements
#partial switch scene.type {
case .Pause_Menu:
rl.DrawRectangleRec(
rl.Rectangle{0, 0, f32(VIEWPORT_W), f32(VIEWPORT_H)},
rl.Color{0, 0, 0, 140},
)
rl.DrawText("PAUSED", VIEWPORT_W / 2 - 80, VIEWPORT_H / 2 - 40, 40, rl.WHITE)
rl.DrawText("Press P to Resume", VIEWPORT_W / 2 - 90, VIEWPORT_H / 2 + 10, 20, rl.LIGHTGRAY)
case .Game_Over:
rl.DrawRectangleRec(
rl.Rectangle{0, 0, f32(VIEWPORT_W), f32(VIEWPORT_H)},
rl.Color{0, 0, 0, 200},
)
msg :cstring = scene.winner_is_player ? "YOU WIN!" : "GAME OVER"
text_color := scene.winner_is_player ? rl.GREEN : rl.RED
rl.DrawText(msg, VIEWPORT_W / 2 - 100, VIEWPORT_H / 2 - 40, 40, text_color)
rl.DrawText("Press P to Play Again", VIEWPORT_W / 2 - 110, VIEWPORT_H / 2 + 10, 20, rl.LIGHTGRAY)
case .Main_Menu:
rl.DrawText("PONG", VIEWPORT_W / 2 - 50, VIEWPORT_H / 3, 40, rl.WHITE)
rl.DrawText("Press ENTER to Start", VIEWPORT_W / 2 - 110, VIEWPORT_H / 2, 20, rl.LIGHTGRAY)
}
}