diff --git a/.cargo/config.toml b/.cargo/config.toml index 08e581a..b6be663 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,13 +3,21 @@ codegen-backend = true [profile.dev] codegen-backend = "cranelift" +opt-level = 1 [profile.dev.package."*"] codegen-backend = "llvm" +opt-level = 3 [profile.release] -lto = true -opt-level = 'z' +codegen-units = 1 +opt-level = "z" +lto = "thin" + +[profile.wasm-release] +inherits = "release" +opt-level = "s" +strip = "debuginfo" # for Linux [target.x86_64-unknown-linux-gnu] diff --git a/README.md b/README.md index f02acb6..141e794 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ This is a mono-repo I am working on containing many mini-games I am working on. +## Games + +* [tetris](src/bin/tetris/README.md) + ## Building a game You can build games in this project with `cargo` provided by Rust: diff --git a/assets/.gitattributes b/assets/.gitattributes new file mode 100644 index 0000000..86acde7 --- /dev/null +++ b/assets/.gitattributes @@ -0,0 +1,2 @@ +*.png filter=lfs diff=lfs merge=lfs -text +*.xcf filter=lfs diff=lfs merge=lfs -text diff --git a/assets/placeholder/tree.png b/assets/placeholder/tree.png new file mode 100644 index 0000000..a0400a5 --- /dev/null +++ b/assets/placeholder/tree.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fc14358306b2264df9bc03a9779975a0f9d9f83a5a8430e142d7f899b4638b65 +size 8095 diff --git a/assets/placeholder/tree.xcf b/assets/placeholder/tree.xcf new file mode 100644 index 0000000..c920314 --- /dev/null +++ b/assets/placeholder/tree.xcf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:61963aea26d3eaf7c1d888b3f1db950751bbfdb07ef67a2c6970466b27b94cca +size 16043 diff --git a/examples/sensors.rs b/examples/sensors.rs index 54fc71c..6b56a39 100644 --- a/examples/sensors.rs +++ b/examples/sensors.rs @@ -27,7 +27,8 @@ fn main() { control_ball, process_events, sync_resource_to_ui::.run_if(resource_changed::), - ).run_if(in_state(GameState::Main)), + ) + .run_if(in_state(LoadingState::Idle)), ) .run(); } @@ -204,19 +205,17 @@ fn process_events( (*flags == CollisionEventFlags::SENSOR).then_some(WithinBounds::Exit(*a, *b)) } }) - .for_each(|within_bounds| { - match within_bounds { - WithinBounds::Enter(a, b) => { - if let Ok(x) = areas.get(a) { - inside.0 = Some(x.clone()); - } else if let Ok(x) = areas.get(b) { - inside.0 = Some(x.clone()); - } + .for_each(|within_bounds| match within_bounds { + WithinBounds::Enter(a, b) => { + if let Ok(x) = areas.get(a) { + inside.0 = Some(x.clone()); + } else if let Ok(x) = areas.get(b) { + inside.0 = Some(x.clone()); } - WithinBounds::Exit(a, b) => { - if areas.contains(a) || areas.contains(b) { - inside.0 = None; - } + } + WithinBounds::Exit(a, b) => { + if areas.contains(a) || areas.contains(b) { + inside.0 = None; } } }) diff --git a/src/base_game.rs b/src/base_game.rs index 4c2278c..836b7a0 100644 --- a/src/base_game.rs +++ b/src/base_game.rs @@ -10,18 +10,10 @@ impl Plugin for BaseGamePlugin { .add_plugins(MeshPickingPlugin) .add_plugins(RapierPhysicsPlugin::::default()) .add_plugins(LoadingPlugin) - .add_systems(Startup, setup_camera) - .init_state::(); + .add_systems(Startup, setup_camera); } } -#[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)] -pub enum GameState { - #[default] - Loading, - Main, -} - /// System to toggle the visibility of entities based on their state pub fn toggle_state_visibility( mut q: Query<(Entity, &mut Visibility, &S)>, diff --git a/src/bin/hum/main.rs b/src/bin/hum/main.rs index 488c023..fa860fa 100644 --- a/src/bin/hum/main.rs +++ b/src/bin/hum/main.rs @@ -1,7 +1,5 @@ use games::*; fn main() { - App::new() - .add_plugins(BaseGamePlugin) - .run(); + App::new().add_plugins(BaseGamePlugin).run(); } diff --git a/src/bin/tetris/README.md b/src/bin/tetris/README.md new file mode 100644 index 0000000..e69de29 diff --git a/src/bin/tetris/main.rs b/src/bin/tetris/main.rs new file mode 100644 index 0000000..fa860fa --- /dev/null +++ b/src/bin/tetris/main.rs @@ -0,0 +1,5 @@ +use games::*; + +fn main() { + App::new().add_plugins(BaseGamePlugin).run(); +} diff --git a/src/bin/trees/main.rs b/src/bin/trees/main.rs new file mode 100644 index 0000000..a71278e --- /dev/null +++ b/src/bin/trees/main.rs @@ -0,0 +1,162 @@ +#![allow(clippy::type_complexity)] + +use games::*; + +fn main() { + App::new() + .add_plugins(BaseGamePlugin) + .insert_resource(ClearColor(WHITE.into())) + .add_systems( + Startup, + (init_trees, init_ui, position_camera.after(setup_camera)), + ) + .add_systems( + Update, + dialog_engine.run_if(input_just_pressed(KeyCode::KeyN)), + ) + .run(); +} + +#[derive(Component)] +struct Tree; + +fn init_trees( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + server: Res, +) { + let tree_card_mesh = meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(1.0))); + + let tree_image = server.load("placeholder/tree.png"); + + // Spawn placeholder tree (red) + { + let tree_material_red = materials.add(StandardMaterial { + base_color_texture: Some(tree_image.clone()), + base_color: RED.into(), + alpha_mode: AlphaMode::Blend, + ..default() + }); + let tree_transform_red = + Transform::from_xyz(-15.0, 0.0, 15.0).with_scale(Vec3::splat(10.0)); + commands.spawn(( + Tree, + Mesh3d(tree_card_mesh.clone()), + MeshMaterial3d(tree_material_red), + tree_transform_red, + Name::new("Red"), + )); + } + + // Spawn placeholder tree (green) + { + let tree_material_green = materials.add(StandardMaterial { + base_color_texture: Some(tree_image.clone()), + base_color: GREEN.into(), + alpha_mode: AlphaMode::Blend, + ..default() + }); + let tree_transform_green = + Transform::from_xyz(15.0, 0.0, 15.0).with_scale(Vec3::splat(10.0)); + commands.spawn(( + Tree, + Mesh3d(tree_card_mesh.clone()), + MeshMaterial3d(tree_material_green), + tree_transform_green, + Name::new("Green"), + )); + } + + // Spawn placeholder tree (blue) + { + let tree_material_blue = materials.add(StandardMaterial { + base_color_texture: Some(tree_image.clone()), + base_color: BLUE.into(), + alpha_mode: AlphaMode::Blend, + ..default() + }); + let tree_transform_blue = + Transform::from_xyz(0.0, 0.0, -15.0).with_scale(Vec3::splat(10.0)); + commands.spawn(( + Tree, + Mesh3d(tree_card_mesh.clone()), + MeshMaterial3d(tree_material_blue), + tree_transform_blue, + Name::new("Blue"), + )); + } +} + +#[derive(Component)] +struct DialogBox; + +fn init_ui(mut commands: Commands) { + commands.spawn(( + DialogBox, + BackgroundColor(BLACK.with_alpha(0.9).into()), + Node { + align_self: AlignSelf::End, + justify_self: JustifySelf::Center, + width: Val::Percent(98.0), + max_height: Val::Percent(25.0), + align_items: AlignItems::Center, + margin: UiRect::all(Val::Percent(1.0)), + padding: UiRect::all(Val::Percent(1.0)), + flex_direction: FlexDirection::Column, + ..default() + }, + )); +} + +fn position_camera(mut query: Query<&mut Transform, (With, With)>) { + use std::f32::consts::PI; + + query.iter_mut().for_each(|mut t| { + *t = Transform::from_xyz(0.0, 100.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y); + t.rotate_y(-PI * 0.5) + }) +} + +#[derive(Component)] +struct DialogOption; + +#[derive(Component)] +struct DialogLine; + +fn dialog_engine( + mut commands: Commands, + dialog_box: Single>, + mut idx: Local, +) { + let dialog: Vec> = vec![ + vec!["A", "B", "C"], + vec!["E", "F", "G"], + vec!["H", "I"], + vec!["J", "K"], + vec!["L"], + ]; + + info!("Show options: {:?}", dialog.get(*idx)); + + commands.entity(*dialog_box).with_children(|parent| { + if let Some(options) = dialog.get(*idx) { + options.iter().for_each(|option| { + parent + .spawn((Text::new(*option), Button, DialogOption)) + .observe(choose_dialog); + }); + } + }); + + *idx += 1; +} + +fn choose_dialog(trigger: Trigger>, mut commands: Commands) { + info!("Choosing dialog {:?}", trigger.target()); + commands + .entity(trigger.target()) + .remove::