Skip to content

Commit

Permalink
Add entity animation sounds
Browse files Browse the repository at this point in the history
  • Loading branch information
hasenbanck committed Dec 26, 2024
1 parent d674b1e commit 6d682a3
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 94 deletions.
44 changes: 36 additions & 8 deletions korangar/src/loaders/action/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::sync::Arc;

use cgmath::{Array, Vector2};
use derive_new::new;
use korangar_audio::{AudioEngine, SoundEffectKey};
#[cfg(feature = "debug")]
use korangar_debug::logging::{print_debug, Colorize, Timer};
use korangar_interface::elements::PrototypeElement;
Expand Down Expand Up @@ -100,6 +101,8 @@ impl<T> AnimationState<T> {
pub struct Actions {
pub actions: Vec<Action>,
pub delays: Vec<f32>,
#[hidden_element]
pub events: Vec<Option<SoundEffectKey>>,
#[cfg(feature = "debug")]
actions_data: ActionsData,
}
Expand All @@ -118,9 +121,9 @@ impl Actions {
T: Into<usize> + Copy,
{
let direction = camera_direction % 8;
let aa = animation_state.action.into() * 8 + direction;
let a = &self.actions[aa % self.actions.len()];
let delay = self.delays[aa % self.delays.len()];
let animation_action = animation_state.action.into() * 8 + direction;
let action = &self.actions[animation_action % self.actions.len()];
let delay = self.delays[animation_action % self.delays.len()];

let factor = animation_state
.factor
Expand All @@ -129,14 +132,14 @@ impl Actions {

let frame = animation_state
.duration
.map(|duration| animation_state.time * a.motions.len() as u32 / duration)
.map(|duration| animation_state.time * action.motions.len() as u32 / duration)
.unwrap_or_else(|| (animation_state.time as f32 / factor) as u32);
// TODO: work out how to avoid losing digits when casting timg to an f32. When
// TODO: work out how to avoid losing digits when casting timing to an f32. When
// fixed remove set_start_time in MouseCursor.

let fs = &a.motions[frame as usize % a.motions.len()];
let motion = &action.motions[frame as usize % action.motions.len()];

for sprite_clip in &fs.sprite_clips {
for sprite_clip in &motion.sprite_clips {
// `get` instead of a direct index in case a fallback was loaded
let Some(texture) = sprite.textures.get(sprite_clip.sprite_number as usize) else {
return;
Expand Down Expand Up @@ -186,13 +189,15 @@ impl Cacheable for Actions {

pub struct ActionLoader {
game_file_loader: Arc<GameFileLoader>,
audio_engine: Arc<AudioEngine<GameFileLoader>>,
cache: SimpleCache<String, Arc<Actions>>,
}

impl ActionLoader {
pub fn new(game_file_loader: Arc<GameFileLoader>) -> Self {
pub fn new(game_file_loader: Arc<GameFileLoader>, audio_engine: Arc<AudioEngine<GameFileLoader>>) -> Self {
Self {
game_file_loader,
audio_engine,
cache: SimpleCache::new(
NonZeroU32::new(MAX_CACHE_COUNT).unwrap(),
NonZeroUsize::new(MAX_CACHE_SIZE).unwrap(),
Expand Down Expand Up @@ -231,6 +236,28 @@ impl ActionLoader {
}
};

let events: Vec<Option<SoundEffectKey>> = actions_data
.events
.iter()
.enumerate()
.map(|(_index, event)| {
if event.name.ends_with(".wav") {
let key = self.audio_engine.load(&event.name);
Some(key)
} else {
// TODO: NHA How do we need to handle the "atk" or "atk.txt" sounds?
#[cfg(feature = "debug")]
print_debug!(
"Found event without a '.wav' file extension at index `{}`: {:?}",
_index,
event.name
);

None
}
})
.collect();

#[cfg(feature = "debug")]
let saved_actions_data = actions_data.clone();

Expand All @@ -241,6 +268,7 @@ impl ActionLoader {
let sprite = Arc::new(Actions {
actions: actions_data.actions,
delays,
events,
#[cfg(feature = "debug")]
actions_data: saved_actions_data,
});
Expand Down
23 changes: 20 additions & 3 deletions korangar/src/loaders/animation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,18 @@ impl AnimationLoader {
color,
..Default::default()
};

let sound = if let Some(event_id) = motion.event_id
&& event_id != -1
&& let Some(event) = animation_pair.actions.events.get(event_id as usize).copied().flatten()
{
Some(event)
} else {
None
};

let frame = AnimationFrame {
sound,
size,
top_left: Vector2::zero(),
offset,
Expand Down Expand Up @@ -325,7 +336,7 @@ fn calculate_new_size(min_top: i32, max_bottom: i32, min_left: i32, max_right: i
}
let size_y = max_bottom - min_top + padding + 1;

return Vector2::new(size_x, size_y);
Vector2::new(size_x, size_y)
}

#[cfg(feature = "debug")]
Expand Down Expand Up @@ -380,11 +391,11 @@ fn calculate_scale_matrix(
) -> Matrix4<f32> {
// Scale the vertices (-1, 2), (-1, 0), (1, 2), (1, 0) to
// match the texture coordinates as specified above.
return Matrix4::from_nonuniform_scale(
Matrix4::from_nonuniform_scale(
(texture_bottom_right.x - texture_bottom_left.x) / 2.0,
(texture_top_left.y - texture_bottom_left.y) / 2.0,
1.0,
);
)
}

fn calculate_translation_matrix(
Expand Down Expand Up @@ -434,7 +445,9 @@ fn merge_frame(frames: &mut [AnimationFrame]) -> AnimationFrame {
},
..Default::default()
};

let frame = AnimationFrame {
sound: None,
size: Vector2::new(1, 1),
top_left: Vector2::zero(),
offset: Vector2::zero(),
Expand All @@ -446,6 +459,7 @@ fn merge_frame(frames: &mut [AnimationFrame]) -> AnimationFrame {
#[cfg(feature = "debug")]
vertical_matrix: Matrix4::identity(),
};

return frame;
}

Expand All @@ -467,6 +481,8 @@ fn merge_frame(frames: &mut [AnimationFrame]) -> AnimationFrame {
new_frame_parts.append(&mut frame.frame_parts);
}

let sound = frames.iter().filter_map(|frame| frame.sound).next();

// The origin is set at (0,0).
//
// The top-left point of the rectangle is calculated as
Expand All @@ -478,6 +494,7 @@ fn merge_frame(frames: &mut [AnimationFrame]) -> AnimationFrame {
// The new offset is calculated as
// center_point - origin.
AnimationFrame {
sound,
size: Vector2::new(new_width, new_height),
top_left: Vector2::zero(),
offset: Vector2::new(top_left_x + (new_width - 1) / 2, top_left_y + (new_height - 1) / 2),
Expand Down
38 changes: 23 additions & 15 deletions korangar/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ impl Client {
let mute_on_focus_loss = audio_settings.mapped(|settings| &settings.mute_on_focus_loss).new_remote();

let audio_engine = Arc::new(AudioEngine::new(game_file_loader.clone()));
audio_engine.set_background_music_volume(0.1);
});

time_phase!("create resource managers", {
Expand All @@ -380,7 +381,7 @@ impl Client {
let font_loader = Rc::new(RefCell::new(FontLoader::new(&game_file_loader, &texture_loader)));
let mut map_loader = MapLoader::new(device.clone(), queue.clone(), game_file_loader.clone(), audio_engine.clone());
let mut sprite_loader = SpriteLoader::new(device.clone(), queue.clone(), game_file_loader.clone());
let mut action_loader = ActionLoader::new(game_file_loader.clone());
let mut action_loader = ActionLoader::new(game_file_loader.clone(), audio_engine.clone());
let effect_loader = EffectLoader::new(game_file_loader.clone());
let animation_loader = AnimationLoader::new();

Expand Down Expand Up @@ -1839,7 +1840,7 @@ impl Client {

self.entities
.iter_mut()
.for_each(|entity| entity.update(&self.map, delta_time as f32, client_tick));
.for_each(|entity| entity.update(&self.audio_engine, &self.map, delta_time as f32, client_tick));

#[cfg(feature = "debug")]
update_entities_measurement.stop();
Expand Down Expand Up @@ -1921,7 +1922,7 @@ impl Client {
let listener = current_camera.focus_point() + EAR_HEIGHT;

self.audio_engine
.set_ambient_listener(listener, current_camera.view_direction(), current_camera.look_up_vector());
.set_spatial_listener(listener, current_camera.view_direction(), current_camera.look_up_vector());
self.audio_engine.update();

#[cfg(feature = "debug")]
Expand All @@ -1933,7 +1934,7 @@ impl Client {
#[cfg(feature = "debug")]
let render_settings = &*self.render_settings.get();
let walk_indicator_color = self.application.get_game_theme().indicator.walking.get();
let entities = &self.entities[..];

#[cfg(feature = "debug")]
let hovered_marker_identifier = match mouse_target {
Some(PickerTarget::Marker(marker_identifier)) => Some(marker_identifier),
Expand Down Expand Up @@ -1981,7 +1982,7 @@ impl Client {
&mut self.debug_marker_renderer,
current_camera,
render_settings,
entities,
&self.entities,
&point_light_set,
hovered_marker_identifier,
);
Expand All @@ -1991,7 +1992,7 @@ impl Client {
&mut self.middle_interface_renderer,
current_camera,
render_settings,
entities,
&self.entities,
&point_light_set,
hovered_marker_identifier,
);
Expand Down Expand Up @@ -2048,8 +2049,9 @@ impl Client {
#[cfg_attr(feature = "debug", korangar_debug::debug_condition(render_settings.show_entities))]
self.map.render_entities(
&mut self.directional_shadow_entity_instructions,
entities,
&mut self.entities,
&self.directional_shadow_camera,
false,
);
}

Expand Down Expand Up @@ -2119,12 +2121,13 @@ impl Client {
};

#[cfg_attr(feature = "debug", korangar_debug::debug_condition(render_settings.show_entities))]
self.map.render_entities(&mut self.entity_instructions, entities, entity_camera);
self.map
.render_entities(&mut self.entity_instructions, &mut self.entities, entity_camera, true);

#[cfg(feature = "debug")]
if render_settings.show_entities_debug {
self.map
.render_entities_debug(&mut self.rectangle_instructions, entities, entity_camera);
.render_entities_debug(&mut self.rectangle_instructions, &self.entities, entity_camera);
}

#[cfg_attr(feature = "debug", korangar_debug::debug_condition(render_settings.show_water))]
Expand Down Expand Up @@ -2158,13 +2161,18 @@ impl Client {
);
}

self.particle_holder
.render(&self.bottom_interface_renderer, current_camera, screen_size, scaling, entities);
self.particle_holder.render(
&self.bottom_interface_renderer,
current_camera,
screen_size,
scaling,
&self.entities,
);

self.effect_holder.render(&mut self.effect_renderer, current_camera);

if let Some(PickerTarget::Tile { x, y }) = mouse_target
&& !entities.is_empty()
&& !&self.entities.is_empty()
{
#[cfg_attr(feature = "debug", korangar_debug::debug_condition(render_settings.show_indicators))]
self.map.render_walk_indicator(
Expand All @@ -2173,7 +2181,7 @@ impl Client {
Vector2::new(x as usize, y as usize),
);
} else if let Some(PickerTarget::Entity(entity_id)) = mouse_target {
let entity = entities.iter().find(|entity| entity.get_entity_id() == entity_id);
let entity = &self.entities.iter().find(|entity| entity.get_entity_id() == entity_id);

if let Some(entity) = entity {
entity.render_status(
Expand All @@ -2199,11 +2207,11 @@ impl Client {
}
}

if !entities.is_empty() {
if !&self.entities.is_empty() {
#[cfg(feature = "debug")]
profile_block!("render player status");

entities[0].render_status(
self.entities[0].render_status(
&self.middle_interface_renderer,
current_camera,
self.application.get_game_theme(),
Expand Down
16 changes: 11 additions & 5 deletions korangar/src/world/animation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::sync::Arc;

use cgmath::{Array, EuclideanSpace, Matrix4, Point3, Transform, Vector2, Zero};
use korangar_audio::SoundEffectKey;
use korangar_interface::elements::PrototypeElement;
use korangar_util::container::Cacheable;
use ragnarok_packets::EntityId;
Expand Down Expand Up @@ -43,6 +44,7 @@ pub struct Animation {

#[derive(Clone)]
pub struct AnimationFrame {
pub sound: Option<SoundEffectKey>,
pub offset: Vector2<i32>,
pub top_left: Vector2<i32>,
pub size: Vector2<i32>,
Expand Down Expand Up @@ -109,7 +111,8 @@ impl AnimationData {
if self.entity_type == EntityType::Player && animation_state.action == ActionType::Idle {
frame = &animation.frames[0];
}
return frame;

frame
}

pub fn calculate_world_matrix(&self, camera: &dyn Camera, frame: &AnimationFrame, entity_position: Point3<f32>) -> Matrix4<f32> {
Expand All @@ -118,17 +121,15 @@ impl AnimationData {
let center_position = Vector2::new(-frame.offset.x as f32, frame.offset.y as f32 + ((frame.size.y - 1) / 2) as f32);
let origin = Point3::from_vec(center_position.extend(0.0)) * SPRITE_SCALE / TILE_SIZE;
let size = Vector2::new(frame.size.x as f32, frame.size.y as f32) * SPRITE_SCALE / TILE_SIZE;
let world_matrix = camera.billboard_matrix(entity_position, origin, size);

return world_matrix;
camera.billboard_matrix(entity_position, origin, size)
}

pub fn get_texture_coordinates(&self) -> (Vector2<f32>, Vector2<f32>) {
let cell_count = Vector2::new(1, 1);
let cell_position = Vector2::new(0, 0);
let texture_size = Vector2::new(1.0 / cell_count.x as f32, 1.0 / cell_count.y as f32);
let texture_position = Vector2::new(texture_size.x * cell_position.x as f32, texture_size.y * cell_position.y as f32);
return (texture_size, texture_position);
(texture_size, texture_position)
}

pub fn render(
Expand All @@ -140,10 +141,15 @@ impl AnimationData {
animation_state: &AnimationState,
head_direction: usize,
add_to_picker: bool,
sound_to_play: Option<&mut Option<SoundEffectKey>>,
) {
let frame = self.get_frame(animation_state, camera, head_direction);
let world_matrix = self.calculate_world_matrix(camera, frame, entity_position);

if let Some(sound_to_play) = sound_to_play {
*sound_to_play = frame.sound;
}

for (index, frame_part) in frame.frame_parts.iter().enumerate() {
let animation_index = frame_part.animation_index;
let sprite_number = frame_part.sprite_number;
Expand Down
Loading

0 comments on commit 6d682a3

Please sign in to comment.