Compare commits

..

No commits in common. "e381109cad03ba71a256c0babc1a21117ccafafd" and "45ab161f22f23eb55ff32c00d689c69aa1defe94" have entirely different histories.

13 changed files with 160 additions and 118 deletions

View File

@ -13,7 +13,7 @@ speech_dispatcher_0_10 = ["bevy_tts/speech_dispatcher_0_10"]
speech_dispatcher_0_11 = ["bevy_tts/speech_dispatcher_0_11"] speech_dispatcher_0_11 = ["bevy_tts/speech_dispatcher_0_11"]
[dependencies.bevy] [dependencies.bevy]
version = "0.11" version = "0.10"
default-features = false default-features = false
features = [ features = [
"bevy_gilrs", "bevy_gilrs",
@ -24,13 +24,14 @@ features = [
] ]
[dependencies] [dependencies]
bevy_rapier2d = "0.22" bevy_rapier2d = "0.21"
bevy_synthizer = "0.4" bevy_synthizer = "0.3"
bevy_tts = { version = "0.6", default-features = false, features = ["tolk"] } bevy_tts = { version = "0.5", default-features = false, features = ["tolk"] }
coord_2d = "0.3" coord_2d = "0.3"
futures-lite = "1" futures-lite = "1"
gilrs = "0.10"
here_be_dragons = { version = "0.3", features = ["serde"] } here_be_dragons = { version = "0.3", features = ["serde"] }
leafwing-input-manager = "0.10" leafwing-input-manager = { git = "https://github.com/ndarilek/leafwing-input-manager", branch = "consume" }
maze_generator = "2" maze_generator = "2"
once_cell = "1" once_cell = "1"
pathfinding = "4" pathfinding = "4"

View File

@ -678,11 +678,11 @@ impl Plugin for CorePlugin {
}; };
app.insert_resource(config) app.insert_resource(config)
.register_type::<CardinalDirection>() .register_type::<CardinalDirection>()
.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter( .add_plugin(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(
config.pixels_per_unit as f32, config.pixels_per_unit as f32,
)) ))
.add_systems(Startup, setup) .add_startup_system(setup)
.add_systems(Update, sync_config); .add_system(sync_config);
} }
} }

View File

