mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
More footstep sfx based on distance
This commit is contained in:
parent
03a1452d16
commit
7dda25a66d
@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Protection rating was moved to the top left of the loadout view
|
||||
- Changed camera smoothing to be off by default.
|
||||
- Fixed AI behavior so only humanoids will attempt to roll
|
||||
- Footstep SFX is now dependant on distance moved, not time since last play
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -64,7 +64,27 @@
|
||||
],
|
||||
threshold: 0.25,
|
||||
),
|
||||
Run: (
|
||||
Run(Earth): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_1",
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_2",
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_3",
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_4",
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_5",
|
||||
],
|
||||
threshold: 1.6,
|
||||
),
|
||||
QuadRun(Earth): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_1",
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_2",
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_3",
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_4",
|
||||
"voxygen.audio.sfx.footsteps.stepdirt_5",
|
||||
],
|
||||
threshold: 0.8,
|
||||
),
|
||||
Run(Grass): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.footsteps.stepgrass_1",
|
||||
"voxygen.audio.sfx.footsteps.stepgrass_2",
|
||||
@ -73,9 +93,9 @@
|
||||
"voxygen.audio.sfx.footsteps.stepgrass_5",
|
||||
"voxygen.audio.sfx.footsteps.stepgrass_6",
|
||||
],
|
||||
threshold: 0.25,
|
||||
threshold: 1.6,
|
||||
),
|
||||
QuadRun: (
|
||||
QuadRun(Grass): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.footsteps.stepgrass_1",
|
||||
"voxygen.audio.sfx.footsteps.stepgrass_2",
|
||||
@ -84,23 +104,41 @@
|
||||
"voxygen.audio.sfx.footsteps.stepgrass_5",
|
||||
"voxygen.audio.sfx.footsteps.stepgrass_6",
|
||||
],
|
||||
threshold: 0.12,
|
||||
threshold: 0.8,
|
||||
),
|
||||
SnowRun: (
|
||||
Run(Snow): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.footsteps.snow_step_1",
|
||||
"voxygen.audio.sfx.footsteps.snow_step_2",
|
||||
"voxygen.audio.sfx.footsteps.snow_step_3",
|
||||
],
|
||||
threshold: 0.25,
|
||||
threshold: 1.6,
|
||||
),
|
||||
QuadSnowRun: (
|
||||
QuadRun(Snow): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.footsteps.snow_step_1",
|
||||
"voxygen.audio.sfx.footsteps.snow_step_2",
|
||||
"voxygen.audio.sfx.footsteps.snow_step_3",
|
||||
],
|
||||
threshold: 0.12,
|
||||
threshold: 0.8,
|
||||
),
|
||||
Run(Rock): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.footsteps.stone_step_1",
|
||||
"voxygen.audio.sfx.footsteps.stone_step_2",
|
||||
"voxygen.audio.sfx.footsteps.stone_step_3",
|
||||
"voxygen.audio.sfx.footsteps.stone_step_4",
|
||||
],
|
||||
threshold: 1.6,
|
||||
),
|
||||
QuadRun(Rock): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.footsteps.stone_step_1",
|
||||
"voxygen.audio.sfx.footsteps.stone_step_2",
|
||||
"voxygen.audio.sfx.footsteps.stone_step_3",
|
||||
"voxygen.audio.sfx.footsteps.stone_step_4",
|
||||
],
|
||||
threshold: 0.8,
|
||||
),
|
||||
//ExperienceGained: (
|
||||
// files: [
|
||||
|
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_1.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_1.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_2.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_2.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_3.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_3.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_4.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_4.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_5.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/footsteps/stepdirt_5.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/stone_step_1.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/footsteps/stone_step_1.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/stone_step_2.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/footsteps/stone_step_2.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/stone_step_3.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/footsteps/stone_step_3.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/stone_step_4.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/footsteps/stone_step_4.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -10,6 +10,7 @@ use crate::{
|
||||
use client::Client;
|
||||
use common::{
|
||||
comp::{Body, CharacterState, PhysicsState, Pos, Vel},
|
||||
resources::DeltaTime,
|
||||
terrain::{BlockKind, TerrainChunk},
|
||||
vol::ReadVol,
|
||||
};
|
||||
@ -25,6 +26,7 @@ struct PreviousEntityState {
|
||||
time: Instant,
|
||||
on_ground: bool,
|
||||
in_water: bool,
|
||||
distance_travelled: f32,
|
||||
}
|
||||
|
||||
impl Default for PreviousEntityState {
|
||||
@ -34,6 +36,7 @@ impl Default for PreviousEntityState {
|
||||
time: Instant::now(),
|
||||
on_ground: true,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,6 +115,7 @@ impl EventMapper for MovementEventMapper {
|
||||
underwater,
|
||||
);
|
||||
internal_state.time = Instant::now();
|
||||
internal_state.distance_travelled = 0.0;
|
||||
}
|
||||
|
||||
// update state to determine the next event. We only record the time (above) if
|
||||
@ -123,6 +127,8 @@ impl EventMapper for MovementEventMapper {
|
||||
} else {
|
||||
internal_state.in_water = false;
|
||||
}
|
||||
let dt = ecs.fetch::<DeltaTime>().0;
|
||||
internal_state.distance_travelled += vel.0.magnitude() * dt;
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,14 +162,19 @@ impl MovementEventMapper {
|
||||
/// any) needs to satisfy two conditions to be allowed to play:
|
||||
/// 1. An sfx.ron entry exists for the movement (we need to know which sound
|
||||
/// file(s) to play) 2. The sfx has not been played since it's timeout
|
||||
/// threshold has elapsed, which prevents firing every tick
|
||||
/// threshold has elapsed, which prevents firing every tick. For movement,
|
||||
/// threshold is not a time, but a distance.
|
||||
fn should_emit(
|
||||
previous_state: &PreviousEntityState,
|
||||
sfx_trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>,
|
||||
) -> bool {
|
||||
if let Some((event, item)) = sfx_trigger_item {
|
||||
if &previous_state.event == event {
|
||||
previous_state.time.elapsed().as_secs_f32() >= item.threshold
|
||||
match event {
|
||||
SfxEvent::Run(_) => previous_state.distance_travelled >= item.threshold,
|
||||
SfxEvent::QuadRun(_) => previous_state.distance_travelled >= item.threshold,
|
||||
_ => previous_state.time.elapsed().as_secs_f32() >= item.threshold,
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
@ -199,8 +210,11 @@ impl MovementEventMapper {
|
||||
SfxEvent::Sneak
|
||||
} else {
|
||||
match underfoot_block_kind {
|
||||
BlockKind::Snow => SfxEvent::SnowRun,
|
||||
_ => SfxEvent::Run,
|
||||
BlockKind::Snow => SfxEvent::Run(BlockKind::Snow),
|
||||
BlockKind::Rock | BlockKind::WeakRock => SfxEvent::Run(BlockKind::Rock),
|
||||
BlockKind::Sand => SfxEvent::Run(BlockKind::Sand),
|
||||
BlockKind::Air => SfxEvent::Idle,
|
||||
_ => SfxEvent::Run(BlockKind::Grass),
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -230,8 +244,11 @@ impl MovementEventMapper {
|
||||
SfxEvent::Swim
|
||||
} else if physics_state.on_ground && vel.magnitude() > 0.1 {
|
||||
match underfoot_block_kind {
|
||||
BlockKind::Snow => SfxEvent::SnowRun,
|
||||
_ => SfxEvent::Run,
|
||||
BlockKind::Snow => SfxEvent::Run(BlockKind::Snow),
|
||||
BlockKind::Rock | BlockKind::WeakRock => SfxEvent::Run(BlockKind::Rock),
|
||||
BlockKind::Sand => SfxEvent::Run(BlockKind::Sand),
|
||||
BlockKind::Air => SfxEvent::Idle,
|
||||
_ => SfxEvent::Run(BlockKind::Grass),
|
||||
}
|
||||
} else {
|
||||
SfxEvent::Idle
|
||||
@ -248,8 +265,11 @@ impl MovementEventMapper {
|
||||
SfxEvent::Swim
|
||||
} else if physics_state.on_ground && vel.magnitude() > 0.1 {
|
||||
match underfoot_block_kind {
|
||||
BlockKind::Snow => SfxEvent::QuadSnowRun,
|
||||
_ => SfxEvent::QuadRun,
|
||||
BlockKind::Snow => SfxEvent::QuadRun(BlockKind::Snow),
|
||||
BlockKind::Rock | BlockKind::WeakRock => SfxEvent::QuadRun(BlockKind::Rock),
|
||||
BlockKind::Sand => SfxEvent::QuadRun(BlockKind::Sand),
|
||||
BlockKind::Air => SfxEvent::Idle,
|
||||
_ => SfxEvent::QuadRun(BlockKind::Grass),
|
||||
}
|
||||
} else {
|
||||
SfxEvent::Idle
|
||||
|
@ -26,14 +26,17 @@ fn config_but_played_since_threshold_no_emit() {
|
||||
|
||||
// Triggered a 'Run' 0 seconds ago
|
||||
let previous_state = PreviousEntityState {
|
||||
event: SfxEvent::Run,
|
||||
event: SfxEvent::Run(BlockKind::Grass),
|
||||
time: Instant::now(),
|
||||
on_ground: true,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
};
|
||||
|
||||
let result =
|
||||
MovementEventMapper::should_emit(&previous_state, Some((&SfxEvent::Run, &trigger_item)));
|
||||
let result = MovementEventMapper::should_emit(
|
||||
&previous_state,
|
||||
Some((&SfxEvent::Run(BlockKind::Grass), &trigger_item)),
|
||||
);
|
||||
|
||||
assert_eq!(result, false);
|
||||
}
|
||||
@ -50,10 +53,13 @@ fn config_and_not_played_since_threshold_emits() {
|
||||
time: Instant::now().checked_add(Duration::from_secs(1)).unwrap(),
|
||||
on_ground: true,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
};
|
||||
|
||||
let result =
|
||||
MovementEventMapper::should_emit(&previous_state, Some((&SfxEvent::Run, &trigger_item)));
|
||||
let result = MovementEventMapper::should_emit(
|
||||
&previous_state,
|
||||
Some((&SfxEvent::Run(BlockKind::Grass), &trigger_item)),
|
||||
);
|
||||
|
||||
assert_eq!(result, true);
|
||||
}
|
||||
@ -66,16 +72,19 @@ fn same_previous_event_elapsed_emits() {
|
||||
};
|
||||
|
||||
let previous_state = PreviousEntityState {
|
||||
event: SfxEvent::Run,
|
||||
event: SfxEvent::Run(BlockKind::Grass),
|
||||
time: Instant::now()
|
||||
.checked_sub(Duration::from_millis(500))
|
||||
.checked_sub(Duration::from_millis(1800))
|
||||
.unwrap(),
|
||||
on_ground: true,
|
||||
in_water: false,
|
||||
distance_travelled: 2.0,
|
||||
};
|
||||
|
||||
let result =
|
||||
MovementEventMapper::should_emit(&previous_state, Some((&SfxEvent::Run, &trigger_item)));
|
||||
let result = MovementEventMapper::should_emit(
|
||||
&previous_state,
|
||||
Some((&SfxEvent::Run(BlockKind::Grass), &trigger_item)),
|
||||
);
|
||||
|
||||
assert_eq!(result, true);
|
||||
}
|
||||
@ -93,6 +102,7 @@ fn maps_idle() {
|
||||
time: Instant::now(),
|
||||
on_ground: true,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::zero(),
|
||||
BlockKind::Grass,
|
||||
@ -114,12 +124,13 @@ fn maps_run_with_sufficient_velocity() {
|
||||
time: Instant::now(),
|
||||
on_ground: true,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::new(0.5, 0.8, 0.0),
|
||||
BlockKind::Grass,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Run);
|
||||
assert_eq!(result, SfxEvent::Run(BlockKind::Grass));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -135,6 +146,7 @@ fn does_not_map_run_with_insufficient_velocity() {
|
||||
time: Instant::now(),
|
||||
on_ground: true,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::new(0.02, 0.0001, 0.0),
|
||||
BlockKind::Grass,
|
||||
@ -153,6 +165,7 @@ fn does_not_map_run_with_sufficient_velocity_but_not_on_ground() {
|
||||
time: Instant::now(),
|
||||
on_ground: false,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::new(0.5, 0.8, 0.0),
|
||||
BlockKind::Grass,
|
||||
@ -183,10 +196,11 @@ fn maps_roll() {
|
||||
..Default::default()
|
||||
},
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Run,
|
||||
event: SfxEvent::Run(BlockKind::Grass),
|
||||
time: Instant::now(),
|
||||
on_ground: true,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::new(0.5, 0.5, 0.0),
|
||||
BlockKind::Grass,
|
||||
@ -208,12 +222,13 @@ fn maps_land_on_ground_to_run() {
|
||||
time: Instant::now(),
|
||||
on_ground: false,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::zero(),
|
||||
BlockKind::Grass,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Run);
|
||||
assert_eq!(result, SfxEvent::Run(BlockKind::Grass));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -226,6 +241,7 @@ fn maps_glider_open() {
|
||||
time: Instant::now(),
|
||||
on_ground: false,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::zero(),
|
||||
BlockKind::Grass,
|
||||
@ -244,6 +260,7 @@ fn maps_glide() {
|
||||
time: Instant::now(),
|
||||
on_ground: false,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::zero(),
|
||||
BlockKind::Grass,
|
||||
@ -262,6 +279,7 @@ fn maps_glider_close_when_closing_mid_flight() {
|
||||
time: Instant::now(),
|
||||
on_ground: false,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::zero(),
|
||||
BlockKind::Grass,
|
||||
@ -284,6 +302,7 @@ fn maps_glider_close_when_landing() {
|
||||
time: Instant::now(),
|
||||
on_ground: false,
|
||||
in_water: false,
|
||||
distance_travelled: 0.0,
|
||||
},
|
||||
Vec3::zero(),
|
||||
BlockKind::Grass,
|
||||
@ -303,7 +322,7 @@ fn maps_quadrupeds_running() {
|
||||
BlockKind::Grass,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Run);
|
||||
assert_eq!(result, SfxEvent::Run(BlockKind::Grass));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -22,7 +22,7 @@
|
||||
//! The following snippet details some entries in the configuration and how they
|
||||
//! map to the sound files:
|
||||
//! ```ignore
|
||||
//! Run: (
|
||||
//! Run(Grass): ( // depends on underfoot block
|
||||
//! files: [
|
||||
//! "voxygen.audio.sfx.footsteps.stepgrass_1",
|
||||
//! "voxygen.audio.sfx.footsteps.stepgrass_2",
|
||||
@ -31,13 +31,13 @@
|
||||
//! "voxygen.audio.sfx.footsteps.stepgrass_5",
|
||||
//! "voxygen.audio.sfx.footsteps.stepgrass_6",
|
||||
//! ],
|
||||
//! threshold: 0.25, // wait 0.25s between plays
|
||||
//! threshold: 1.6, // travelled distance before next play
|
||||
//! ),
|
||||
//! Wield(Sword): ( // depends on the player's weapon
|
||||
//! files: [
|
||||
//! "voxygen.audio.sfx.weapon.sword_out",
|
||||
//! ],
|
||||
//! threshold: 0.5,
|
||||
//! threshold: 0.5, // wait 0.5s between plays
|
||||
//! ),
|
||||
//! ...
|
||||
//! ```
|
||||
@ -95,7 +95,7 @@ use common::{
|
||||
object, Body, CharacterAbilityType, InventoryUpdateEvent,
|
||||
},
|
||||
outcome::Outcome,
|
||||
terrain::TerrainChunk,
|
||||
terrain::{BlockKind, TerrainChunk},
|
||||
};
|
||||
use common_sys::state::State;
|
||||
use event_mapper::SfxEventMapper;
|
||||
@ -147,10 +147,8 @@ pub enum SfxEvent {
|
||||
RunningWater,
|
||||
Idle,
|
||||
Swim,
|
||||
Run,
|
||||
QuadRun,
|
||||
SnowRun,
|
||||
QuadSnowRun,
|
||||
Run(BlockKind),
|
||||
QuadRun(BlockKind),
|
||||
Roll,
|
||||
Sneak,
|
||||
Climb,
|
||||
|
Loading…
Reference in New Issue
Block a user