diff --git a/src/assets.rs b/src/assets.rs deleted file mode 100644 index 323d9a4..0000000 --- a/src/assets.rs +++ /dev/null @@ -1,72 +0,0 @@ -use bevy::prelude::*; - -#[derive(Resource, Debug, Default)] -pub struct AssetLoader { - pub layouts: Layouts, - pub images: Images, - pub sounds: Sounds, - pub fonts: Fonts, -} - -#[derive(Resource, Debug, Default)] -pub struct Layouts { - pub player: Handle, - pub statue: Handle, -} - -#[derive(Resource, Debug, Default)] -pub struct Images { - pub player: Handle, - pub statue: Handle, -} - -#[derive(Resource, Debug, Default)] -pub struct Sounds { - pub meow: Handle, -} - -#[derive(Resource, Debug, Default)] -pub struct Fonts { - pub iosevkalytemin: Handle, -} - -pub fn startup( - mut assets: ResMut, - asset_server: Res, - mut texture_atlases: ResMut>, -) { - let props = asset_server.load("img/Props.png"); - let player = asset_server.load("img/Player.png"); - - let player_atlas = TextureAtlasLayout::from_grid( - UVec2::new(32, 64), - 3, - 1, - Some(UVec2 { x: 0, y: 0 }), - Some(UVec2 { x: 0, y: 0 }), - ); - let statue_atlas = - TextureAtlasLayout::from_grid(UVec2::new(40, 74), 1, 1, None, Some(UVec2::new(443, 20))); - - let player_atlas_handle = texture_atlases.add(player_atlas); - let statue_atlas_handle = texture_atlases.add(statue_atlas); - - *assets = AssetLoader { - images: Images { - player, - statue: props.clone(), - }, - layouts: Layouts { - player: player_atlas_handle, - statue: statue_atlas_handle, - }, - - sounds: Sounds { - meow: asset_server.load("sfx/meow.wav"), - }, - - fonts: Fonts { - iosevkalytemin: asset_server.load("font/iosevka-lyteterm-regular.subset.ttf"), - }, - }; -} diff --git a/src/camera.rs b/src/camera.rs index 34f8fab..fb4ed46 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -2,8 +2,8 @@ use bevy::prelude::*; use bevy::render::camera::Camera; pub fn startup(mut commands: Commands) { - let bundle = (Camera2dBundle::default(), IsDefaultUiCamera); - // bundle.0.projection.scale = 1; + let mut bundle = (Camera2dBundle::default(), IsDefaultUiCamera); + bundle.0.projection.scale = 1.; commands.spawn(bundle); } diff --git a/src/game.rs b/src/game.rs new file mode 100644 index 0000000..b70f4ee --- /dev/null +++ b/src/game.rs @@ -0,0 +1,4 @@ +use crate::prelude::*; + +#[derive(Component, Default)] +pub struct Gameobject; diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..1036432 --- /dev/null +++ b/src/input.rs @@ -0,0 +1,53 @@ +use bevy::prelude::*; + +#[derive(Resource, Default, Debug, Clone, PartialEq)] +pub struct Input { + pub movement: Vec2, + pub angle: f32, + pub action: bool, + pub cancel: bool, +} + +pub fn process_input( + mut input: ResMut, + keys: Res>, + // mouse: Res>, +) { + input.movement.x = 0.; + input.movement.y = 0.; + for key in keys.get_pressed() { + match key { + KeyCode::KeyA | KeyCode::ArrowLeft => { + input.movement -= Vec2::X; + } + KeyCode::KeyD | KeyCode::ArrowRight => { + input.movement += Vec2::X; + } + KeyCode::KeyW | KeyCode::ArrowUp => { + input.movement += Vec2::Y; + } + KeyCode::KeyS | KeyCode::ArrowDown => { + input.movement -= Vec2::Y; + } + _ => {} + } + } + input.movement = input.movement.normalize_or_zero(); + // input.target // not set using keyboard, see mouse + input.action = input.action || keys.any_pressed([KeyCode::Space, KeyCode::Enter]); + input.cancel = input.cancel || keys.just_pressed(KeyCode::Escape); + + info!("Input: {:#?}", input); +} + +// TODO: controller input: https://bevy-cheatbook.github.io/input/gamepad.html +// Iterate controllers on startup and assign to players/units? +// What logic for handling controller connection/disconnection? +// Will we have splitscreen? +// Once a controller is assigned to a player, we can handle its input +// pub fn controller_input( +// axes: Res>, +// buttons: Res>, +// my_gamepad: Option>, +// ) { +// } diff --git a/src/main.rs b/src/main.rs index ae8b1f8..7916255 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,20 @@ -use bevy::audio::{AudioPlugin, SpatialScale}; -use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin}; -use bevy::prelude::{default, *}; -use bevy::window::{PrimaryWindow, WindowMode}; - -mod assets; mod camera; +mod game; +mod input; mod main_menu; mod movement; mod player; +mod prelude; mod statue; +use bevy::asset::load_internal_binary_asset; +use bevy::audio::{AudioPlugin, SpatialScale}; +use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin}; +use bevy::window::{PrimaryWindow, WindowMode}; +use input::Input; +use prelude::*; +use statue::SpawnStatueEvent; + #[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)] pub enum Game { #[default] @@ -39,7 +44,8 @@ fn main() -> AppExit { .set(WindowPlugin { primary_window: Some(Window { title: "Kodo Tag".into(), - mode: bevy::window::WindowMode::BorderlessFullscreen, + // mode: bevy::window::WindowMode::BorderlessFullscreen, + mode: bevy::window::WindowMode::Windowed, // resolution: (640. * 2., 360. * 2.).into(), ..default() }), @@ -52,41 +58,57 @@ fn main() -> AppExit { }) .set(ImagePlugin::default_nearest()), FrameTimeDiagnosticsPlugin, - )) - .init_resource::() - .init_state::() - .init_state::() - .add_systems(OnEnter(View::MainMenu), main_menu::startup) - .add_systems(OnExit(View::MainMenu), main_menu::exit) - .add_systems(OnEnter(View::InGame), (player::startup, statue::startup)) - .add_systems(OnExit(View::InGame), (player::exit, statue::exit)) - .add_systems( - OnEnter(View::LoadingScreen), - (startup, assets::startup, camera::startup), - ) - .add_systems( + )); + + load_internal_binary_asset!( + app, + TextStyle::default().font, + "../assets/font/iosevka-lyteterm-regular.subset.ttf", + |bytes: &[u8], _path: String| { Font::try_from_bytes(bytes.to_vec()).unwrap() } + ); + + app.init_resource::() + .init_state::() + .init_state::(); + + app.configure_sets( Update, ( - update, - finish_setup.run_if(in_state(View::LoadingScreen)), - ( - player::sprite_select, - player::controls, - movement::update_velocity_by_heading, - movement::resolve_velocity.after(movement::update_velocity_by_heading), - movement::ysort.after(movement::update_velocity_by_heading), - camera::update - .after(player::controls) - .after(movement::resolve_velocity), - ) - .in_set(InGameSet) - .run_if(in_state(View::InGame)), - (main_menu::update) - .in_set(MainMenuSet) - .run_if(in_state(View::MainMenu)), + MainMenuSet.run_if(in_state(View::MainMenu)), + InGameSet + .run_if(in_state(View::InGame)) + .after(input::process_input), ), - ) - .insert_resource(ClearColor(Color::srgb(0.3, 0.1, 0.5))); + ); + + app.add_event::(); + + app.add_systems(OnEnter(View::MainMenu), main_menu::startup) + .add_systems(OnExit(View::MainMenu), main_menu::exit) + .add_systems(OnEnter(View::InGame), (player::startup, statue::startup)) + .add_systems(OnExit(View::InGame), (player::exit, statue::exit)) + .add_systems(OnEnter(View::LoadingScreen), (startup, camera::startup)) + .add_systems( + Update, + ( + finish_setup.run_if(in_state(View::LoadingScreen)), + input::process_input, + (update,).after(input::process_input), + ( + player::control, + statue::spawn_statue, + movement::update_velocity_by_heading, + movement::resolve_velocity.after(movement::update_velocity_by_heading), + movement::ysort.after(movement::update_velocity_by_heading), + camera::update + .after(player::control) + .after(movement::resolve_velocity), + ) + .in_set(InGameSet), + (main_menu::update).in_set(MainMenuSet), + ), + ) + .insert_resource(ClearColor(Color::srgb(0.3, 0.1, 0.5))); // NOTE: would need to add PBR feature I think? // Was intending to use this for day/night cycle type stuff a la V Rising? // app.insert_resource(AmbientLight { @@ -97,14 +119,6 @@ fn main() -> AppExit { app.run() } -fn toggle_fullscreen(mut window: Mut) { - if window.mode == WindowMode::Windowed { - window.mode = WindowMode::BorderlessFullscreen - } else { - window.mode = WindowMode::Windowed - } -} - #[derive(Component)] struct FpsText; @@ -112,22 +126,21 @@ fn finish_setup(mut app_state: ResMut>) { app_state.set(View::MainMenu); } -fn startup(mut commands: Commands, assets: Res) { +fn startup(mut commands: Commands, mut ui_scale: ResMut) { commands.spawn(( FpsText, TextBundle::from_sections([ TextSection::new( "FPS: ", TextStyle { - font: assets.fonts.iosevkalytemin.clone(), font_size: 60., ..default() }, ), TextSection::from_style(TextStyle { - font: assets.fonts.iosevkalytemin.clone(), font_size: 60., color: Color::hsla(0.5, 0.5, 0.5, 0.5), + ..default() }), ]) .with_style(Style { @@ -137,19 +150,49 @@ fn startup(mut commands: Commands, assets: Res) { ..default() }), )); + + ui_scale.0 = 1.; } fn update( + view: Res>, + input: Res, + mut next_state: ResMut>, diagnostics: Res, mut query: Query<&mut Text, With>, - keyboard: Res>, mut window: Query<&mut Window, With>, + keys: Res>, + mut app_exit_events: ResMut>, ) { - if keyboard.just_pressed(KeyCode::Enter) - && (keyboard.pressed(KeyCode::AltLeft) || keyboard.pressed(KeyCode::AltRight)) + if input.cancel { + match view.get() { + View::InGame => { + next_state.set(crate::View::MainMenu); + } + View::MainMenu => { + app_exit_events.send(AppExit::Success); + } + View::LoadingScreen => {} + } + } else if input.action { + match view.get() { + View::InGame => {} + View::MainMenu => { + next_state.set(crate::View::InGame); + } + View::LoadingScreen => {} + } + } + if keys.just_pressed(KeyCode::Enter) + && (keys.pressed(KeyCode::AltLeft) || keys.pressed(KeyCode::AltRight)) { if let Ok(window) = window.get_single_mut() { - toggle_fullscreen(window) + let mut window = window; + if window.mode == WindowMode::Windowed { + window.mode = WindowMode::BorderlessFullscreen + } else { + window.mode = WindowMode::Windowed + } } } for mut text in &mut query { diff --git a/src/main_menu.rs b/src/main_menu.rs index 76e4d40..4ae5048 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -1,11 +1,9 @@ use bevy::prelude::*; -use crate::assets::AssetLoader; - #[derive(Component, Debug)] pub struct MainMenu; -pub fn startup(mut commands: Commands, assets: Res) { +pub fn startup(mut commands: Commands) { commands .spawn(( MainMenu, @@ -25,7 +23,6 @@ pub fn startup(mut commands: Commands, assets: Res) { TextBundle::from_section( "Text Example\nPress ENTER to play", TextStyle { - font: assets.fonts.iosevkalytemin.clone(), font_size: 100.0, ..default() }, @@ -63,20 +60,4 @@ pub fn exit(mut commands: Commands, q: Query>) { } } -pub fn update( - keyboard: Res>, - mut next_state: ResMut>, - mut app_exit_events: ResMut>, -) { - for key in keyboard.get_just_pressed() { - match key { - KeyCode::Escape => { - app_exit_events.send(AppExit::Success); - } - KeyCode::Enter => { - next_state.set(crate::View::InGame); - } - _ => {} - } - } -} +pub fn update() {} diff --git a/src/movement.rs b/src/movement.rs index 4f7eff2..a067af3 100644 --- a/src/movement.rs +++ b/src/movement.rs @@ -9,7 +9,7 @@ pub struct Heading(pub Vec2); #[derive(Component, Deref, DerefMut, Debug, Default)] pub struct Speed(pub f32); -#[derive(Component, Debug)] +#[derive(Component, Debug, Default)] pub struct YSortable; pub fn resolve_velocity(mut query: Query<(&Velocity, &mut Transform)>, time: Res