diff --git a/resources/sprites/flappy.ron b/resources/sprites/flappy.ron index 0d38431..bab8129 100644 --- a/resources/sprites/flappy.ron +++ b/resources/sprites/flappy.ron @@ -37,6 +37,36 @@ y: 490, width: 17, height: 13, - ) + ), + ( // Tap Tap Dialogue + x: 292, + y: 91, + width: 56, + height: 48, + ), + ( // Play Button + x: 354, + y: 118, + width: 50, + height: 28, + ), + ( // Leaderboard button + x: 414, + y: 118, + width: 42, + height: 28, + ), + ( // Get Ready + x: 295, + y: 59, + width: 91, + height: 24, + ), + ( // Flappy Bird Text + x: 351, + y: 91, + width: 88, + height: 25, + ), ] ) \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 853a8d0..7c95d0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,8 +51,9 @@ fn main() -> amethyst::Result<()> { .with_plugin(RenderFlat2D::default()), )?; + // Creates the app with the startup state and bound game data - let mut game = Application::new(resources, state::PlayState::default(), game_data)?; + let mut game = Application::new(resources, state::SplashState::default(), game_data)?; game.run(); Ok(()) diff --git a/src/state.rs b/src/state.rs index 4ade02c..915c81b 100644 --- a/src/state.rs +++ b/src/state.rs @@ -16,16 +16,90 @@ use crate::systems::{BirbGravity, ScrollScrollables}; #[derive(Default)] pub struct PlayState<'a, 'b> { - /// The `State` specific `Dispatcher`, containing `System`s only relevant for this `State`. + + // Custom dispatch systems for this state dispatcher: Option>, + + sprites: Vec, +} + +impl<'a, 'b> PlayState<'a, 'b> { + + fn init_sprites(&mut self, world: &mut World) { + + let sprites = world.try_fetch_mut::>().unwrap().clone(); + let dimensions = (*world.read_resource::()).clone(); + + + let background_sprite = sprites.get("day-background").unwrap().clone(); + + let background_object = TiledScroller { + speed: -75.0, + position: 1.0, + width: 144.0 * 3.0, + height: 256.0 * 3.0, + }; + + let mut transform = Transform::default(); + transform.set_scale(Vector3::new(3.0, 3.0, 3.0)); + transform.set_translation_xyz(background_object.width/2.0, background_object.height/2.0, 0.0); + + self.sprites.push(world + .create_entity() + .with(background_sprite.clone()) // Sprite Render + .with(background_object.clone()) + .with(transform.clone()) + .build()); + + transform.set_translation_xyz(3.0*144.0/2.0*3.0, 3.0*256.0/2.0, 0.0); + + self.sprites.push(world + .create_entity() + .with(background_sprite.clone()) // Sprite Render + .with(TiledScroller { + speed: -75.0, + position: 2.0, + width: 0.0, + height: 0.0 + }) + .with(transform.clone()) + .build()); + + let ground_sprite = sprites.get("ground").unwrap(); + transform.set_translation_xyz(3.0*168.0/2.0*3.0, 3.0*56.0/2.0, 0.1); + + self.sprites.push(world + .create_entity() + .with(ground_sprite.clone()) // Sprite Render + .with(TiledScroller { + speed: -100.0, + position: 2.0, + width: 0.0, + height: 0.0, + }) + .with(transform.clone()) + .build()); + + let birb_sprite = sprites.get("floppy").unwrap(); + transform.set_translation_xyz(dimensions.width()/2.0, dimensions.height()/2.0, 0.2); + + self.sprites.push(world + .create_entity() + .with(birb_sprite.clone()) // Sprite Render + .with(Birb { + vertical_speed: 0.0, + position: 0.0, + starting_height: 0.0 + }) + .with(transform) + .build()); + } } impl<'a, 'b> SimpleState for PlayState<'a, 'b> { - // On start will run when this state is initialized. For more - // state lifecycle hooks, see: - // https://book.amethyst.rs/stable/concepts/state.html#life-cycle fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) { + let world = data.world; // Get the screen dimensions so we can initialize the camera and @@ -36,7 +110,7 @@ impl<'a, 'b> SimpleState for PlayState<'a, 'b> { // Place the camera /// function sets size of camera window - init_camera(world, &dimensions); + // Create the `DispatcherBuilder` and register some `System`s that should only run for this `State`. let mut dispatcher_builder = DispatcherBuilder::new(); @@ -49,10 +123,7 @@ impl<'a, 'b> SimpleState for PlayState<'a, 'b> { self.dispatcher = Some(dispatcher); - // Load our sprites and display them - let sprites = load_sprites(world); - world.insert(sprites.clone()); - init_sprites(world, &sprites, &dimensions); + PlayState::init_sprites(self, world); } @@ -69,13 +140,9 @@ impl<'a, 'b> SimpleState for PlayState<'a, 'b> { } if is_key_down(&event, VirtualKeyCode::P) { - // So I need to set the scrolling and gravity systems to pause - - return Trans::Push(Box::new(PausedState{ sprite: None })); + return Trans::Pop; } } - - // Keep going Trans::None } @@ -84,163 +151,263 @@ impl<'a, 'b> SimpleState for PlayState<'a, 'b> { if let Some(dispatcher) = self.dispatcher.as_mut() { dispatcher.dispatch(&data.world); } - Trans::None } } -fn init_camera(world: &mut World, dimensions: &ScreenDimensions) { - // Center the camera in the middle of the screen, and let it cover - // the entire screen - let mut transform = Transform::default(); - transform.set_translation_xyz(dimensions.width() * 0.5, dimensions.height() * 0.5, 1.); - - world - .create_entity() - .with(Camera::standard_2d(dimensions.width(), dimensions.height())) - .with(transform) - .build(); +#[derive(Default)] +pub struct SplashState { + sprites: Vec, } -fn load_sprites(world: &mut World) -> HashMap { - // Load the texture for our sprites. We'll later need to - // add a handle to this texture to our `SpriteRender`s, so - // we need to keep a reference to it. - let texture_handle = { - let loader = world.read_resource::(); - let texture_storage = world.read_resource::>(); - loader.load( - "sprites/flappy.png", - ImageFormat::default(), - (), - &texture_storage, - ) - }; - - // Load the spritesheet definition file, which contains metadata on our - // spritesheet texture. - let sheet_handle = { - let loader = world.read_resource::(); - let sheet_storage = world.read_resource::>(); - loader.load( - "sprites/flappy.ron", - SpriteSheetFormat(texture_handle), - (), - &sheet_storage, - ) - }; - - let sprite_map = vec![ - ("day-background".to_string(), 0), - ("night-background".to_string(), 1), - ("down-pipe".to_string(), 2), - ("up-pipe".to_string(), 3), - ("ground".to_string(), 4), - ("floppy".to_string(), 5), - ]; - - sprite_map.iter() - .map(|i| (i.0.clone(), SpriteRender { - sprite_sheet: sheet_handle.clone(), - sprite_number: i.1, - })) - .collect() -} +impl SplashState { -fn init_sprites(world: &mut World, sprites: &HashMap, dimensions: &ScreenDimensions) { + fn init_camera(world: &mut World) { - let background_sprite = sprites.get("day-background").unwrap(); + let dimensions = (*world.read_resource::()).clone(); + // Center the camera in the middle of the screen, and let it cover + // the entire screen + let mut transform = Transform::default(); + transform.set_translation_xyz(dimensions.width() * 0.5, dimensions.height() * 0.5, 1.); - let background_object = TiledScroller { - speed: -75.0, - position: 1.0, - width: 144.0 * 3.0, - height: 256.0 * 3.0, - }; + world + .create_entity() + .with(Camera::standard_2d(dimensions.width(), dimensions.height())) + .with(transform) + .build(); + } - let mut transform = Transform::default(); - transform.set_scale(Vector3::new(3.0, 3.0, 3.0)); - transform.set_translation_xyz(background_object.width/2.0, background_object.height/2.0, 0.0); + fn init_sprites(&mut self, world: &mut World) { + let sprites = world.try_fetch_mut::>().unwrap().clone(); + let dimensions = (*world.read_resource::()).clone(); - world - .create_entity() - .with(background_sprite.clone()) // Sprite Render - .with(background_object.clone()) - .with(transform.clone()) - .build(); + let flappy_bird_text_sprite = sprites + .get("flappy-bird-text").unwrap().clone(); + let play_button_sprite = sprites + .get("play-button").unwrap().clone(); + let leaderboard_button_sprite = sprites + .get("leaderboard-button").unwrap().clone(); + let background_sprite = sprites + .get("day-background").unwrap().clone(); + let ground_sprite = sprites + .get("ground").unwrap().clone(); + + let background_object = TiledScroller { + speed: -75.0, + position: 1.0, + width: 144.0 * 3.0, + height: 256.0 * 3.0, + }; - transform.set_translation_xyz(3.0*144.0/2.0*3.0, 3.0*256.0/2.0, 0.0); + let mut transform = Transform::default(); + transform.set_scale(Vector3::new(3.0, 3.0, 3.0)); + transform.set_translation_xyz(dimensions.width()/2.0 - 100.0, dimensions.height() - 100.0, 0.1); - world - .create_entity() - .with(background_sprite.clone()) // Sprite Render - .with(TiledScroller { - speed: -75.0, - position: 2.0, - width: 0.0, - height: 0.0 - }) - .with(transform.clone()) - .build(); - - let ground_sprite = sprites.get("ground").unwrap(); - transform.set_translation_xyz(3.0*168.0/2.0*3.0, 3.0*56.0/2.0, 0.1); - - world - .create_entity() - .with(ground_sprite.clone()) // Sprite Render - .with(TiledScroller { - speed: -100.0, - position: 2.0, - width: 0.0, - height: 0.0, - }) - .with(transform.clone()) - .build(); - - let birb_sprite = sprites.get("floppy").unwrap(); - transform.set_translation_xyz(dimensions.width()/2.0, dimensions.height()/2.0, 0.2); - - world - .create_entity() - .with(birb_sprite.clone()) // Sprite Render - .with(Birb { - vertical_speed: 0.0, - position: 0.0, - starting_height: 0.0 - }) - .with(transform) - .build(); + self.sprites.push(world + .create_entity() + .with(background_sprite.clone()) // Sprite Render + .with(background_object.clone()) + .with(transform.clone()) + .build()); -} + transform.set_translation_xyz(3.0*144.0/2.0*3.0, 3.0*256.0/2.0, 0.0); -#[derive(Default)] -pub struct PausedState { - sprite: Option, + self.sprites.push(world + .create_entity() + .with(background_sprite.clone()) // Sprite Render + .with(TiledScroller { + speed: -75.0, + position: 2.0, + width: 0.0, + height: 0.0 + }) + .with(transform.clone()) + .build()); + + transform.set_translation_xyz(3.0*168.0/2.0*3.0, 3.0*56.0/2.0, 0.1); + + self.sprites.push(world + .create_entity() + .with(ground_sprite.clone()) // Sprite Render + .with(TiledScroller { + speed: -100.0, + position: 2.0, + width: 0.0, + height: 0.0, + }) + .with(transform.clone()) + .build()); + + transform.set_translation_xyz(background_object.width/2.0, background_object.height/2.0, 0.0); + + self.sprites.push(world + .create_entity() + .with(flappy_bird_text_sprite.clone()) + .with(transform.clone()) + .build()); + + transform.set_translation_xyz(100.0/2.0, 100.0/2.0, 0.1); + + self.sprites.push(world + .create_entity() + .with(play_button_sprite.clone()) + .with(transform.clone()) + .build()); + + transform.set_translation_xyz(500.0/2.0, 100.0/2.0, 0.1); + + self.sprites.push(world + .create_entity() + .with(leaderboard_button_sprite.clone()) + .with(transform.clone()) + .build()); + } + + fn load_sprites(world: &mut World) -> HashMap { + // Load the texture for our sprites. We'll later need to + // add a handle to this texture to our `SpriteRender`s, so + // we need to keep a reference to it. + let texture_handle = { + let loader = world.read_resource::(); + let texture_storage = world.read_resource::>(); + loader.load( + "sprites/flappy.png", + ImageFormat::default(), + (), + &texture_storage, + ) + }; + + // Load the spritesheet definition file, which contains metadata on our + // spritesheet texture. + let sheet_handle = { + let loader = world.read_resource::(); + let sheet_storage = world.read_resource::>(); + loader.load( + "sprites/flappy.ron", + SpriteSheetFormat(texture_handle), + (), + &sheet_storage, + ) + }; + + let sprite_map = vec![ + ("day-background".to_string(), 0), + ("night-background".to_string(), 1), + ("down-pipe".to_string(), 2), + ("up-pipe".to_string(), 3), + ("ground".to_string(), 4), + ("floppy".to_string(), 5), + ("tap-tap-dialogue".to_string(), 6), + ("play-button".to_string(), 7), + ("leaderboard-button".to_string(), 8), + ("get-ready-text".to_string(), 9), + ("flappy-bird-text".to_string(), 10), + ]; + + sprite_map.iter() + .map(|i| (i.0.clone(), SpriteRender { + sprite_sheet: sheet_handle.clone(), + sprite_number: i.1, + })) + .collect() + } } -impl SimpleState for PausedState { +impl SimpleState for SplashState { fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) { let world = data.world; + // Load the sprites. Insert them into the world as this is the first function to be called + let sprites = SplashState::load_sprites(world); + world.insert(sprites.clone()); + + SplashState::load_sprites(world); + SplashState::init_camera(world); + SplashState::init_sprites(self, world); + + } + + fn handle_event( + &mut self, + mut data: StateData<'_, GameData<'_, '_>>, + event: StateEvent, + ) -> SimpleTrans { + + if let StateEvent::Window(event) = &event { + // Check if the window should be closed + if is_close_requested(&event) || is_key_down(&event, VirtualKeyCode::Escape) { + return Trans::Quit; + } + + // Check if the window should be closed + if is_key_down(&event, VirtualKeyCode::Space) { + let world = data.world; + for i in &self.sprites { + world.delete_entity(*i); + } + self.sprites.clear(); + + return Trans::Push(Box::new(ReadyState::default())); + } + } + + // Keep going + Trans::None + } + + fn update(&mut self, data: &mut StateData<'_, GameData<'_, '_>>) -> SimpleTrans { + Trans::None + } +} + +#[derive(Default)] +pub struct ReadyState { + sprites: Vec, +} + +impl ReadyState { + fn init_sprites(&mut self, world: &mut World, dimensions: &ScreenDimensions) { + let dimensions = (*world.read_resource::()).clone(); + let sprites = world.try_fetch_mut::>().unwrap().clone(); + + let get_ready_text_sprite = sprites + .get("get-ready-text").unwrap().clone(); - let sprite = world.try_fetch::>().unwrap().get("up-pipe").unwrap().clone(); + let tap_tap_dialogue_sprite = sprites + .get("tap-tap-dialogue").unwrap().clone(); - // let sprite = resource.get("up-pipe").unwrap().clone(); let mut transform = Transform::default(); transform.set_scale(Vector3::new(3.0, 3.0, 3.0)); + transform.set_translation_xyz(dimensions.width()/2.0 - 100.0, dimensions.height() - 100.0, 0.1); + + self.sprites.push(world + .create_entity() + .with(get_ready_text_sprite.clone()) // Sprite Render + .with(transform.clone()) + .build()); + transform.set_translation_xyz(500.0/2.0, 500.0/2.0, 0.1); - self.sprite = Some(world + self.sprites.push(world .create_entity() - .with(sprite.clone()) // Sprite Render + .with(tap_tap_dialogue_sprite.clone()) // Sprite Render .with(transform.clone()) .build()); } +} +impl SimpleState for ReadyState { + + + fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) { + let world = data.world; + + + } fn handle_event( &mut self, @@ -250,12 +417,19 @@ impl SimpleState for PausedState { if let StateEvent::Window(event) = &event { // Check if the window should be closed - if is_key_down(&event, VirtualKeyCode::Space) { + if is_close_requested(&event) || is_key_down(&event, VirtualKeyCode::Escape) { + return Trans::Quit; + } + // Check if the window should be closed + if is_key_down(&event, VirtualKeyCode::Space) { let world = data.world; - world.delete_entity(self.sprite.unwrap()); - self.sprite = None; - return Trans::Pop; + for i in &self.sprites { + world.delete_entity(*i); + } + self.sprites.clear(); + + return Trans::Push(Box::new(PlayState::default())); } }