diff --git a/Cargo.lock b/Cargo.lock index 0105d87..8c1947b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -588,25 +588,6 @@ dependencies = [ "glam", ] -[[package]] -name = "bevy_mod_picking" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db42ac84b1409452bbfa696d9071b9a7a2505c73620c939b758b5bf23573976a" -dependencies = [ - "bevy", - "bevy_mod_raycast", -] - -[[package]] -name = "bevy_mod_raycast" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aead49a20f5e694f4fb59c7312f9a1813b65a2a0ac2c385d53d40f25cae896f" -dependencies = [ - "bevy", -] - [[package]] name = "bevy_pbr" version = "0.8.1" @@ -930,7 +911,6 @@ dependencies = [ "bevy", "bevy-inspector-egui", "bevy_common_assets", - "bevy_mod_picking", "bevy_rapier2d", "cpal 0.14.0", "crossbeam-channel", @@ -939,7 +919,6 @@ dependencies = [ "rand_distr", "rapier2d", "serde", - "serde_json", "ticktock", ] @@ -1584,9 +1563,9 @@ dependencies = [ [[package]] name = "erased-serde" -version = "0.3.23" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54558e0ba96fbe24280072642eceb9d7d442e32c7ec0ea9e7ecd7b4ea2cf4e11" +checksum = "003000e712ad0f95857bd4d2ef8d1890069e06554101697d12050668b2f6f020" dependencies = [ "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 8fb6f94..cb38147 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] bevy = "0.8.1" bevy_common_assets = { version = "0.3.0", features = ["json"] } +bevy-inspector-egui = "0.12.1" bevy_rapier2d = "0.16.2" crossbeam-channel = "0.5.6" rand = "0.8.5" @@ -16,11 +17,8 @@ rapier2d = "0.14.0" serde = { version = "1.0.144", features = ["derive"] } [target."cfg(not(target_arch = \"wasm32\"))".dependencies] -bevy-inspector-egui = "0.12.1" -bevy_mod_picking = "0.9.0" cpal = "0.14.0" hexodsp = { git = "https://github.com/WeirdConstructor/HexoDSP", default-features = false } -serde_json = "1.0.85" ticktock = "0.8.0" [target."cfg(target_arch = \"wasm32\")".dependencies] diff --git a/README.md b/README.md index c452b76..17112e6 100644 --- a/README.md +++ b/README.md @@ -45,19 +45,6 @@ This game uses [HexoDSP](https://github.com/WeirdConstructor/HexoDSP) for audio The synthetizer matrix can be edited using [HexoSynth](https://github.com/WeirdConstructor/HexoSynth) visual editor. -## Develop - -Skip to level `N: u32` with the command `bevyjam `. - -Edit the level `N: u32` with the command `bevyjam e`. - -### Editor controls - -* **Select**: left click to select, click in void to deselect, CTRL+click to select many, CTRL+A to select all -* **Move selection**: arrows to move one step, Shift+arrows to move continuously -* **Move camera**: CTRL+arrows -* **Save**: CTRL+S - ## License GNU AGPL v3, CopyLeft 2022 Pascal Engélibert, Nixon Cheng diff --git a/assets/game.levels.json b/assets/game.levels.json index bca10de..549c17b 100644 --- a/assets/game.levels.json +++ b/assets/game.levels.json @@ -1,346 +1,119 @@ { - "levels": [ - { - "comment": "Movement tutorial", - "characters": [ - { - "pos": [ - 0.0, - -192.0 - ], - "color": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - }, - { - "pos": [ - -128.0, - -192.0 - ], - "color": [ - 0.0, - 1.0, - 0.0, - 1.0 - ] - }, - { - "pos": [ - 128.0, - -192.0 - ], - "color": [ - 0.0, - 0.0, - 1.0, - 1.0 - ] - } - ], - "platforms": [ - { - "pos": [ - 0.0, - -256.0 - ], - "size": [ - 800.0, - 16.0 - ] - } - ], - "absorbing_filters": [], - "rotating_filters": [], - "texts": [ - { - "pos": [ - 0.0, - 0.0 - ], - "font_size": 32.0, - "text": "Combine the colors to synthetize a white light.\nUse arrows to move." - } - ] - }, - { - "comment": "Switch tutorial", - "characters": [ - { - "pos": [ - 0.0, - -192.0 - ], - "color": [ - 0.0, - 1.0, - 0.0, - 1.0 - ] - }, - { - "pos": [ - -128.0, - -192.0 - ], - "color": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - }, - { - "pos": [ - 128.0, - 320.0 - ], - "color": [ - 0.0, - 0.0, - 1.0, - 1.0 - ] - } - ], - "platforms": [ - { - "pos": [ - 0.0, - -256.0 - ], - "size": [ - 800.0, - 16.0 - ] - }, - { - "pos": [ - 128.0, - 256.0 - ], - "size": [ - 96.0, - 16.0 - ] - } - ], - "absorbing_filters": [], - "rotating_filters": [], - "texts": [ - { - "pos": [ - 0.0, - 0.0 - ], - "font_size": 32.0, - "text": "Press Tab to switch." - } - ] - }, - { - "comment": "Absorbing filter tutorial", - "characters": [ - { - "pos": [ - -128.0, - -192.0 - ], - "color": [ - 1.0, - 0.64, - 0.0, - 1.0 - ] - }, - { - "pos": [ - 128.0, - -192.0 - ], - "color": [ - 0.0, - 0.37, - 1.0, - 1.0 - ] - } - ], - "platforms": [ - { - "pos": [ - 0.0, - -256.0 - ], - "size": [ - 800.0, - 16.0 - ] - }, - { - "pos": [ - 0.0, - -128.0 - ], - "size": [ - 800.0, - 16.0 - ] - } - ], - "absorbing_filters": [ - { - "pos": [ - 0.0, - -192.0 - ], - "size": [ - 16.0, - 112.0 - ], - "color": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - } - ], - "rotating_filters": [], - "texts": [ - { - "pos": [ - 0.0, - 0.0 - ], - "font_size": 32.0, - "text": "Press R to reset." - } - ] - }, - { - "comment": "Rotating filter tutorial", - "characters": [ - { - "pos": [ - 0.0, - -192.0 - ], - "color": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - }, - { - "pos": [ - -128.0, - -192.0 - ], - "color": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - }, - { - "pos": [ - 128.0, - -192.0 - ], - "color": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - } - ], - "platforms": [ - { - "pos": [ - 0.0, - -256.0 - ], - "size": [ - 800.0, - 16.0 - ] - } - ], - "absorbing_filters": [], - "rotating_filters": [ - { - "pos": [ - 0.0, - -64.0 - ], - "angle": 45.0 - } - ], - "texts": [ - { - "pos": [ - 0.0, - 0.0 - ], - "font_size": 32.0, - "text": "Let's rotate the hue!" - } - ] - }, - { - "comment": "Game over", - "characters": [ - { - "pos": [ - 0.0, - -64.0 - ], - "color": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - } - ], - "platforms": [ - { - "pos": [ - 0.0, - -256.0 - ], - "size": [ - 800.0, - 16.0 - ] - } - ], - "absorbing_filters": [], - "rotating_filters": [], - "texts": [ - { - "pos": [ - 0.0, - 128.0 - ], - "font_size": 48.0, - "text": "Thank you for playing!" - }, - { - "pos": [ - 0.0, - 0.0 - ], - "font_size": 32.0, - "text": "There is no more light to combine." - } - ] - } - ] + "levels": [ + { + "comment": "Movement tutorial", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]} + ], + "characters": [ + {"pos": [0, -192], "color": [1,0,0,1]}, + {"pos": [-128, -192], "color": [0,1,0,1]}, + {"pos": [128, -192], "color": [0,0,1,1]} + ], + "absorbing_filters": [], + "rotating_filters": [], + "texts": [ + { + "pos": [0, 0], + "font_size": 32, + "text": "Combine the colors to synthetize a white light.\nUse arrows to move." + } + ] + }, + { + "comment": "Switch tutorial", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]}, + {"pos": [128, 256], "size": [96, 16]} + ], + "characters": [ + {"pos": [0, -192], "color": [0,1,0,1]}, + {"pos": [-128, -192], "color": [1,0,0,1]}, + {"pos": [128, 320], "color": [0,0,1,1]} + ], + "absorbing_filters": [], + "rotating_filters": [], + "texts": [ + { + "pos": [0, 0], + "font_size": 32, + "text": "Press Tab to switch." + } + ] + }, + { + "comment": "Absorbing filter tutorial", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]}, + {"pos": [0, -128], "size": [800, 16]} + ], + "characters": [ + {"pos": [-128, -192], "color": [1,0.64,0,1]}, + {"pos": [128, -192], "color": [0,0.37,1,1]} + ], + "absorbing_filters": [ + { + "pos": [0, -192], + "size": [16, 112], + "color": [1,0,0,1] + } + ], + "rotating_filters": [], + "texts": [ + { + "pos": [0, 0], + "font_size": 32, + "text": "Press R to reset." + } + ] + }, + { + "comment": "Rotating filter tutorial", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]} + ], + "characters": [ + {"pos": [0, -192], "color": [1,0,0,1]}, + {"pos": [-128, -192], "color": [1,0,0,1]}, + {"pos": [128, -192], "color": [1,0,0,1]} + ], + "absorbing_filters": [], + "rotating_filters": [ + { + "pos": [0, -64], + "angle": 45 + } + ], + "texts": [ + { + "pos": [0, 0], + "font_size": 32, + "text": "Let's rotate the hue!" + } + ] + }, + { + "comment": "Game over", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]} + ], + "characters": [ + {"pos": [0, -64], "color": [1,0,0,1]} + ], + "absorbing_filters": [], + "rotating_filters": [], + "texts": [ + { + "pos": [0, 128], + "font_size": 48, + "text": "Thank you for playing!" + }, + { + "pos": [0, 0], + "font_size": 32, + "text": "There is no more light to combine." + } + ] + } + ] } \ No newline at end of file diff --git a/build-wasm.sh b/build-wasm.sh index 0a2d039..b9643dc 100644 --- a/build-wasm.sh +++ b/build-wasm.sh @@ -1,3 +1,2 @@ -cargo build --release --target wasm32-unknown-unknown || exit 1 -echo "==> wasm-bindgen..." -wasm-bindgen --out-name bevyjam --out-dir target --target web target/wasm32-unknown-unknown/release/bevyjam.wasm || exit 1 +cargo build --release --target wasm32-unknown-unknown +wasm-bindgen --out-name bevyjam --out-dir target --target web target/wasm32-unknown-unknown/release/bevyjam.wasm diff --git a/src/editor.rs b/src/editor.rs deleted file mode 100644 index 55c1592..0000000 --- a/src/editor.rs +++ /dev/null @@ -1,613 +0,0 @@ -#![allow(clippy::type_complexity)] -use crate::{levels::stored::*, AppState}; - -use bevy::{ - input::{keyboard::KeyCode, Input}, - prelude::{ - shape::{Circle, Quad}, - *, - }, - sprite::Mesh2dHandle, -}; -use bevy_mod_picking::*; - -pub struct EditorPlugin; - -impl Plugin for EditorPlugin { - fn build(&self, app: &mut App) { - app.add_event::() - .add_plugins(DefaultPickingPlugins) - .add_system_set(SystemSet::on_enter(AppState::Editor).with_system(setup)) - .add_system_set( - SystemSet::on_update(AppState::Editor) - .with_system(move_system) - .with_system(input_control_system) - .with_system(follow_ends_system), - ); - } -} - -// Events - -struct DragEndEvent(Entity); - -// Resources - -struct CharacterList(Vec); - -// Components - -#[derive(Component)] -struct Platform; - -#[derive(Component)] -struct Ends(Entity, Entity); - -#[derive(Component)] -struct Draggable; - -#[derive(Component)] -struct End(Entity); - -#[derive(Component)] -struct CharacterColor(Color); - -#[derive(Component)] -struct Size(Vec2); - -#[derive(Component)] -struct RotatingFilterAngle(f32); - -#[derive(Component)] -struct AbsorbingFilterColor(Color); - -// Bundles - -#[derive(Bundle)] -struct PlatformBundle { - #[bundle] - mesh: ColorMesh2dBundle, - size: Size, - platform: Platform, -} - -#[derive(Bundle)] -struct EndBundle { - #[bundle] - mesh: ColorMesh2dBundle, - #[bundle] - pickable: PickableBundle, - draggable: Draggable, - end: End, -} - -#[derive(Bundle)] -struct CharacterBundle { - #[bundle] - mesh: ColorMesh2dBundle, - color: CharacterColor, - #[bundle] - pickable: PickableBundle, - draggable: Draggable, -} - -#[derive(Bundle)] -struct AbsorbingFilterBundle { - #[bundle] - mesh: ColorMesh2dBundle, - size: Size, - color: AbsorbingFilterColor, -} - -#[derive(Bundle)] -struct RotatingFilterBundle { - #[bundle] - mesh: ColorMesh2dBundle, - angle: RotatingFilterAngle, - #[bundle] - pickable: PickableBundle, - draggable: Draggable, -} - -// Functions - -fn spawn_platform( - commands: &mut Commands, - meshes: &mut ResMut>, - materials: &mut ResMut>, - - transform: Transform, - size: Vec2, -) { - let platform = commands - .spawn_bundle(PlatformBundle { - mesh: ColorMesh2dBundle { - mesh: meshes.add(Mesh::from(Quad { size, flip: false })).into(), - material: materials.add(ColorMaterial::from(Color::GRAY)), - transform, - ..default() - }, - size: Size(size), - platform: Platform, - }) - .id(); - let ends = Ends( - commands - .spawn_bundle(EndBundle { - mesh: ColorMesh2dBundle { - mesh: meshes - .add(Mesh::from(Circle { - radius: 8., - vertices: 12, - })) - .into(), - material: materials.add(ColorMaterial::from(Color::rgba(1., 1., 0., 0.7))), - transform: Transform::from_xyz( - transform.translation.x - size.x / 2., - transform.translation.y - size.y / 2., - 0.5, - ), - ..default() - }, - pickable: PickableBundle::default(), - draggable: Draggable, - end: End(platform), - }) - .id(), - commands - .spawn_bundle(EndBundle { - mesh: ColorMesh2dBundle { - mesh: meshes - .add(Mesh::from(Circle { - radius: 8., - vertices: 12, - })) - .into(), - material: materials.add(ColorMaterial::from(Color::rgba(1., 1., 0., 0.7))), - transform: Transform::from_xyz( - transform.translation.x + size.x / 2., - transform.translation.y + size.y / 2., - 0.5, - ), - ..default() - }, - pickable: PickableBundle::default(), - draggable: Draggable, - end: End(platform), - }) - .id(), - ); - commands.entity(platform).insert(ends); -} - -fn spawn_character( - commands: &mut Commands, - meshes: &mut ResMut>, - materials: &mut ResMut>, - asset_server: &Res, - - transform: Transform, - color: Color, - index: usize, -) -> Entity { - let font = asset_server.get_handle("UacariLegacy-Thin.ttf"); - commands - .spawn_bundle(CharacterBundle { - mesh: ColorMesh2dBundle { - mesh: meshes - .add(Mesh::from(Quad { - size: Vec2 { x: 64., y: 64. }, - flip: false, - })) - .into(), - material: materials.add(ColorMaterial::from(color)), - transform, - ..default() - }, - color: CharacterColor(color), - pickable: PickableBundle::default(), - draggable: Draggable, - }) - .with_children(|c| { - c.spawn_bundle(Text2dBundle { - text: Text::from_section( - &index.to_string(), - TextStyle { - font: font.clone(), - font_size: 32., - color: Color::WHITE, - }, - ) - .with_alignment(TextAlignment::CENTER), - transform: Transform::from_xyz(0., 0., 1.), - ..Default::default() - }); - }) - .id() -} - -fn spawn_absorbing_filter( - commands: &mut Commands, - meshes: &mut ResMut>, - materials: &mut ResMut>, - - transform: Transform, - size: Vec2, - color: Color, -) { - let absorbing_filter = commands - .spawn_bundle(AbsorbingFilterBundle { - mesh: ColorMesh2dBundle { - mesh: meshes.add(Mesh::from(Quad { size, flip: false })).into(), - material: materials.add(ColorMaterial::from(color)), - transform, - ..default() - }, - size: Size(size), - color: AbsorbingFilterColor(color), - }) - .id(); - let ends = Ends( - commands - .spawn_bundle(EndBundle { - mesh: ColorMesh2dBundle { - mesh: meshes - .add(Mesh::from(Circle { - radius: 8., - vertices: 12, - })) - .into(), - material: materials.add(ColorMaterial::from(Color::rgba(1., 1., 0., 0.7))), - transform: Transform::from_xyz( - transform.translation.x - size.x / 2., - transform.translation.y - size.y / 2., - 0.5, - ), - ..default() - }, - pickable: PickableBundle::default(), - draggable: Draggable, - end: End(absorbing_filter), - }) - .id(), - commands - .spawn_bundle(EndBundle { - mesh: ColorMesh2dBundle { - mesh: meshes - .add(Mesh::from(Circle { - radius: 8., - vertices: 12, - })) - .into(), - material: materials.add(ColorMaterial::from(Color::rgba(1., 1., 0., 0.7))), - transform: Transform::from_xyz( - transform.translation.x + size.x / 2., - transform.translation.y + size.y / 2., - 0.5, - ), - ..default() - }, - pickable: PickableBundle::default(), - draggable: Draggable, - end: End(absorbing_filter), - }) - .id(), - ); - commands.entity(absorbing_filter).insert(ends); -} - -fn spawn_rotating_filter( - commands: &mut Commands, - meshes: &mut ResMut>, - materials: &mut ResMut>, - asset_server: &Res, - - transform: Transform, - angle: f32, -) -> Entity { - let font = asset_server.get_handle("UacariLegacy-Thin.ttf"); - commands - .spawn_bundle(RotatingFilterBundle { - mesh: ColorMesh2dBundle { - mesh: meshes - .add(Mesh::from(Circle { - radius: 32., - vertices: 36, - })) - .into(), - material: materials.add(ColorMaterial::from(Color::WHITE)), - transform, - ..default() - }, - angle: RotatingFilterAngle(angle), - pickable: PickableBundle::default(), - draggable: Draggable, - }) - .with_children(|c| { - c.spawn_bundle(Text2dBundle { - text: Text::from_section( - &angle.to_string(), - TextStyle { - font: font.clone(), - font_size: 32., - color: Color::RED, - }, - ) - .with_alignment(TextAlignment::CENTER), - transform: Transform::from_xyz(0., 0., 1.), - ..Default::default() - }); - }) - .id() -} - -fn spawn_stored_level( - commands: &mut Commands, - meshes: &mut ResMut>, - materials: &mut ResMut>, - asset_server: &Res, - - stored_level: &StoredLevel, -) { - for platform in stored_level.platforms.iter() { - spawn_platform( - commands, - meshes, - materials, - Transform::from_xyz(platform.pos.x, platform.pos.y, 0.), - platform.size, - ); - } - - let mut character_list = Vec::new(); - for (i, character) in stored_level.characters.iter().enumerate() { - character_list.push(spawn_character( - commands, - meshes, - materials, - asset_server, - Transform::from_xyz(character.pos.x, character.pos.y, 0.), - character.color.into(), - i, - )); - } - commands.insert_resource(CharacterList(character_list)); - - for absorbing_filter in stored_level.absorbing_filters.iter() { - spawn_absorbing_filter( - commands, - meshes, - materials, - Transform::from_xyz(absorbing_filter.pos.x, absorbing_filter.pos.y, 0.), - absorbing_filter.size, - absorbing_filter.color.into(), - ); - } - - for rotating_filter in stored_level.rotating_filters.iter() { - spawn_rotating_filter( - commands, - meshes, - materials, - asset_server, - Transform::from_xyz(rotating_filter.pos.x, rotating_filter.pos.y, 0.), - rotating_filter.angle, - ); - } -} - -fn save_level( - level_id: &Res, - stored_levels_assets: &mut ResMut>, - stored_levels_handle: &Res>, - character_list: &Res, - character_query: &Query<(&Transform, &CharacterColor), Without>, - platform_query: &Query<(&Transform, &Size), With>, - absorbing_filter_query: &Query<(&Transform, &Size, &AbsorbingFilterColor), Without>, - rotating_filter_query: &Query< - (&Transform, &RotatingFilterAngle), - (Without, Without), - >, -) { - let stored_levels = stored_levels_assets.get_mut(stored_levels_handle).unwrap(); - if let Some(stored_level) = stored_levels.levels.get_mut(level_id.0 .0 as usize) { - stored_level.platforms.clear(); - for (transform, size) in platform_query.iter() { - stored_level.platforms.push(StoredPlatform { - pos: Vec2 { - x: transform.translation.x, - y: transform.translation.y, - }, - size: size.0, - }) - } - - stored_level.characters.clear(); - for entity in character_list.0.iter() { - if let Ok((transform, color)) = character_query.get(*entity) { - stored_level.characters.push(StoredCharacter { - pos: Vec2 { - x: transform.translation.x, - y: transform.translation.y, - }, - color: color.0.into(), - }) - } - } - - stored_level.absorbing_filters.clear(); - for (transform, size, color) in absorbing_filter_query.iter() { - stored_level.absorbing_filters.push(StoredAbsorbingFilter { - pos: Vec2 { - x: transform.translation.x, - y: transform.translation.y, - }, - size: size.0, - color: color.0.into(), - }) - } - - stored_level.rotating_filters.clear(); - for (transform, angle) in rotating_filter_query.iter() { - stored_level.rotating_filters.push(StoredRotatingFilter { - pos: Vec2 { - x: transform.translation.x, - y: transform.translation.y, - }, - angle: angle.0, - }) - } - } else { - return; - } - match std::fs::OpenOptions::new() - .write(true) - .truncate(true) - .open("assets/game.levels.json") - { - Ok(mut file) => { - serde_json::to_writer_pretty(&mut file, stored_levels).unwrap(); - println!("Saved!"); - } - Err(e) => eprintln!("Error writing levels file: {:?}", e), - } -} - -// Systems - -fn setup( - mut commands: Commands, - mut meshes: ResMut>, - mut materials: ResMut>, - camera_query: Query>, - level_id: Res, - stored_levels_assets: Res>, - stored_levels_handle: Res>, - asset_server: Res, -) { - commands - .entity(camera_query.single()) - .insert_bundle(PickingCameraBundle::default()); - - if let Some(stored_level) = stored_levels_assets - .get(&stored_levels_handle) - .unwrap() - .levels - .get(level_id.0 .0 as usize) - { - spawn_stored_level( - &mut commands, - &mut meshes, - &mut materials, - &asset_server, - stored_level, - ); - } -} - -fn input_control_system( - keyboard_input: Res>, - level_id: Res, - mut stored_levels_assets: ResMut>, - stored_levels_handle: Res>, - character_list: Res, - character_query: Query<(&Transform, &CharacterColor), Without>, - platform_query: Query<(&Transform, &Size), With>, - absorbing_filter_query: Query<(&Transform, &Size, &AbsorbingFilterColor), Without>, - rotating_filter_query: Query< - (&Transform, &RotatingFilterAngle), - (Without, Without), - >, -) { - if keyboard_input.just_released(KeyCode::S) - && (keyboard_input.pressed(KeyCode::LControl) || keyboard_input.pressed(KeyCode::RControl)) - { - save_level( - &level_id, - &mut stored_levels_assets, - &stored_levels_handle, - &character_list, - &character_query, - &platform_query, - &absorbing_filter_query, - &rotating_filter_query, - ); - } -} - -fn move_system( - keyboard_input: Res>, - mut camera_query: Query<&mut Transform, (With, Without)>, - mut drag_query: Query<(&mut Transform, &Selection, Option<&End>), With>, - mut drag_end_event: EventWriter, -) { - if keyboard_input.pressed(KeyCode::LControl) || keyboard_input.pressed(KeyCode::RControl) { - let mut transform = camera_query.single_mut(); - let drag = Vec3 { - x: (keyboard_input.pressed(KeyCode::Right) as i8 - - keyboard_input.pressed(KeyCode::Left) as i8) as _, - y: (keyboard_input.pressed(KeyCode::Up) as i8 - - keyboard_input.pressed(KeyCode::Down) as i8) as _, - z: 0., - } * 8.; - transform.translation += drag; - return; - } - - let drag = if keyboard_input.pressed(KeyCode::LShift) || keyboard_input.pressed(KeyCode::RShift) - { - Vec3 { - x: (keyboard_input.pressed(KeyCode::Right) as i8 - - keyboard_input.pressed(KeyCode::Left) as i8) as _, - y: (keyboard_input.pressed(KeyCode::Up) as i8 - - keyboard_input.pressed(KeyCode::Down) as i8) as _, - z: 0., - } - } else { - Vec3 { - x: (keyboard_input.just_pressed(KeyCode::Right) as i8 - - keyboard_input.just_pressed(KeyCode::Left) as i8) as _, - y: (keyboard_input.just_pressed(KeyCode::Up) as i8 - - keyboard_input.just_pressed(KeyCode::Down) as i8) as _, - z: 0., - } - } * 8.; - if drag != Vec3::ZERO { - for (mut transform, selection, end) in drag_query.iter_mut() { - if selection.selected() { - transform.translation += drag; - if let Some(End(entity)) = end { - drag_end_event.send(DragEndEvent(*entity)); - } - } - } - } -} - -fn follow_ends_system( - mut meshes: ResMut>, - mut follower_query: Query<(&mut Transform, &mut Mesh2dHandle, &mut Size, &Ends)>, - end_query: Query<&Transform, Without>, - mut drag_end_event: EventReader, -) { - for DragEndEvent(entity) in drag_end_event.iter() { - if let Ok((mut transform, mut mesh, mut size, Ends(end1, end2))) = - follower_query.get_mut(*entity) - { - if let (Ok(end1), Ok(end2)) = (end_query.get(*end1), end_query.get(*end2)) { - transform.translation.x = (end1.translation.x + end2.translation.x) / 2.; - transform.translation.y = (end1.translation.y + end2.translation.y) / 2.; - size.0 = Vec2 { - x: (end2.translation.x - end1.translation.x).abs(), - y: (end2.translation.y - end1.translation.y).abs(), - }; - *mesh = meshes - .add(Mesh::from(Quad { - size: size.0, - flip: false, - })) - .into(); - } - } - } -} diff --git a/src/game.rs b/src/game.rs index 32f3bb0..102a44e 100644 --- a/src/game.rs +++ b/src/game.rs @@ -471,13 +471,14 @@ fn move_camera( let size: Vec2 = camera.logical_viewport_size().unwrap(); let half_height: f32 = size.y * 0.5; - let mut target_translation = character_transform.translation; + let mut target_translation = character_transform.translation; // prevent camera from going too low target_translation.y = target_translation.y.max(half_height - MARGIN); - camera_transform.translation = camera_transform - .translation - .lerp(target_translation, time.delta_seconds() * FOLLOW_SPEED); + camera_transform.translation = camera_transform.translation.lerp( + target_translation, + time.delta_seconds() * FOLLOW_SPEED, + ); // always make sure that camera is away from the object in order to render them camera_transform.translation.z = 999.0; diff --git a/src/levels.rs b/src/levels.rs index f99b429..c131e63 100644 --- a/src/levels.rs +++ b/src/levels.rs @@ -1,7 +1,5 @@ #![allow(clippy::too_many_arguments)] -pub use stored::*; - use crate::game::*; use bevy::{prelude::*, reflect::TypeUuid}; @@ -57,6 +55,60 @@ pub fn post_setup_level( } } +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "1fbba930-644b-0d62-2514-4b302b945327"] +pub struct StoredLevels { + levels: Vec, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "a1464a30-1f57-a654-d56c-ded41032af0b"] +pub struct StoredLevel { + pub comment: String, + pub characters: Vec, + pub platforms: Vec, + pub absorbing_filters: Vec, + pub rotating_filters: Vec, + pub texts: Vec, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "1c798f8c-ef15-c528-693e-76becdef6b10"] +pub struct StoredCharacter { + pub pos: Vec2, + pub color: Vec4, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "31696095-59de-93be-b5e9-333c2afbc900"] +pub struct StoredPlatform { + pub pos: Vec2, + pub size: Vec2, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "bcad7fff-0605-c4e3-3cd4-42d5bbaad926"] +pub struct StoredAbsorbingFilter { + pub pos: Vec2, + pub size: Vec2, + pub color: Vec4, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "fa2843f2-6e34-601b-6c46-4827b0370b3f"] +pub struct StoredRotatingFilter { + pub pos: Vec2, + pub angle: f32, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "72f6321a-f01f-6eea-9b17-3159837a2fd3"] +pub struct StoredText { + pub pos: Vec2, + pub font_size: f32, + pub text: String, +} + pub fn spawn_stored_level( commands: &mut Commands, character_meshes: &Res, @@ -127,61 +179,3 @@ pub fn spawn_stored_level( .insert(Level); } } - -pub mod stored { - use super::*; - - #[derive(Deserialize, Serialize, TypeUuid)] - #[uuid = "1fbba930-644b-0d62-2514-4b302b945327"] - pub struct StoredLevels { - pub levels: Vec, - } - - #[derive(Deserialize, Serialize, TypeUuid)] - #[uuid = "a1464a30-1f57-a654-d56c-ded41032af0b"] - pub struct StoredLevel { - pub comment: String, - pub characters: Vec, - pub platforms: Vec, - pub absorbing_filters: Vec, - pub rotating_filters: Vec, - pub texts: Vec, - } - - #[derive(Deserialize, Serialize, TypeUuid)] - #[uuid = "1c798f8c-ef15-c528-693e-76becdef6b10"] - pub struct StoredCharacter { - pub pos: Vec2, - pub color: Vec4, - } - - #[derive(Deserialize, Serialize, TypeUuid)] - #[uuid = "31696095-59de-93be-b5e9-333c2afbc900"] - pub struct StoredPlatform { - pub pos: Vec2, - pub size: Vec2, - } - - #[derive(Deserialize, Serialize, TypeUuid)] - #[uuid = "bcad7fff-0605-c4e3-3cd4-42d5bbaad926"] - pub struct StoredAbsorbingFilter { - pub pos: Vec2, - pub size: Vec2, - pub color: Vec4, - } - - #[derive(Deserialize, Serialize, TypeUuid)] - #[uuid = "fa2843f2-6e34-601b-6c46-4827b0370b3f"] - pub struct StoredRotatingFilter { - pub pos: Vec2, - pub angle: f32, - } - - #[derive(Deserialize, Serialize, TypeUuid)] - #[uuid = "72f6321a-f01f-6eea-9b17-3159837a2fd3"] - pub struct StoredText { - pub pos: Vec2, - pub font_size: f32, - pub text: String, - } -} diff --git a/src/main.rs b/src/main.rs index 7976caa..410492a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,5 @@ -#![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; @@ -11,7 +7,6 @@ mod menu; mod particle_effect; use bevy::{ - asset::{Asset, HandleId, LoadState}, prelude::*, window::{WindowId, WindowMode}, }; @@ -20,22 +15,9 @@ 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() { @@ -46,45 +28,32 @@ fn main() { 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"), - ) - }; + let first_level = game::LevelId( + std::env::args() + .nth(1) + .map_or(0, |s| s.parse().unwrap_or(0)), + ); #[cfg(target_arch = "wasm32")] - let (first_level, use_editor) = (game::LevelId(0), false); + let first_level = game::LevelId(0); - let mut app = App::new(); - app.insert_resource(Msaa { samples: 4 }) + App::new() + .insert_resource(Msaa { samples: 4 }) .insert_resource(audio_event_sender) - .insert_resource(UseEditor(use_editor)) - .add_state(AppState::Loading) + .add_state(AppState::Menu) .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_plugin(RapierPhysicsPlugin::::pixels_per_meter(64.0)) + //.add_plugin(RapierDebugRenderPlugin::default()) + .add_plugin(menu::MenuPlugin) + .add_plugin(game::GamePlugin) + .add_plugin(particle_effect::ParticleEffectPlugin) + //.add_plugin(bevy_inspector_egui::WorldInspectorPlugin::new()) + .add_system(keyboard_util_system) .add_startup_system(setup) - .add_system_set(SystemSet::on_update(AppState::Loading).with_system(loading_system)) .run(); } @@ -94,13 +63,9 @@ fn setup(mut commands: Commands, mut windows: ResMut, asset_server: Res .unwrap() .set_title(String::from("Bevyjam")); - 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"))); - commands.insert_resource(assets); + commands.insert_resource(asset_server.load::("game.levels.json")); + commands.insert_resource(asset_server.load::("UacariLegacy-Thin.ttf")); + commands.insert_resource(asset_server.load::("bevy.png")); commands.spawn_bundle(Camera2dBundle::default()); commands.insert_resource(AmbientLight { @@ -109,23 +74,6 @@ fn setup(mut commands: Commands, mut windows: ResMut, asset_server: Res }); } -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"))] { diff --git a/src/particle_effect.rs b/src/particle_effect.rs index b711548..c1ee094 100644 --- a/src/particle_effect.rs +++ b/src/particle_effect.rs @@ -44,6 +44,7 @@ impl FromWorld for ParticleMesh { } } +#[derive(bevy_inspector_egui::Inspectable)] pub struct ParticleEffectResource { pub translation: Vec3, pub prev_translation: Vec3,