From 4d7828ec94771e26889283c5db3696f07ce5a341 Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Sat, 22 May 2021 15:50:29 -0400 Subject: [PATCH 1/3] Make the camera zoom as the bow (or any ChargedRanged attack) is charging. --- CHANGELOG.md | 1 + common/src/states/charged_ranged.rs | 11 ++++++--- voxygen/src/session/mod.rs | 35 +++++++++++++++++++---------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82d00174ed..aca832c29f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Chat tabs - NPC's now hear certain sounds - Renamed Animal Trainers to Beastmasters and gave them their own set of armor to wear +- ChargedRanged attacks (such as some bow attacks) use an FOV zoom effect to indicate charge. - Add chest to each dungeon with unique loot ### Changed diff --git a/common/src/states/charged_ranged.rs b/common/src/states/charged_ranged.rs index 2b8de1ac42..9f8be59235 100644 --- a/common/src/states/charged_ranged.rs +++ b/common/src/states/charged_ranged.rs @@ -61,6 +61,13 @@ pub struct Data { pub exhausted: bool, } +impl Data { + /// How complete the charge is, on a scale of 0.0 to 1.0 + pub fn charge_frac(&self) -> f32 { + (self.timer.as_secs_f32() / self.static_data.charge_duration.as_secs_f32()).min(1.0) + } +} + impl CharacterBehavior for Data { fn behavior(&self, data: &JoinData) -> StateUpdate { let mut update = StateUpdate::from(data); @@ -91,9 +98,7 @@ impl CharacterBehavior for Data { }, StageSection::Charge => { if !input_is_pressed(data, self.static_data.ability_info.input) && !self.exhausted { - let charge_frac = (self.timer.as_secs_f32() - / self.static_data.charge_duration.as_secs_f32()) - .min(1.0); + let charge_frac = self.charge_frac(); let arrow = ProjectileConstructor::Arrow { damage: self.static_data.initial_damage as f32 + charge_frac * self.static_data.scaled_damage as f32, diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index 479fc9394e..edc1653dfe 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -295,6 +295,22 @@ impl PlayState for SessionState { camera.set_orientation(cam_dir); } + let client = self.client.borrow(); + let player_entity = client.entity(); + + let fov_scaling = { + if let Some(comp::CharacterState::ChargedRanged(cr)) = client + .state() + .read_storage::() + .get(player_entity) + { + 1.0 - 3.0 * cr.charge_frac() / 4.0 + } else { + 1.0 + } + }; + camera.set_fov((global_state.settings.graphics.fov as f32 * fov_scaling).to_radians()); + // Compute camera data camera.compute_dependents(&*self.client.borrow().state().terrain()); let camera::Dependents { @@ -305,18 +321,17 @@ impl PlayState for SessionState { let cam_pos = cam_pos + focus_off; let (is_aiming, aim_dir_offset) = { - let client = self.client.borrow(); let is_aiming = client .state() .read_storage::() - .get(client.entity()) + .get(player_entity) .map(|cs| cs.is_aimed()) .unwrap_or(false); ( is_aiming, if is_aiming && self.scene.camera().get_mode() == CameraMode::ThirdPerson { - Vec3::unit_z() * 0.05 + Vec3::unit_z() * 0.025 } else { Vec3::zero() }, @@ -324,25 +339,21 @@ impl PlayState for SessionState { }; self.is_aiming = is_aiming; - let player_entity = self.client.borrow().entity(); - - let can_build = self - .client - .borrow() + let can_build = client .state() .read_storage::() .get(player_entity) .map_or_else(|| false, |cb| cb.enabled); - let is_mining = self - .client - .borrow() + let is_mining = client .inventories() .get(player_entity) .and_then(|inv| inv.equipped(EquipSlot::ActiveMainhand)) .and_then(|item| item.tool()) .map_or(false, |tool| tool.kind == ToolKind::Pick) - && self.client.borrow().is_wielding() == Some(true); + && client.is_wielding() == Some(true); + + drop(client); // Check to see whether we're aiming at anything let (build_pos, select_pos, target_entity) = From 7a97fbb5cf5807d3b1b86bcee33f633678181b86 Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Sun, 23 May 2021 17:31:44 -0400 Subject: [PATCH 2/3] Add zoom scaling as well as FOV scaling to ChargedRanged, and restore the old zoom afterwards. --- common/src/states/charged_ranged.rs | 6 +++++- voxygen/src/scene/camera.rs | 12 +++++++++++- voxygen/src/session/mod.rs | 25 +++++++++++++++---------- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/common/src/states/charged_ranged.rs b/common/src/states/charged_ranged.rs index 9f8be59235..ea57674868 100644 --- a/common/src/states/charged_ranged.rs +++ b/common/src/states/charged_ranged.rs @@ -64,7 +64,11 @@ pub struct Data { impl Data { /// How complete the charge is, on a scale of 0.0 to 1.0 pub fn charge_frac(&self) -> f32 { - (self.timer.as_secs_f32() / self.static_data.charge_duration.as_secs_f32()).min(1.0) + if let StageSection::Charge = self.stage_section { + (self.timer.as_secs_f32() / self.static_data.charge_duration.as_secs_f32()).min(1.0) + } else { + 0.0 + } } } diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index 9f018445e5..fc34f8c93b 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -42,6 +42,7 @@ pub struct Camera { ori: Vec3, tgt_dist: f32, dist: f32, + tgt_fov: f32, fov: f32, aspect: f32, mode: CameraMode, @@ -76,6 +77,7 @@ impl Camera { ori: Vec3::zero(), tgt_dist: 10.0, dist: 10.0, + tgt_fov: 1.1, fov: 1.1, aspect, mode, @@ -222,6 +224,14 @@ impl Camera { ); } + if (self.fov - self.tgt_fov).abs() > 0.01 { + self.fov = f32::lerp( + self.fov, + self.tgt_fov, + 0.65 * (delta as f32) / self.interp_time(), + ); + } + if (self.focus - self.tgt_focus).magnitude_squared() > 0.001 { let lerped_focus = Lerp::lerp( self.focus, @@ -290,7 +300,7 @@ impl Camera { pub fn get_fov(&self) -> f32 { self.fov } /// Set the field of view of the camera in radians. - pub fn set_fov(&mut self, fov: f32) { self.fov = fov; } + pub fn set_fov(&mut self, fov: f32) { self.tgt_fov = fov; } /// Set the FOV in degrees pub fn set_fov_deg(&mut self, fov: u16) { diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index edc1653dfe..3133a024f6 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -72,6 +72,7 @@ pub struct SessionState { target_entity: Option, selected_entity: Option<(specs::Entity, std::time::Instant)>, interactable: Option, + saved_zoom_dist: Option, } /// Represents an active game session (i.e., the one being played). @@ -118,6 +119,7 @@ impl SessionState { target_entity: None, selected_entity: None, interactable: None, + saved_zoom_dist: None, } } @@ -298,17 +300,20 @@ impl PlayState for SessionState { let client = self.client.borrow(); let player_entity = client.entity(); - let fov_scaling = { - if let Some(comp::CharacterState::ChargedRanged(cr)) = client - .state() - .read_storage::() - .get(player_entity) - { - 1.0 - 3.0 * cr.charge_frac() / 4.0 - } else { - 1.0 + let mut fov_scaling = 1.0; + if let Some(comp::CharacterState::ChargedRanged(cr)) = client + .state() + .read_storage::() + .get(player_entity) + { + fov_scaling -= 3.0 * cr.charge_frac() / 4.0; + if self.saved_zoom_dist.is_none() { + self.saved_zoom_dist = Some(camera.get_distance()); + camera.set_distance(0.0); } - }; + } else if let Some(dist) = self.saved_zoom_dist.take() { + camera.set_distance(dist); + } camera.set_fov((global_state.settings.graphics.fov as f32 * fov_scaling).to_radians()); // Compute camera data From d6442dbd3b1f60e8a68132a9f1fe67c1d5a0a256 Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Wed, 26 May 2021 11:51:29 -0400 Subject: [PATCH 3/3] Change the ChargedRanged zoom distance from 0.0 to 2.0, and add a delay after the mouse click before the zoom starts (i.e. hold to zoom, spam click will not zoom). --- voxygen/src/session/mod.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index 3133a024f6..969e70287b 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -306,11 +306,17 @@ impl PlayState for SessionState { .read_storage::() .get(player_entity) { - fov_scaling -= 3.0 * cr.charge_frac() / 4.0; - if self.saved_zoom_dist.is_none() { - self.saved_zoom_dist = Some(camera.get_distance()); - camera.set_distance(0.0); + if cr.charge_frac() > 0.25 { + fov_scaling -= 3.0 * cr.charge_frac() / 4.0; } + let max_dist = if let Some(dist) = self.saved_zoom_dist { + dist + } else { + let dist = camera.get_distance(); + self.saved_zoom_dist = Some(dist); + dist + }; + camera.set_distance(Lerp::lerp(max_dist, 2.0, 1.0 - fov_scaling)); } else if let Some(dist) = self.saved_zoom_dist.take() { camera.set_distance(dist); }