From bb6827b0f01225c7e6d9576d8df5ba40d9ec9297 Mon Sep 17 00:00:00 2001 From: Back777space Date: Sun, 6 Apr 2025 13:38:16 +0200 Subject: [PATCH 1/3] start flashlight working --- src/main.rs | 16 +++++++-------- src/player.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index cf1bac4..48bedad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,7 @@ fn main() { RapierPhysicsPlugin::::default(), RapierDebugRenderPlugin::default(), player::plugin, - debugging::plugin + // debugging::plugin )) .init_state::() .add_systems(OnEnter(GameState::Playing), setup) @@ -62,11 +62,11 @@ fn setup( Collider::cuboid(0.5, 0.5, 0.5), )); // light - commands.spawn(( - PointLight { - shadows_enabled: true, - ..default() - }, - Transform::from_xyz(4.0, 8.0, 4.0), - )); + // commands.spawn(( + // PointLight { + // shadows_enabled: true, + // ..default() + // }, + // Transform::from_xyz(4.0, 8.0, 4.0), + // )); } diff --git a/src/player.rs b/src/player.rs index be909ac..369fcb7 100644 --- a/src/player.rs +++ b/src/player.rs @@ -51,12 +51,21 @@ impl Default for HeadBob { #[derive(Component, Debug)] pub struct BaseTransform(pub Transform); +#[derive(Debug, Component)] +pub struct Flashlight; + pub fn plugin(app: &mut App) { app.add_plugins(toolbar::plugin) .add_systems(OnEnter(GameState::Playing), (init_player, hide_cursor)) .add_systems( Update, - (move_camera, handle_input, apply_head_bob, on_resize_system).run_if(in_state(GameState::Playing)), + ( + move_camera, + handle_input, + apply_head_bob, + on_resize_system, + handle_flashlight, + ).run_if(in_state(GameState::Playing)), ) .add_systems( FixedUpdate, @@ -112,6 +121,7 @@ pub fn init_player( RenderLayers::layer(STATIC_LAYER), )); + // pitslamp sprite let window = window.single(); let transform = flashlight_base_transform(window.width(), window.height()); parent.spawn(( @@ -120,6 +130,19 @@ pub fn init_player( transform, RenderLayers::layer(STATIC_LAYER), )); + + // feitelijke pitslamp + parent.spawn(( + Flashlight, + PointLight { + intensity: 0.0, // start with the light off + color: Color::WHITE, + shadows_enabled: true, + ..default() + }, + Transform::from_xyz(1.0, 2.0, 0.0), + GlobalTransform::default(), + )); }); } @@ -221,10 +244,10 @@ pub fn handle_input( } else { player.speed_factor = 1.0; } - if keyboard_input.pressed(KeyCode::KeyE) { + if keyboard_input.just_pressed(KeyCode::KeyE) { *action = PlayerAction::Interact } - if keyboard_input.pressed(KeyCode::KeyA) { + if keyboard_input.just_pressed(KeyCode::KeyF) { *action = PlayerAction::ToggleFlashlight; } @@ -295,7 +318,7 @@ pub fn apply_head_bob( if is_moving { transform.translation.x = horizontal_offset; } else { - // decrease bobbing magnitued + // decrease bobbing magnitude transform.translation.x *= 0.8; } } @@ -320,4 +343,25 @@ pub fn apply_head_bob( } } } -} \ No newline at end of file +} + +pub fn handle_flashlight( + mut player_query: Query<(&mut PlayerAction, Entity), With>, + mut flashlight_query: Query<&mut PointLight, With>, +) { + let Ok((mut action, player_entity)) = player_query.get_single_mut() else { + return; + }; + if *action != PlayerAction::ToggleFlashlight { + return; + } + if let Ok(mut point_light) = flashlight_query.get_mut(player_entity) { + point_light.intensity = if point_light.intensity > 0.0 { + 0.0 + } else { + 100_000.0 + }; + println!("Flashlight {}", if point_light.intensity > 0.0 { "on" } else { "off" }); + } + *action = PlayerAction::Move; +} From 99041827d4d737b7d2fa771442274225b2080c7e Mon Sep 17 00:00:00 2001 From: Back777space Date: Sun, 6 Apr 2025 14:34:29 +0200 Subject: [PATCH 2/3] flashlight working --- src/player.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/player.rs b/src/player.rs index 369fcb7..788107d 100644 --- a/src/player.rs +++ b/src/player.rs @@ -65,6 +65,7 @@ pub fn plugin(app: &mut App) { apply_head_bob, on_resize_system, handle_flashlight, + // handle_flashlight_movement, ).run_if(in_state(GameState::Playing)), ) .add_systems( @@ -134,13 +135,17 @@ pub fn init_player( // feitelijke pitslamp parent.spawn(( Flashlight, - PointLight { - intensity: 0.0, // start with the light off + SpotLight { + intensity: 0.0, color: Color::WHITE, - shadows_enabled: true, + range: 4.0, + outer_angle: 30.0_f32.to_radians(), // wide cone for flashlight + inner_angle: 10.0_f32.to_radians(), // narrower inner cone + shadows_enabled: false, // (set to true for realism) + radius: 0.35, // low value for hard light ..default() }, - Transform::from_xyz(1.0, 2.0, 0.0), + Transform::from_xyz(0.0, -0.15, 0.5), GlobalTransform::default(), )); }); @@ -217,6 +222,8 @@ pub fn handle_input( mut query: Query<(&Transform, &mut PlayerInput, &mut PlayerAction, &mut Player), With>, ) { for (transform, mut input, mut action, mut player) in query.iter_mut() { + *action = PlayerAction::Move; + let forward = transform.forward(); let right = transform.right(); let mut movement_direction = Vec3::ZERO; @@ -346,22 +353,21 @@ pub fn apply_head_bob( } pub fn handle_flashlight( - mut player_query: Query<(&mut PlayerAction, Entity), With>, - mut flashlight_query: Query<&mut PointLight, With>, + player_query: Query<&PlayerAction, With>, + mut flashlight_query: Query<&mut SpotLight, With>, ) { - let Ok((mut action, player_entity)) = player_query.get_single_mut() else { + let Ok(action) = player_query.get_single() else { return; }; if *action != PlayerAction::ToggleFlashlight { return; } - if let Ok(mut point_light) = flashlight_query.get_mut(player_entity) { - point_light.intensity = if point_light.intensity > 0.0 { + if let Ok(mut spotlight) = flashlight_query.get_single_mut() { + spotlight.intensity = if spotlight.intensity > 0.0 { 0.0 } else { - 100_000.0 + 300_000.0 }; - println!("Flashlight {}", if point_light.intensity > 0.0 { "on" } else { "off" }); + println!("Flashlight {}", if spotlight.intensity > 0.0 { "on" } else { "off" }); } - *action = PlayerAction::Move; } From f538c597f76e332969f705f434cc76cb00704a53 Mon Sep 17 00:00:00 2001 From: Back777space Date: Sun, 6 Apr 2025 15:41:22 +0200 Subject: [PATCH 3/3] flashlight sound and animation --- Cargo.lock | 193 ++++++++++++++++++++++++++--- Cargo.toml | 1 + assets/audio/flashlight-switch.mp3 | Bin 0 -> 30720 bytes assets/audio/flashlight-switch.ogg | Bin 0 -> 9958 bytes assets/main.assets.ron | 2 + src/asset_loading/mod.rs | 34 ++--- src/main.rs | 2 +- src/player.rs | 50 +++++++- 8 files changed, 246 insertions(+), 36 deletions(-) create mode 100644 assets/audio/flashlight-switch.mp3 create mode 100644 assets/audio/flashlight-switch.ogg diff --git a/Cargo.lock b/Cargo.lock index 92620f2..c04da23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -147,6 +147,7 @@ dependencies = [ "bevy", "bevy_asset_loader", "bevy_egui", + "bevy_kira_audio", "bevy_rapier3d", ] @@ -168,7 +169,7 @@ dependencies = [ "ndk-context", "ndk-sys 0.6.0+11769913", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -593,7 +594,7 @@ dependencies = [ "bevy", "ron", "serde", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -925,6 +926,20 @@ dependencies = [ "bevy_winit", ] +[[package]] +name = "bevy_kira_audio" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c929e59bffeb04011aab93880623163c0f8c31c7e99d752d74ba935a53546731" +dependencies = [ + "anyhow", + "bevy", + "kira", + "parking_lot", + "thiserror 2.0.12", + "uuid", +] + [[package]] name = "bevy_log" version = "0.15.3" @@ -1608,7 +1623,7 @@ dependencies = [ "polling", "rustix", "slab", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2141,7 +2156,7 @@ dependencies = [ "const_panic", "encase_derive", "glam", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2164,6 +2179,15 @@ dependencies = [ "syn", ] +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "epaint" version = "0.31.1" @@ -2518,6 +2542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee" dependencies = [ "bytemuck", + "mint", "rand", "serde", ] @@ -2612,7 +2637,7 @@ checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" dependencies = [ "log", "presser", - "thiserror", + "thiserror 1.0.69", "windows 0.58.0", ] @@ -3020,7 +3045,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -3074,6 +3099,22 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kira" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a9f9dff5e262540b628b00d5e1a772270a962d6869f8695bb24832ff3b394" +dependencies = [ + "cpal", + "glam", + "mint", + "paste", + "ringbuf", + "send_wrapper", + "symphonia", + "triple_buffer", +] + [[package]] name = "ktx2" version = "0.3.0" @@ -3295,6 +3336,12 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mint" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" + [[package]] name = "naga" version = "23.1.0" @@ -3313,7 +3360,7 @@ dependencies = [ "rustc-hash 1.1.0", "spirv", "termcolor", - "thiserror", + "thiserror 1.0.69", "unicode-xid", ] @@ -3332,7 +3379,7 @@ dependencies = [ "regex", "regex-syntax 0.8.5", "rustc-hash 1.1.0", - "thiserror", + "thiserror 1.0.69", "tracing", "unicode-ident", ] @@ -3376,7 +3423,7 @@ dependencies = [ "log", "ndk-sys 0.5.0+25.2.9519653", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3391,7 +3438,7 @@ dependencies = [ "ndk-sys 0.6.0+11769913", "num_enum", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3974,7 +4021,7 @@ dependencies = [ "slab", "smallvec", "spade", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4282,7 +4329,7 @@ dependencies = [ "profiling", "rustc-hash 2.1.1", "simba", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4315,7 +4362,7 @@ dependencies = [ "rand_chacha", "simd_helpers", "system-deps", - "thiserror", + "thiserror 1.0.69", "v_frame", "wasm-bindgen", ] @@ -4457,6 +4504,15 @@ version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +[[package]] +name = "ringbuf" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79abed428d1fd2a128201cec72c5f6938e2da607c6f3745f769fabea399d950a" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "robust" version = "1.1.0" @@ -4471,7 +4527,7 @@ checksum = "6006a627c1a38d37f3d3a85c6575418cfe34a5392d60a686d0071e1c8d427acb" dependencies = [ "cpal", "lewton", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4753,7 +4809,7 @@ dependencies = [ "log", "memmap2", "rustix", - "thiserror", + "thiserror 1.0.69", "wayland-backend", "wayland-client", "wayland-csd-frame", @@ -4835,6 +4891,77 @@ dependencies = [ "zeno", ] +[[package]] +name = "symphonia" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9" +dependencies = [ + "lazy_static", + "symphonia-codec-vorbis", + "symphonia-core", + "symphonia-format-ogg", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-codec-vorbis" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a98765fb46a0a6732b007f7e2870c2129b6f78d87db7987e6533c8f164a9f30" +dependencies = [ + "log", + "symphonia-core", + "symphonia-utils-xiph", +] + +[[package]] +name = "symphonia-core" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "798306779e3dc7d5231bd5691f5a813496dc79d3f56bf82e25789f2094e022c3" +dependencies = [ + "arrayvec", + "bitflags 1.3.2", + "bytemuck", + "lazy_static", + "log", +] + +[[package]] +name = "symphonia-format-ogg" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada3505789516bcf00fc1157c67729eded428b455c27ca370e41f4d785bfa931" +dependencies = [ + "log", + "symphonia-core", + "symphonia-metadata", + "symphonia-utils-xiph", +] + +[[package]] +name = "symphonia-metadata" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc622b9841a10089c5b18e99eb904f4341615d5aa55bbf4eedde1be721a4023c" +dependencies = [ + "encoding_rs", + "lazy_static", + "log", + "symphonia-core", +] + +[[package]] +name = "symphonia-utils-xiph" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "484472580fa49991afda5f6550ece662237b00c6f562c7d9638d1b086ed010fe" +dependencies = [ + "symphonia-core", + "symphonia-metadata", +] + [[package]] name = "syn" version = "2.0.100" @@ -4926,7 +5053,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -4940,6 +5076,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -5141,6 +5288,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "triple_buffer" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de7a7d39da903eaef0d0fd14aae8c8c36cdd7dc1d5a251f88c84b676e8dc0a14" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "ttf-parser" version = "0.20.0" @@ -5271,6 +5427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ "getrandom 0.2.15", + "rand", "serde", ] @@ -5602,7 +5759,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror", + "thiserror 1.0.69", "wgpu-hal", "wgpu-types", ] @@ -5644,7 +5801,7 @@ dependencies = [ "renderdoc-sys", "rustc-hash 1.1.0", "smallvec", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "web-sys", "wgpu-types", diff --git a/Cargo.toml b/Cargo.toml index e6ba7b6..37bea78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ edition = "2024" bevy = { version="0.15.3", features = ["jpeg"]} bevy_asset_loader = { version ="0.22.0", features = ["standard_dynamic_assets"] } bevy_egui = "0.33.0" +bevy_kira_audio = "0.22.0" bevy_rapier3d = "0.29.0" diff --git a/assets/audio/flashlight-switch.mp3 b/assets/audio/flashlight-switch.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..c7d13efa2275e46a0595021df2bebaea4ad55612 GIT binary patch literal 30720 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 gP!1suO5SUT5I("main.assets.ron") - .load_collection::() - .load_collection::() - .load_collection::(), - // .load_collection::() - // .load_collection::() - // .load_collection::() - // .load_collection::(), - ); + app.add_plugins(AudioPlugin) + .add_loading_state( + LoadingState::new(GameState::Loading) + .continue_to_state(GameState::Menu) + .with_dynamic_assets_file::("main.assets.ron") + .load_collection::() + .load_collection::() + .load_collection::() + .load_collection::(), + // .load_collection::() + // .load_collection::() + // .load_collection::(), + ); } // the following asset collections will be loaded during the State `GameState::InitialLoading` // when done loading, they will be inserted as resources (see ) #[derive(AssetCollection, Resource, Clone)] -pub(crate) struct AudioAssets {} +pub(crate) struct AudioAssets { + #[asset(key = "flashlight_click")] + pub(crate) flash_click: Handle, +} #[derive(AssetCollection, Resource, Clone)] pub(crate) struct GltfAssets { @@ -54,4 +58,6 @@ pub(crate) struct ImageAssets { pub(crate) struct FlashlightAssets { #[asset(key = "flash_hold_4")] pub(crate) flash_hold_4: Handle, + #[asset(key = "flash_hold_4_pressed")] + pub(crate) flash_hold_4_pressed: Handle, } diff --git a/src/main.rs b/src/main.rs index 48bedad..ebcbc51 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use asset_loading::ImageAssets; -use bevy::{prelude::*}; +use bevy::prelude::*; use bevy_rapier3d::prelude::*; mod asset_loading; diff --git a/src/player.rs b/src/player.rs index 788107d..f969cf2 100644 --- a/src/player.rs +++ b/src/player.rs @@ -2,11 +2,12 @@ use bevy::{ input::mouse::AccumulatedMouseMotion, prelude::*, render::view::RenderLayers, window::{PrimaryWindow, WindowResized} }; +use bevy_kira_audio::{Audio, AudioControl}; use bevy_rapier3d::prelude::*; pub mod toolbar; -use crate::{asset_loading::FlashlightAssets, GameState}; +use crate::{asset_loading::{AudioAssets, FlashlightAssets}, GameState}; #[derive(Debug, Component, Default)] pub struct Player { @@ -54,6 +55,22 @@ pub struct BaseTransform(pub Transform); #[derive(Debug, Component)] pub struct Flashlight; +#[derive(Component)] +pub struct FlashlightButtonAnimation { + pub timer: Timer, + pub is_pressed: bool, +} + +impl Default for FlashlightButtonAnimation { + fn default() -> Self { + Self { + timer: Timer::from_seconds(0.20, TimerMode::Once), + is_pressed: false, + } + } +} + + pub fn plugin(app: &mut App) { app.add_plugins(toolbar::plugin) .add_systems(OnEnter(GameState::Playing), (init_player, hide_cursor)) @@ -65,7 +82,7 @@ pub fn plugin(app: &mut App) { apply_head_bob, on_resize_system, handle_flashlight, - // handle_flashlight_movement, + update_flashlight_button_animation, ).run_if(in_state(GameState::Playing)), ) .add_systems( @@ -130,6 +147,7 @@ pub fn init_player( transform.0.clone(), transform, RenderLayers::layer(STATIC_LAYER), + FlashlightButtonAnimation::default(), )); // feitelijke pitslamp @@ -355,6 +373,9 @@ pub fn apply_head_bob( pub fn handle_flashlight( player_query: Query<&PlayerAction, With>, mut flashlight_query: Query<&mut SpotLight, With>, + mut flashlight_sprite_query: Query<&mut FlashlightButtonAnimation>, + audio_assets: Res, + audio: Res