use ggez::event::{self, EventLoop};
use ggez::graphics::Color;
use ggez::*;
use std::collections::VecDeque;
pub struct SceneManager {
scene_stack: VecDeque<Box<dyn Scene>>,
}
impl SceneManager {
pub fn new<T: Scene + 'static>(initial_scene: T) -> Self {
let mut sm = SceneManager {
scene_stack: VecDeque::new(),
};
sm.scene_stack.push_back(Box::new(initial_scene));
sm
}
pub fn new_and_run<T: Scene + 'static>(
event_loop: EventLoop<()>,
ctx: Context,
initial_scene: T,
) -> ! {
let sm = SceneManager::new(initial_scene);
event::run(ctx, event_loop, sm)
}
}
impl event::EventHandler<GameError> for SceneManager {
fn update(&mut self, ctx: &mut Context) -> Result<(), GameError> {
if let Some(scene) = self.scene_stack.back_mut() {
let switch = scene.update(ctx)?;
match switch {
SceneSwitch::None => {}
SceneSwitch::Pop(n) => {
for _ in 0..n {
self.scene_stack.pop_back();
}
}
SceneSwitch::Replace(n, scene_box) => {
for _ in 0..n {
self.scene_stack.pop_back();
}
self.scene_stack.push_back(scene_box);
}
SceneSwitch::Push(scene_box) => {
self.scene_stack.push_back(scene_box);
}
}
}
if self.scene_stack.is_empty() {
ctx.request_quit();
}
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> Result<(), GameError> {
let canvas = graphics::Canvas::from_frame(ctx, Color::from_rgb(0, 0, 0));
canvas.finish(ctx)?;
let mut it = self.scene_stack.iter_mut().peekable();
while let Some(scenebox) = it.next() {
scenebox.draw(ctx, it.peek().is_none())?;
}
Ok(())
}
}
pub enum SceneSwitch {
None,
Pop(u32),
Push(Box<dyn Scene>),
Replace(u32, Box<dyn Scene>),
}
impl SceneSwitch {
pub fn none() -> Self {
Self::None
}
pub fn push(scene: impl Scene + 'static) -> Self {
Self::Push(Box::new(scene))
}
pub fn pop(pop_amount: u32) -> Self {
Self::Pop(pop_amount)
}
pub fn replace(scene: impl Scene + 'static, pop_amount: u32) -> Self {
Self::Replace(pop_amount, Box::new(scene))
}
}
pub trait Scene {
fn update(&mut self, ctx: &mut Context) -> Result<SceneSwitch, GameError>;
fn draw(&mut self, ctx: &mut Context, mouse_listen: bool) -> Result<(), GameError>;
}