You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
martian-chess/src/main.rs

184 lines
5.1 KiB
Rust

#![allow(clippy::type_complexity, clippy::too_many_arguments)]
#![feature(iter_array_chunks)] // used in ray.rs
#![feature(iter_intersperse)] // used in debug.rs
#![feature(async_closure)] // Loading tweakfiles
mod audio;
mod credits;
mod debug;
mod display3d;
mod game;
mod hit3d;
mod intro;
mod loading;
mod menu;
mod prelude;
mod tutorial;
mod tweak;
mod ui;
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.init_state::<GameState>();
app.init_state::<DisplayState>();
app.add_systems(
Update,
(
debug_state::<DisplayState>.run_if(resource_changed::<State<DisplayState>>),
debug_state::<GameState>.run_if(resource_changed::<State<GameState>>),
debug_state::<tutorial::TutorialState>
.run_if(resource_changed::<State<tutorial::TutorialState>>),
),
);
app.add_systems(Startup, set_window_icon);
app.add_plugins(
DefaultPlugins
.set(ImagePlugin::default_nearest())
.set(WindowPlugin {
primary_window: Some(Window {
title: "Martian Chess".into(),
..default()
}),
..default()
}),
);
app.add_plugins(credits::CreditsPlugin);
app.add_plugins(debug::DebugPlugin);
app.add_plugins(display3d::Display3dPlugin);
app.add_plugins(game::GamePlugin);
app.add_plugins(loading::LoadingPlugin);
app.add_plugins(menu::MenuPlugin);
app.add_plugins(audio::AudioPlugin);
app.add_plugins(ui::UiPlugin);
app.add_plugins(tweak::TweakPlugin);
app.add_plugins(intro::IntroPlugin);
app.add_plugins(tutorial::TutorialPlugin);
app.run();
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States, Component)]
pub enum GameState {
#[default]
Loading,
Credits,
Intro,
Title,
Play,
Endgame,
Restart,
Quit,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States, Component)]
pub(crate) enum DisplayState {
#[default]
Display3d,
}
/// System for printing the current state
///
/// Only runs when state is modified.
fn debug_state<S: States>(state: Res<State<S>>) {
info!("State change {:?}", *state);
}
pub(crate) fn manage_state_entities<Marker>() -> impl FnMut(
Query<
(&Marker, &mut Visibility),
(
With<Marker>,
Without<game::Captured>,
Without<game::ValidMove>,
),
>,
Res<State<Marker>>,
)
where
Marker: Component + States + PartialEq + std::fmt::Debug,
{
move |mut entities: Query<
(&Marker, &mut Visibility),
(
With<Marker>,
Without<game::Captured>,
Without<game::ValidMove>,
),
>,
curr_state: Res<State<Marker>>| {
info!("Activating state {:?}", *curr_state);
entities.iter_mut().for_each(|(mark, mut visibility)| {
*visibility = if mark == curr_state.get() {
Visibility::Inherited
} else {
Visibility::Hidden
};
});
}
}
pub(crate) fn any_component_changed<C: Component>(
) -> impl Fn(Query<Entity, Changed<C>>) -> bool + Clone {
|q: Query<Entity, Changed<C>>| -> bool { !q.is_empty() }
}
pub(crate) fn any_component_added<C: Component>() -> impl Fn(Query<Entity, Added<C>>) -> bool + Clone
{
|q: Query<Entity, Added<C>>| -> bool { !q.is_empty() }
}
pub(crate) fn _any_component_added_or_changed<C: Component>(
q: Query<Entity, Or<(Added<C>, Changed<C>)>>,
) -> bool {
!q.is_empty()
}
fn set_window_icon(
// we have to use `NonSend` here
windows: NonSend<WinitWindows>,
) {
// here we use the `image` crate to load our icon data from a png file
// this is not a very bevy-native solution, but it will do
let (icon_rgba, icon_width, icon_height) = {
let image = image::open("assets/images/3DIcon.png")
.expect("Failed to open icon path")
.into_rgba8();
let (width, height) = image.dimensions();
let rgba = image.into_raw();
(rgba, width, height)
};
let icon = Icon::from_rgba(icon_rgba, icon_width, icon_height).unwrap();
// do it for all windows
for window in windows.windows.values() {
window.set_window_icon(Some(icon.clone()));
}
}
pub(crate) fn just_pressed<T>(button: T) -> impl FnMut(Res<ButtonInput<T>>) -> bool + Clone
where
T: Copy + Eq + Hash + Send + Sync + 'static,
{
Box::new(move |buttons: Res<ButtonInput<T>>| -> bool { buttons.just_pressed(button) })
}
pub(crate) fn just_released<T>(button: T) -> impl FnMut(Res<ButtonInput<T>>) -> bool + Clone
where
T: Copy + Eq + Hash + Send + Sync + 'static,
{
Box::new(move |buttons: Res<ButtonInput<T>>| -> bool { buttons.just_released(button) })
}
pub(crate) fn pressed<T>(button: T) -> impl FnMut(Res<ButtonInput<T>>) -> bool + Clone
where
T: Copy + Eq + Hash + Send + Sync + 'static,
{
Box::new(move |buttons: Res<ButtonInput<T>>| -> bool { buttons.pressed(button) })
}