#![feature(iter_array_chunks)] // used in ray.rs #[cfg(feature = "fmod")] mod audio; mod credits; mod debug; mod display2d; mod display3d; mod game; mod hit; mod loading; mod menu; mod prelude; use std::time::Duration; use bevy::{ asset::{ChangeWatcher, HandleId}, input::{keyboard::KeyboardInput, ButtonState}, }; use crate::prelude::*; fn main() { if std::env::var_os("CARGO_MANIFEST_DIR").is_none() { std::env::set_var("CARGO_MANIFEST_DIR", "."); } let mut app = App::new(); app.add_state::(); app.add_state::(); app.add_systems(Update, state.run_if(resource_changed::>())); app.add_systems(Update, loading.run_if(in_state(GameState::Loading))); app.add_systems( Update, toggle_display_mode.run_if(on_event::()), ); app.add_plugins( DefaultPlugins .set(ImagePlugin::default_nearest()) .set(WindowPlugin { primary_window: Some(Window { title: "Martian Chess".into(), resolution: (640., 480.).into(), ..default() }), ..default() }) .set(AssetPlugin { watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), ..default() }), ); app.add_plugins(credits::CreditsPlugin); app.add_plugins(debug::DebugPlugin); app.add_plugins(display2d::Display2dPlugin); app.add_plugins(display3d::Display3dPlugin); app.add_plugins(game::GamePlugin); app.add_plugins(loading::LoadingPlugin); app.add_plugins(menu::MenuPlugin); #[cfg(feature = "fmod")] app.add_plugins(audio::AudioPlugin); app.run(); } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States, Component)] pub enum GameState { #[default] Loading, Menu, Credits, Play, } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States, Component)] pub enum DisplayState { #[default] Display2d, Display3d, } fn loading( server: Res, sprites: Res>, gltfs: Res>, mut next_state: ResMut>, ) { let s_ids = sprites .ids() .filter(|&id| matches!(id, HandleId::AssetPathId(_))) .collect::>(); let g_ids = gltfs .ids() .filter(|&id| matches!(id, HandleId::AssetPathId(_))) .collect::>(); debug!( "Sprite len: {:?} | GLTF len: {:?}", s_ids.len(), g_ids.len() ); if s_ids.len() > 0 && g_ids.len() > 0 { let s_ready = s_ids .iter() .all(|&id| server.get_load_state(id) == LoadState::Loaded); let g_ready = g_ids .iter() .all(|&id| server.get_load_state(id) == LoadState::Loaded); if s_ready && g_ready { next_state.set(GameState::Menu) } } } /// System for printing the current state /// /// Only runs when state is modified. fn state(game_state: Res>, display_state: Res>) { info!("Game State is {:?}", *game_state); info!("Display State is {:?}", *display_state); } fn toggle_display_mode( mut events: EventReader, display_state: Res>, mut next_state: ResMut>, ) { events .iter() .filter( |KeyboardInput { key_code, state, .. }| (*key_code, *state) == (Some(KeyCode::Space), ButtonState::Pressed), ) .for_each(|_| match display_state.get() { DisplayState::Display2d => next_state.set(DisplayState::Display3d), DisplayState::Display3d => next_state.set(DisplayState::Display2d), }) } fn activate( mut cameras: Query<&mut Camera, With>, mut entities: Query<&mut Visibility, With>, ) { cameras.iter_mut().for_each(|mut camera| { camera.is_active = true; }); entities.iter_mut().for_each(|mut visibility| { *visibility = Visibility::Visible; }); } fn deactivate( mut cameras: Query<&mut Camera, With>, mut entities: Query<&mut Visibility, With>, ) { cameras.iter_mut().for_each(|mut camera| { camera.is_active = false; }); entities.iter_mut().for_each(|mut visibility| { *visibility = Visibility::Hidden; }); } pub(crate) fn any_component_changed(q: Query>) -> bool { !q.is_empty() } pub(crate) fn any_component_added(q: Query>) -> bool { !q.is_empty() } pub(crate) fn any_component_added_or_changed( q: Query, Changed)>>, ) -> bool { !q.is_empty() }