@ -13,7 +13,7 @@ use crate::{
visibility::{RevealedTiles, Viewshed, Visible, VisibleEntities}, visibility::{RevealedTiles, Viewshed, Visible, VisibleEntities},
}; };
#[derive(Actionlike, PartialEq, Eq, Clone, Copy, Hash, Debug, Reflect)] #[derive(Actionlike, PartialEq, Eq, Clone, Copy, Hash, Debug)]
pub enum ExplorationAction { pub enum ExplorationAction {
Forward, Forward,
Backward, Backward,
@ -49,7 +49,7 @@ where
#[reflect(Component)] #[reflect(Component)]
pub struct Mappable; pub struct Mappable;
fn exploration_type_change<ExplorationType>( fn exploration_type_change<ExplorationType, State>(
mut tts: ResMut<Tts>, mut tts: ResMut<Tts>,
mut explorers: Query<( mut explorers: Query<(
&ActionState<ExplorationAction>, &ActionState<ExplorationAction>,
@ -60,6 +60,7 @@ fn exploration_type_change<ExplorationType>(
) -> Result<(), Box<dyn Error>> ) -> Result<(), Box<dyn Error>>
where where
ExplorationType: Component + Default + Copy + Ord, ExplorationType: Component + Default + Copy + Ord,
State: 'static + Clone + Debug + Eq + Hash + Send + Sync,
{ {
for (actions, visible, mut focused) in &mut explorers { for (actions, visible, mut focused) in &mut explorers {
let mut types: Vec<ExplorationType> = vec![]; let mut types: Vec<ExplorationType> = vec![];
@ -111,7 +112,7 @@ where
Ok(()) Ok(())
} }
fn exploration_type_focus<ExplorationType>( fn exploration_type_focus<ExplorationType, State>(
mut commands: Commands, mut commands: Commands,
mut tts: ResMut<Tts>, mut tts: ResMut<Tts>,
explorers: Query<( explorers: Query<(
@ -125,6 +126,7 @@ fn exploration_type_focus<ExplorationType>(
) -> Result<(), Box<dyn Error>> ) -> Result<(), Box<dyn Error>>
where where
ExplorationType: Component + Default + PartialEq, ExplorationType: Component + Default + PartialEq,
State: 'static + Clone + Debug + Eq + Hash + Send + Sync,
{ {
for (entity, actions, visible_entities, focused_type, exploring) in &explorers { for (entity, actions, visible_entities, focused_type, exploring) in &explorers {
let mut features = features let mut features = features
@ -200,7 +202,7 @@ where
Ok(()) Ok(())
} }
fn exploration_focus<MapData>( fn exploration_focus<State, MapData>(
mut commands: Commands, mut commands: Commands,
map: Query<&Map<MapData>>, map: Query<&Map<MapData>>,
explorers: Query< explorers: Query<
@ -213,6 +215,7 @@ fn exploration_focus<MapData>(
With<Player>, With<Player>,
>, >,
) where ) where
State: 'static + Clone + Debug + Eq + Hash + Send + Sync,
MapData: 'static + Clone + Default + Send + Sync, MapData: 'static + Clone + Default + Send + Sync,
{ {
for (entity, actions, transform, exploring) in &explorers { for (entity, actions, transform, exploring) in &explorers {
@ -249,11 +252,12 @@ fn exploration_focus<MapData>(
} }
} }
fn navigate_to_explored<MapData>( fn navigate_to_explored<State, MapData>(
mut commands: Commands, mut commands: Commands,
map: Query<(&Map<MapData>, &RevealedTiles)>, map: Query<(&Map<MapData>, &RevealedTiles)>,
explorers: Query<(Entity, &ActionState<ExplorationAction>, &Exploring)>, explorers: Query<(Entity, &ActionState<ExplorationAction>, &Exploring)>,
) where ) where
State: 'static + Clone + Debug + Eq + Hash + Send + Sync,
MapData: 'static + Clone + Default + Send + Sync, MapData: 'static + Clone + Default + Send + Sync,
{ {
for (entity, actions, exploring) in &explorers { for (entity, actions, exploring) in &explorers {
@ -396,33 +400,31 @@ where
.register_type::<ExplorationFocused>() .register_type::<ExplorationFocused>()
.register_type::<Mappable>() .register_type::<Mappable>()
.register_type::<Explorable>() .register_type::<Explorable>()
.add_plugins(InputManagerPlugin::<ExplorationAction>::default()) .add_plugin(InputManagerPlugin::<ExplorationAction>::default())
.add_systems( .add_systems(
Update,
( (
exploration_type_change::<ExplorationType>.pipe(error_handler), exploration_type_change::<ExplorationType, State>.pipe(error_handler),
exploration_type_changed_announcement::<ExplorationType>.pipe(error_handler), exploration_type_changed_announcement::<ExplorationType>.pipe(error_handler),
) )
.chain() .chain()
.in_set(Exploration), .in_set(Exploration),
) )
.add_systems( .add_systems(
Update,
( (
exploration_focus::<MapData>, exploration_focus::<State, MapData>,
exploration_type_focus::<ExplorationType>.pipe(error_handler), exploration_type_focus::<ExplorationType, State>.pipe(error_handler),
exploration_changed_announcement::<ExplorationType, MapData> exploration_changed_announcement::<ExplorationType, MapData>
.pipe(error_handler), .pipe(error_handler),
) )
.chain() .chain()
.in_set(Exploration), .in_set(Exploration),
) )
.add_systems(Update, navigate_to_explored::<MapData>.in_set(Exploration)); .add_system(navigate_to_explored::<State, MapData>.in_set(Exploration));
if !config.states.is_empty() { if !config.states.is_empty() {
let states = config.states; let states = config.states;
for state in states { for state in states {
app.configure_set(Update, Exploration.run_if(in_state(state.clone()))) app.configure_set(Exploration.in_set(OnUpdate(state.clone())))
.add_systems(OnExit(state), cleanup); .add_system(cleanup.in_schedule(OnExit(state)));
} }
} }
} }

View File

@ -12,6 +12,7 @@ pub mod core;
pub mod error; pub mod error;
pub mod exploration; pub mod exploration;
pub use futures_lite; pub use futures_lite;
pub use gilrs;
pub use here_be_dragons as mapgen; pub use here_be_dragons as mapgen;
pub use leafwing_input_manager; pub use leafwing_input_manager;
pub mod log; pub mod log;

View File

@ -60,7 +60,11 @@ pub struct LogPlugin;
impl Plugin for LogPlugin { impl Plugin for LogPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.register_type::<LogEntry>() app.register_type::<LogEntry>()
.add_systems(Startup, setup) .add_startup_system(setup)
.add_systems(PostUpdate, read_log.pipe(error_handler)); .add_system(
read_log
.pipe(error_handler)
.in_base_set(CoreSet::PostUpdate),
);
} }
} }

View File

@ -329,12 +329,12 @@ impl<MapData: 'static + Clone + Default + Send + Sync> Plugin for MapPlugin<MapD
app.insert_resource(self.clone()) app.insert_resource(self.clone())
.register_type::<Portal>() .register_type::<Portal>()
.add_systems( .add_systems(
PreUpdate,
( (
spawn_colliders::<MapData>, spawn_colliders::<MapData>,
spawn_portals::<MapData>, spawn_portals::<MapData>,
spawn_portal_colliders::<MapData>, spawn_portal_colliders::<MapData>,
), )
.in_base_set(CoreSet::PreUpdate),
); );
} }
} }

View File

@ -13,7 +13,7 @@ use crate::{
utils::target_and_other, utils::target_and_other,
}; };
#[derive(Actionlike, PartialEq, Eq, Clone, Copy, Hash, Debug, Reflect)] #[derive(Actionlike, PartialEq, Eq, Clone, Copy, Hash, Debug)]
pub enum NavigationAction { pub enum NavigationAction {
Move, Move,
Translate, Translate,
@ -415,21 +415,21 @@ where
.register_type::<StrafeMovementFactor>() .register_type::<StrafeMovementFactor>()
.register_type::<RotationSpeed>() .register_type::<RotationSpeed>()
.register_type::<Speed>() .register_type::<Speed>()
.add_plugins(InputManagerPlugin::<NavigationAction>::default()) .add_plugin(InputManagerPlugin::<NavigationAction>::default())
.add_systems(PreUpdate, (update_direction, add_speed)) .add_systems((update_direction, add_speed).in_base_set(CoreSet::PreUpdate))
.add_systems( .add_systems(
Update,
(snap.pipe(error_handler), controls) (snap.pipe(error_handler), controls)
.chain() .chain()
.in_set(Movement), .in_set(Movement),
) )
.add_systems((tick_snap_timers, speak_direction.pipe(error_handler)))
.add_systems( .add_systems(
Update, (remove_direction, log_area_descriptions::<State>).in_base_set(CoreSet::PostUpdate),
(tick_snap_timers, speak_direction.pipe(error_handler)),
)
.add_systems(
PostUpdate,
(remove_direction, log_area_descriptions::<State>),
); );
if !self.states.is_empty() {
for state in &self.states {
app.configure_set(Movement.in_set(OnUpdate(state.clone())));
}
}
} }
} }

View File

@ -19,7 +19,7 @@ use crate::{
navigation::{NavigationAction, RotationSpeed}, navigation::{NavigationAction, RotationSpeed},
}; };
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug, Reflect)] #[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
pub struct NegotiatePathAction; pub struct NegotiatePathAction;
impl Actionlike for NegotiatePathAction { impl Actionlike for NegotiatePathAction {
@ -404,18 +404,18 @@ pub struct PathfindingPlugin;
impl Plugin for PathfindingPlugin { impl Plugin for PathfindingPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_plugins(InputManagerPlugin::<NegotiatePathAction>::default()) app.add_plugin(InputManagerPlugin::<NegotiatePathAction>::default())
.register_type::<Destination>() .register_type::<Destination>()
.register_type::<NoPath>() .register_type::<NoPath>()
.register_type::<Path>() .register_type::<Path>()
.register_type::<CostMap>() .register_type::<CostMap>()
.add_systems(PreUpdate, (negotiate_path, poll_tasks)) .add_systems((negotiate_path, poll_tasks).in_base_set(CoreSet::PreUpdate))
.add_systems( .add_systems(
PreUpdate,
(actions, calculate_path) (actions, calculate_path)
.chain() .chain()
.in_base_set(CoreSet::PreUpdate)
.after(InputManagerSystem::Tick), .after(InputManagerSystem::Tick),
) )
.add_systems(PostUpdate, remove_destination); .add_system(remove_destination.in_base_set(CoreSet::PostUpdate));
} }
} }

View File

@ -45,15 +45,8 @@ impl Footsteps {
fn added(mut commands: Commands, footsteps: Query<(Entity, &Footstep), Added<Footstep>>) { fn added(mut commands: Commands, footsteps: Query<(Entity, &Footstep), Added<Footstep>>) {
for (entity, footstep) in &footsteps { for (entity, footstep) in &footsteps {
if let Some(audio) = &footstep.audio { if let Some(audio) = &footstep.audio {
let mut pitch = 1.;
if let Some(pitch_variation) = footstep.pitch_variation {
pitch -= pitch_variation / 2.;
pitch += random::<f64>() * pitch_variation;
}
commands.entity(entity).insert(Sound { commands.entity(entity).insert(Sound {
audio: audio.clone(), audio: audio.clone(),
gain: footstep.gain,
pitch,
paused: true, paused: true,
..default() ..default()
}); });
@ -79,8 +72,8 @@ fn update(
let distance = last.0 + (last.1.distance(transform)); let distance = last.0 + (last.1.distance(transform));
if distance >= footstep.step_length { if distance >= footstep.step_length {
last_step_distance.insert(entity, (0., *transform)); last_step_distance.insert(entity, (0., *transform));
let audio = if let Some(footsteps) = footsteps { if let Some(footsteps) = footsteps {
if footsteps.len() == 1 { let audio = if footsteps.len() == 1 {
Some(footsteps[0].clone()) Some(footsteps[0].clone())
} else if !footsteps.is_empty() { } else if !footsteps.is_empty() {
let mut footsteps = footsteps.clone(); let mut footsteps = footsteps.clone();
@ -95,22 +88,30 @@ fn update(
Some(audio) Some(audio)
} else { } else {
None None
};
if let Some(audio) = audio {
let mut pitch = 1.;
if let Some(pitch_variation) = footstep.pitch_variation {
pitch -= pitch_variation / 2.;
pitch += random::<f64>() * pitch_variation;
}
commands.entity(entity).insert(Sound {
audio,
gain: footstep.gain,
pitch,
..default()
});
} }
} else { } else if let Some(mut sound) = sound {
footstep.audio.clone() sound.gain = footstep.gain;
}; sound.pitch = footstep.pitch.unwrap_or(1.);
if let Some(audio) = audio {
let mut pitch = 1.;
if let Some(pitch_variation) = footstep.pitch_variation { if let Some(pitch_variation) = footstep.pitch_variation {
pitch -= pitch_variation / 2.; let mut pitch = sound.pitch - pitch_variation / 2.;
pitch += random::<f64>() * pitch_variation; pitch += random::<f64>() * pitch_variation;
sound.pitch = pitch;
} }
commands.entity(entity).insert(Sound { sound.paused = false;
audio, sound.restart = true;
gain: footstep.gain,
pitch,
..default()
});
} }
} else if last.1 != *transform { } else if last.1 != *transform {
last_step_distance.insert(entity, (distance, *transform)); last_step_distance.insert(entity, (distance, *transform));
@ -126,9 +127,11 @@ pub struct FootstepPlugin;
impl Plugin for FootstepPlugin { impl Plugin for FootstepPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(PreUpdate, added).add_systems( app.add_system(added.in_base_set(CoreSet::PreUpdate))
PostUpdate, .add_system(
update.after(TransformSystem::TransformPropagate), update
); .after(TransformSystem::TransformPropagate)
.in_base_set(CoreSet::PostUpdate),
);
} }
} }

View File

@ -1,3 +1,5 @@
use std::{fmt::Debug, time::Duration};
use bevy::prelude::*; use bevy::prelude::*;
use bevy_synthizer::{Audio, Sound}; use bevy_synthizer::{Audio, Sound};
@ -6,7 +8,7 @@ use rand::random;
use crate::{ use crate::{
core::Player, core::Player,
exploration::ExplorationFocused, exploration::ExplorationFocused,
visibility::{Visible, VisibleEntities}, visibility::{VisibilityChanged, Visible, VisibleEntities},
}; };
#[derive(Component, Clone, Debug)] #[derive(Component, Clone, Debug)]
@ -20,12 +22,17 @@ pub struct SoundIcon {
impl Default for SoundIcon { impl Default for SoundIcon {
fn default() -> Self { fn default() -> Self {
let seconds = random::<f32>() + 4.5; let seconds = random::<f32>() + 4.5;
Self { let mut icon = Self {
audio: default(), audio: default(),
gain: 1., gain: 1.,
pitch: 1., pitch: 1.,
interval: Some(Timer::from_seconds(seconds, TimerMode::Once)), interval: Some(Timer::from_seconds(seconds, TimerMode::Repeating)),
};
if let Some(ref mut interval) = icon.interval {
let seconds = Duration::from_secs_f32(seconds - 0.1);
interval.set_elapsed(seconds);
} }
icon
} }
} }
@ -36,7 +43,7 @@ fn added(mut commands: Commands, icons: Query<(Entity, &SoundIcon), Added<SoundI
let pitch = icon.pitch; let pitch = icon.pitch;
let looping = icon.interval.is_none(); let looping = icon.interval.is_none();
commands.entity(entity).insert(Sound { commands.entity(entity).insert(Sound {
audio: buffer, audio: buffer.into(),
gain, gain,
pitch, pitch,
looping, looping,
@ -61,7 +68,7 @@ fn update<S>(
) where ) where
S: States, S: States,
{ {
if !config.states.is_empty() && !config.states.contains(state.get()) { if !config.states.is_empty() && !config.states.contains(&state.0) {
return; return;
} }
for visible in &viewers { for visible in &viewers {
@ -75,40 +82,28 @@ fn update<S>(
}; };
if let Some(entity) = entity { if let Some(entity) = entity {
if visible.contains(&entity) { if visible.contains(&entity) {
if let Some(interval) = icon.interval.as_mut() { if sound.looping {
if interval.finished() {
interval.reset();
continue;
} else if interval.percent() == 0. {
sound.generator = None;
}
interval.tick(time.delta());
}
if sound.audio != icon.audio {
sound.audio = icon.audio.clone();
}
if sound.gain != icon.gain {
sound.gain = icon.gain;
}
if sound.pitch != icon.pitch {
sound.pitch = icon.pitch;
}
let looping = icon.interval.is_none();
if sound.looping != looping {
sound.looping = looping;
}
if sound.paused {
sound.paused = false; sound.paused = false;
sound.generator = None; } else if let Some(interval) = icon.interval.as_mut() {
interval.tick(time.delta());
if interval.finished() {
sound.paused = false;
sound.restart = true;
interval.reset();
}
} }
let buffer = icon.audio.clone();
let audio: Audio = buffer.into();
if sound.audio != audio {
sound.audio = audio;
}
sound.gain = icon.gain;
sound.pitch = icon.pitch;
sound.looping = icon.interval.is_none();
} else if !sound.paused { } else if !sound.paused {
sound.paused = true; sound.paused = true;
if let Some(interval) = icon.interval.as_mut() { sound.restart = true;
interval.reset();
}
} }
} else {
panic!("Should not happen");
} }
} }
} }
@ -153,6 +148,38 @@ fn exploration_focus_removed(
} }
} }
fn reset_timer_on_visibility_gain(
mut events: EventReader<VisibilityChanged>,
player: Query<Entity, With<Player>>,
mut icons: Query<&mut SoundIcon>,
children: Query<&Children>,
) {
for event in events.iter() {
if let VisibilityChanged::Gained { viewer, viewed } = event {
if player.get(*viewer).is_ok() {
let mut targets = vec![];
if icons.get(*viewed).is_ok() {
targets.push(viewed);
}
if let Ok(children) = children.get(*viewed) {
for child in children.iter() {
if icons.get(*child).is_ok() {
targets.push(child);
}
}
}
for icon in targets.iter_mut() {
if let Ok(mut icon) = icons.get_mut(**icon) {
if let Some(timer) = icon.interval.as_mut() {
timer.set_elapsed(timer.duration());
}
}
}
}
}
}
}
#[derive(Resource, Clone)] #[derive(Resource, Clone)]
pub struct SoundIconPlugin<S> { pub struct SoundIconPlugin<S> {
pub states: Vec<S>, pub states: Vec<S>,
@ -170,11 +197,16 @@ where
{ {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.insert_resource(self.clone()) app.insert_resource(self.clone())
.add_systems(PreUpdate, added) .add_systems((added, reset_timer_on_visibility_gain).in_base_set(CoreSet::PreUpdate))
.add_systems(PreUpdate, (exploration_focus_changed, update::<S>).chain())
.add_systems( .add_systems(
PostUpdate, (exploration_focus_changed, update::<S>)
exploration_focus_removed.after(exploration_focus_changed), .chain()
.in_base_set(CoreSet::PreUpdate),
)
.add_system(
exploration_focus_removed
.in_base_set(CoreSet::PostUpdate)
.after(exploration_focus_changed),
); );
} }
} }

View File

@ -154,11 +154,8 @@ impl Plugin for PitchShiftPlugin {
.register_type::<Behind>() .register_type::<Behind>()
.init_resource::<LastIconPitch>() .init_resource::<LastIconPitch>()
.init_resource::<LastSoundPitch>() .init_resource::<LastSoundPitch>()
.add_systems(PreUpdate, tag_behind) .add_system(tag_behind.in_base_set(CoreSet::PreUpdate))
.add_systems( .add_systems((behind_added, sound_icon_changed, sound_changed, sync_config))
Update, .add_system(behind_removed.in_base_set(CoreSet::PostUpdate));
(behind_added, sound_icon_changed, sound_changed, sync_config),
)
.add_systems(PostUpdate, behind_removed);
} }
} }

View File

@ -56,10 +56,11 @@ pub struct VolumetricPlugin;
impl Plugin for VolumetricPlugin { impl Plugin for VolumetricPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.register_type::<Volumetric>() app.register_type::<Volumetric>()
.add_systems( .add_system(
PostUpdate, update
update.before(TransformSystem::TransformPropagate), .in_base_set(CoreSet::PostUpdate)
.before(TransformSystem::TransformPropagate),
) )
.add_systems(PostUpdate, removed); .add_system(removed.in_base_set(CoreSet::PostUpdate));
} }
} }

View File

@ -233,7 +233,6 @@ impl ViewshedBundle {
} }
} }
#[derive(Event)]
pub enum VisibilityChanged { pub enum VisibilityChanged {
Gained { viewer: Entity, viewed: Entity }, Gained { viewer: Entity, viewed: Entity },
Lost { viewer: Entity, viewed: Entity }, Lost { viewer: Entity, viewed: Entity },
@ -442,13 +441,15 @@ impl<MapData: 'static + Clone + Default + Send + Sync> Plugin for VisibilityPlug
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<VisibilityChanged>() app.add_event::<VisibilityChanged>()
.add_systems( .add_systems(
PreUpdate,
( (
add_visibility_indices::<MapData>, add_visibility_indices::<MapData>,
update_viewshed, update_viewshed,
update_revealed_tiles::<MapData>, update_revealed_tiles::<MapData>,
), )
.in_base_set(CoreSet::PreUpdate),
) )
.add_systems(PostUpdate, (log_visible, viewshed_removed, remove_visible)); .add_systems(
(log_visible, viewshed_removed, remove_visible).in_base_set(CoreSet::PostUpdate),
);
} }
} }