diff --git a/src/game_scene_manager.odin b/src/game_scene_manager.odin new file mode 100644 index 0000000..c80fe75 --- /dev/null +++ b/src/game_scene_manager.odin @@ -0,0 +1,132 @@ +package game + +import rl "vendor:raylib" + +Scene :: union { + Scene_Menu, + Scene_Gameplay, +} + +Scene_Menu :: struct { + selected_option: int, +} + +Scene_Gameplay :: struct { + level: Level, +} + +// ------------------------------------------------------------------------------ +// Scene Dispatchers +// ------------------------------------------------------------------------------ +scene_update :: proc(game: ^Game, dt: f32) { + // Must mutate the actual union via pointer + switch &s in game.current_scene { + case Scene_Menu: // update_menu(&s, game, dt) + case Scene_Gameplay: update_gameplay(&s, game, dt) + } +} + +scene_render :: proc(game: ^Game) { + // Value inspect is fine for rendering + switch &s in game.current_scene { + case Scene_Menu: // render_menu(s) + case Scene_Gameplay: render_gameplay(s, game.is_paused) + } +} + +// ------------------------------------------------------------------------------ +// Gameplay Scene +// ------------------------------------------------------------------------------ +init_gameplay_scene :: proc() -> Scene_Gameplay { + return Scene_Gameplay{ + level = init_level(), + } +} + +update_gameplay :: proc(scene: ^Scene_Gameplay, game: ^Game, dt: f32) { + if rl.IsKeyPressed(.P) { + game.is_paused = !game.is_paused + } + + if game.is_paused { + if rl.IsKeyPressed(.Q) { + game.current_scene = Scene_Menu{selected_option = 0} + } + return + } + + // Delegate world updates to level logic + update_level(&scene.level, dt) +} + +render_gameplay :: proc(scene: Scene_Gameplay, is_paused: bool) { + // Delegate world rendering to level logic + render_level(scene.level) + + // Scene UI Overlays + if is_paused { + rl.DrawText("PAUSED", 1200, 700, 40, rl.WHITE) + rl.DrawText("Press Q to Quit to Menu", 1150, 760, 20, rl.LIGHTGRAY) + } +} + +// +Level :: struct { + field_bounds: rl.Rectangle, + player: Entity, + enemy: Entity, + ball: Entity, +} + +init_level :: proc() -> Level { + pad_x := f32(WINDOW_WIDTH) * 0.10 + pad_y := f32(WINDOW_HEIGHT) * 0.10 + + bounds := rl.Rectangle{ + x = pad_x, + y = pad_y, + width = f32(WINDOW_WIDTH) - (pad_x * 2), + height = f32(WINDOW_HEIGHT) - (pad_y * 2), + } + + // player entity + player_ent := init_player() + player_ent.pos.x = bounds.x + 3 + player_ent.pos.y = bounds.y + (bounds.height / 2) - (player_ent.shape_size.y / 2) + + // enemy entity + enemy_ent := init_enemy() + enemy_ent.pos.x = (bounds.width + pad_x) - (enemy_ent.shape_size.x) - 3 + enemy_ent.pos.y = bounds.y + (bounds.height / 2) - (enemy_ent.shape_size.y / 2) + + + return Level{ + field_bounds = bounds, + player = player_ent, + enemy = enemy_ent, + ball = init_ball() + } +} + +update_level :: proc(level: ^Level, dt: f32) { + update_player(dt, &level.player, level) + // update_enemy(...) + // update_ball(...) +} + +render_level :: proc(level: Level) { + // Field Background & Outer Border + rl.DrawRectangleRec(level.field_bounds, rl.DARKGRAY) + rl.DrawRectangleLinesEx(level.field_bounds, 3, rl.RAYWHITE) + + // Center Divide Line + center_x := f32(WINDOW_WIDTH) / 2.0 + start_pos := rl.Vector2{center_x, level.field_bounds.y + 3} + end_pos := rl.Vector2{center_x, level.field_bounds.y + level.field_bounds.height - 3} + rl.DrawLineEx(start_pos, end_pos, 3.0, rl.WHITE) + + // Entities + render_player(level.player, level.field_bounds) + render_enemy(level.enemy, level.field_bounds) + render_ball(level.ball, level.field_bounds) +} \ No newline at end of file