use crate::core::world::GameData;
pub trait Scene {
fn on_start(&mut self, _data: &mut GameData) {}
fn on_update(&mut self, _data: &mut GameData) {}
fn late_update(&mut self, _data: &mut GameData) {}
fn on_stop(&mut self, _data: &mut GameData) {}
}
pub(crate) enum SceneAction {
Update,
Start,
EndFrame,
LateUpdate,
}
#[derive(Default)]
pub(crate) struct SceneMachine {
pub(crate) current_scene: Option<Box<dyn Scene>>,
pub(crate) current_scene_started: bool
}
impl SceneMachine {
pub(crate) fn apply_scene_action(&mut self, action: SceneAction, data: &mut GameData) {
if let Some(scene) = self.current_scene.as_mut() {
match action {
SceneAction::Update => {
if !self.current_scene_started{
scene.on_start(data);
self.current_scene_started = true;
}
scene.on_update(data);
},
SceneAction::Start => {
scene.on_start(data);
self.current_scene_started = true;
},
SceneAction::EndFrame => {}
SceneAction::LateUpdate => scene.late_update(data),
};
}
match action {
SceneAction::EndFrame => {
let action = data.scene_controller().action();
match action {
Some(SceneTrans::Switch(new_scene)) => {
if let Some(mut scene) = self.current_scene.take() {
scene.on_stop(data);
}
self.current_scene = Some(new_scene);
self.current_scene_started = false;
}
_ => {}
}
}
_ => {}
}
}
}
pub(crate) enum SceneTrans {
Switch(Box<dyn Scene>)
}
#[derive(Default)]
pub struct SceneController {
pub(crate) action: Option<SceneTrans>,
}
impl SceneController {
pub fn switch<T: Scene + Default + 'static>(&mut self) {
self.action = Some(SceneTrans::Switch(Box::<T>::default()));
}
pub(crate) fn action(&mut self) -> Option<SceneTrans> {
self.action.take()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Default)]
struct A;
#[derive(Default)]
struct B;
#[derive(Default)]
struct C;
#[derive(Default)]
struct D;
impl Scene for A {}
impl Scene for B {}
#[test]
fn switch_scene_should_replace_at_same_index() {
let mut world = GameData::default();
world.insert_resource(SceneController::default());
let scene = Box::new(A);
let mut machine = SceneMachine { current_scene: Some(scene), current_scene_started: false };
world.scene_controller().switch::<B>();
machine.apply_scene_action(SceneAction::EndFrame, &mut world);
}
}