mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add a volume option to SfxEvents, and use this to dispatch movement sfx for quadripeds at a volume proportionate to their size.
This commit is contained in:
parent
13cbef7865
commit
d87061fe14
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Brighter / higher contrast main-map
|
||||
- Removed highlighting of non-collectible sprites
|
||||
- Fixed /give_exp ignoring player argument
|
||||
- Extend run sfx to small animals to prevent sneak attacks by geese.
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -9,12 +9,21 @@ use vek::*;
|
||||
pub struct SfxEventItem {
|
||||
pub sfx: SfxEvent,
|
||||
pub pos: Option<Vec3<f32>>,
|
||||
pub vol: Option<f32>,
|
||||
}
|
||||
|
||||
impl SfxEventItem {
|
||||
pub fn new(sfx: SfxEvent, pos: Option<Vec3<f32>>) -> Self { Self { sfx, pos } }
|
||||
pub fn new(sfx: SfxEvent, pos: Option<Vec3<f32>>, vol: Option<f32>) -> Self {
|
||||
Self { sfx, pos, vol }
|
||||
}
|
||||
|
||||
pub fn at_player_position(sfx: SfxEvent) -> Self { Self { sfx, pos: None } }
|
||||
pub fn at_player_position(sfx: SfxEvent) -> Self {
|
||||
Self {
|
||||
sfx,
|
||||
pos: None,
|
||||
vol: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Hash, Eq)]
|
||||
|
@ -10,7 +10,7 @@ use soundcache::SoundCache;
|
||||
|
||||
use common::assets;
|
||||
use cpal::traits::DeviceTrait;
|
||||
use rodio::{Decoder, Device};
|
||||
use rodio::{source::Source, Decoder, Device};
|
||||
use vek::*;
|
||||
|
||||
const FALLOFF: f32 = 0.13;
|
||||
@ -135,11 +135,14 @@ impl AudioFrontend {
|
||||
self.music_channels.last_mut()
|
||||
}
|
||||
|
||||
pub fn play_sfx(&mut self, sound: &str, pos: Vec3<f32>) {
|
||||
pub fn play_sfx(&mut self, sound: &str, pos: Vec3<f32>, vol: Option<f32>) {
|
||||
if self.audio_device.is_some() {
|
||||
let calc_pos = ((pos - self.listener_pos) * FALLOFF).into_array();
|
||||
|
||||
let sound = self.sound_cache.load_sound(sound);
|
||||
let sound = self
|
||||
.sound_cache
|
||||
.load_sound(sound)
|
||||
.amplify(vol.unwrap_or(1.0));
|
||||
|
||||
let left_ear = self.listener_ear_left.into_array();
|
||||
let right_ear = self.listener_ear_right.into_array();
|
||||
|
@ -32,7 +32,7 @@ impl MovementEventMapper {
|
||||
}
|
||||
|
||||
pub fn maintain(&mut self, client: &Client, triggers: &SfxTriggers) {
|
||||
const SFX_DIST_LIMIT_SQR: f32 = 22500.0;
|
||||
const SFX_DIST_LIMIT_SQR: f32 = 20000.0;
|
||||
let ecs = client.state().ecs();
|
||||
|
||||
let player_position = ecs
|
||||
@ -65,18 +65,25 @@ impl MovementEventMapper {
|
||||
|
||||
let mapped_event = match body {
|
||||
Body::Humanoid(_) => Self::map_movement_event(character, state, vel.0, stats),
|
||||
Body::QuadrupedMedium(_) => {
|
||||
// TODO: Quadriped running sfx
|
||||
SfxEvent::Idle
|
||||
Body::QuadrupedMedium(_)
|
||||
| Body::QuadrupedSmall(_)
|
||||
| Body::BirdMedium(_)
|
||||
| Body::BirdSmall(_)
|
||||
| Body::BipedLarge(_) => {
|
||||
Self::map_non_humanoid_movement_event(character, vel.0)
|
||||
},
|
||||
_ => SfxEvent::Idle,
|
||||
_ => SfxEvent::Idle, // Ignore fish, critters, etc...
|
||||
};
|
||||
|
||||
// Check for SFX config entry for this movement
|
||||
if Self::should_emit(state, triggers.get_key_value(&mapped_event)) {
|
||||
ecs.read_resource::<EventBus<SfxEventItem>>()
|
||||
.emitter()
|
||||
.emit(SfxEventItem::new(mapped_event, Some(pos.0)));
|
||||
.emit(SfxEventItem::new(
|
||||
mapped_event,
|
||||
Some(pos.0),
|
||||
Some(Self::get_volume_for_body_type(body)),
|
||||
));
|
||||
|
||||
// Update the last play time
|
||||
state.event = mapped_event;
|
||||
@ -99,7 +106,7 @@ impl MovementEventMapper {
|
||||
/// they have not triggered an event for > n seconds. This prevents
|
||||
/// stale records from bloating the Map size.
|
||||
fn cleanup(&mut self, player: EcsEntity) {
|
||||
const TRACKING_TIMEOUT: u64 = 15;
|
||||
const TRACKING_TIMEOUT: u64 = 10;
|
||||
|
||||
let now = Instant::now();
|
||||
self.event_history.retain(|entity, event| {
|
||||
@ -197,11 +204,34 @@ impl MovementEventMapper {
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps a limited set of movements for other non-humanoid entities
|
||||
fn map_non_humanoid_movement_event(current_event: &CharacterState, vel: Vec3<f32>) -> SfxEvent {
|
||||
if current_event.movement == MovementState::Run && vel.magnitude() > 0.1 {
|
||||
SfxEvent::Run
|
||||
} else {
|
||||
SfxEvent::Idle
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true for any state where the player has their weapon drawn. This
|
||||
/// helps us manage the wield/unwield sfx events
|
||||
fn has_weapon_drawn(state: ActionState) -> bool {
|
||||
state.is_wield() | state.is_attack() | state.is_block() | state.is_charge()
|
||||
}
|
||||
|
||||
/// Returns a relative volume value for a body type. This helps us emit sfx
|
||||
/// at a volume appropriate fot the entity we are emitting the event for
|
||||
fn get_volume_for_body_type(body: &Body) -> f32 {
|
||||
match body {
|
||||
Body::Humanoid(_) => 0.9,
|
||||
Body::QuadrupedSmall(_) => 0.3,
|
||||
Body::QuadrupedMedium(_) => 0.7,
|
||||
Body::BirdMedium(_) => 0.3,
|
||||
Body::BirdSmall(_) => 0.2,
|
||||
Body::BipedLarge(_) => 1.0,
|
||||
_ => 0.9,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] mod tests;
|
||||
|
@ -1,7 +1,10 @@
|
||||
use super::*;
|
||||
use common::{
|
||||
assets,
|
||||
comp::{humanoid, item::Tool, ActionState, Body, MovementState, Stats},
|
||||
comp::{
|
||||
bird_small, humanoid, item::Tool, quadruped_medium, quadruped_small, ActionState, Body,
|
||||
MovementState, Stats,
|
||||
},
|
||||
event::SfxEvent,
|
||||
};
|
||||
use std::time::{Duration, Instant};
|
||||
@ -417,3 +420,37 @@ fn does_not_map_wield_when_no_main_weapon() {
|
||||
|
||||
assert_eq!(result, SfxEvent::Run);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_quadrupeds_running() {
|
||||
let result = MovementEventMapper::map_non_humanoid_movement_event(
|
||||
&CharacterState {
|
||||
movement: MovementState::Run,
|
||||
action: ActionState::Idle,
|
||||
},
|
||||
Vec3::new(0.5, 0.8, 0.0),
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Run);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determines_relative_volumes() {
|
||||
let human =
|
||||
MovementEventMapper::get_volume_for_body_type(&Body::Humanoid(humanoid::Body::random()));
|
||||
|
||||
let quadruped_medium = MovementEventMapper::get_volume_for_body_type(&Body::QuadrupedMedium(
|
||||
quadruped_medium::Body::random(),
|
||||
));
|
||||
|
||||
let quadruped_small = MovementEventMapper::get_volume_for_body_type(&Body::QuadrupedSmall(
|
||||
quadruped_small::Body::random(),
|
||||
));
|
||||
|
||||
let bird_small =
|
||||
MovementEventMapper::get_volume_for_body_type(&Body::BirdSmall(bird_small::Body::random()));
|
||||
|
||||
assert!(quadruped_medium < human);
|
||||
assert!(quadruped_small < quadruped_medium);
|
||||
assert!(bird_small < quadruped_small);
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ impl SfxMgr {
|
||||
},
|
||||
};
|
||||
|
||||
audio.play_sfx(sfx_file, position);
|
||||
audio.play_sfx(sfx_file, position, event.vol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user