#![allow(clippy::too_many_arguments)] #[cfg(not(target_arch = "wasm32"))] mod audio; #[cfg(not(target_arch = "wasm32"))] mod editor; mod filters; mod game; mod levels; mod menu; mod particle_effect; use bevy::{ asset::{Asset, HandleId, LoadState}, prelude::*, window::{WindowMode, WindowResizeConstraints}, }; use bevy_common_assets::json::JsonAssetPlugin; use bevy_rapier2d::prelude::*; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] enum AppState { Loading, Menu, Game, Win, Editor, } struct UseEditor(bool); struct LoadingAssets(Vec); impl LoadingAssets { fn add(&mut self, handle: Handle) -> Handle { self.0.push(handle.id); handle } } fn main() { let (audio_event_sender, audio_event_receiver) = crossbeam_channel::bounded::(512); #[cfg(not(target_arch = "wasm32"))] std::thread::spawn(move || audio::setup(audio_event_receiver)); #[cfg(not(target_arch = "wasm32"))] let (first_level, use_editor) = { let mut args = std::env::args().skip(1); ( game::LevelId(args.next().map_or(0, |s| s.parse().unwrap_or(0))), args.next().map_or(false, |s| s == "e"), ) }; #[cfg(target_arch = "wasm32")] let (first_level, use_editor) = (game::LevelId(0), false); let mut app = App::new(); app.insert_resource(Msaa { samples: 4 }) .insert_resource(WindowDescriptor { width: 640.0, height: 480.0, resize_constraints: WindowResizeConstraints { min_width: 256., min_height: 256., max_width: f32::INFINITY, max_height: f32::INFINITY, }, resizable: true, title: "Lux synthesĕ".into(), ..Default::default() }) .insert_resource(audio_event_sender) .insert_resource(UseEditor(use_editor)) .add_state(AppState::Loading) .insert_resource(game::FirstLevel(first_level)) .insert_resource(ClearColor(Color::BLACK)) .add_plugins(DefaultPlugins) //.add_plugin(RapierDebugRenderPlugin::default()) //.add_plugin(bevy_inspector_egui::WorldInspectorPlugin::new()) .add_plugin(JsonAssetPlugin::::new(&[ "levels.json", ])); if !use_editor { app.add_plugin(RapierPhysicsPlugin::::pixels_per_meter(64.0)) .add_plugin(menu::MenuPlugin) .add_plugin(game::GamePlugin) .add_plugin(particle_effect::ParticleEffectPlugin); } #[cfg(not(target_arch = "wasm32"))] if use_editor { app.add_plugin(editor::EditorPlugin); } app.add_system(keyboard_util_system) .add_startup_system(setup) .add_system_set(SystemSet::on_update(AppState::Loading).with_system(loading_system)) .run(); } fn setup(mut commands: Commands, asset_server: Res) { let mut assets = LoadingAssets(Vec::new()); commands.insert_resource( assets.add(asset_server.load::("game.levels.json")), ); commands.insert_resource(assets.add(asset_server.load::("UacariLegacy-Thin.ttf"))); commands.insert_resource([ assets.add(asset_server.load::("bevy.png")), assets.add(asset_server.load("melty.png")), ]); commands.insert_resource(assets); commands.spawn_bundle(Camera2dBundle::default()); commands.insert_resource(AmbientLight { color: Color::WHITE, brightness: 0.6, }); } fn loading_system( asset_server: Res, use_editor: Res, assets: Res, mut app_state: ResMut>, ) { if asset_server.get_group_load_state(assets.0.iter().copied()) == LoadState::Loaded { app_state .replace(if use_editor.0 { AppState::Editor } else { AppState::Menu }) .ok(); } } fn keyboard_util_system(keyboard_input: Res>, mut windows: ResMut) { #[cfg(not(target_arch = "wasm32"))] { if keyboard_input.just_released(KeyCode::Escape) { std::process::exit(0); } if keyboard_input.just_pressed(KeyCode::F11) { if let Some(window) = windows.get_primary_mut() { window.set_mode(match window.mode() { WindowMode::Windowed => WindowMode::Fullscreen, _ => WindowMode::Windowed, }); } } } }