mirror of
https://gitlab.com/veloren/veloren.git
synced 2025-07-25 04:42:23 +00:00
Merge branch 'aweinstock/bow-zoom-charge-master' into 'master'
Make the camera zoom as the bow (or any ChargedRanged attack) is charging. See merge request veloren/veloren!2339
This commit is contained in:
@ -62,6 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Chat tabs
|
- Chat tabs
|
||||||
- NPC's now hear certain sounds
|
- NPC's now hear certain sounds
|
||||||
- Renamed Animal Trainers to Beastmasters and gave them their own set of armor to wear
|
- 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
|
- Add chest to each dungeon with unique loot
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -61,6 +61,17 @@ pub struct Data {
|
|||||||
pub exhausted: bool,
|
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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CharacterBehavior for Data {
|
impl CharacterBehavior for Data {
|
||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
@ -91,9 +102,7 @@ impl CharacterBehavior for Data {
|
|||||||
},
|
},
|
||||||
StageSection::Charge => {
|
StageSection::Charge => {
|
||||||
if !input_is_pressed(data, self.static_data.ability_info.input) && !self.exhausted {
|
if !input_is_pressed(data, self.static_data.ability_info.input) && !self.exhausted {
|
||||||
let charge_frac = (self.timer.as_secs_f32()
|
let charge_frac = self.charge_frac();
|
||||||
/ self.static_data.charge_duration.as_secs_f32())
|
|
||||||
.min(1.0);
|
|
||||||
let arrow = ProjectileConstructor::Arrow {
|
let arrow = ProjectileConstructor::Arrow {
|
||||||
damage: self.static_data.initial_damage as f32
|
damage: self.static_data.initial_damage as f32
|
||||||
+ charge_frac * self.static_data.scaled_damage as f32,
|
+ charge_frac * self.static_data.scaled_damage as f32,
|
||||||
|
@ -42,6 +42,7 @@ pub struct Camera {
|
|||||||
ori: Vec3<f32>,
|
ori: Vec3<f32>,
|
||||||
tgt_dist: f32,
|
tgt_dist: f32,
|
||||||
dist: f32,
|
dist: f32,
|
||||||
|
tgt_fov: f32,
|
||||||
fov: f32,
|
fov: f32,
|
||||||
aspect: f32,
|
aspect: f32,
|
||||||
mode: CameraMode,
|
mode: CameraMode,
|
||||||
@ -76,6 +77,7 @@ impl Camera {
|
|||||||
ori: Vec3::zero(),
|
ori: Vec3::zero(),
|
||||||
tgt_dist: 10.0,
|
tgt_dist: 10.0,
|
||||||
dist: 10.0,
|
dist: 10.0,
|
||||||
|
tgt_fov: 1.1,
|
||||||
fov: 1.1,
|
fov: 1.1,
|
||||||
aspect,
|
aspect,
|
||||||
mode,
|
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 {
|
if (self.focus - self.tgt_focus).magnitude_squared() > 0.001 {
|
||||||
let lerped_focus = Lerp::lerp(
|
let lerped_focus = Lerp::lerp(
|
||||||
self.focus,
|
self.focus,
|
||||||
@ -290,7 +300,7 @@ impl Camera {
|
|||||||
pub fn get_fov(&self) -> f32 { self.fov }
|
pub fn get_fov(&self) -> f32 { self.fov }
|
||||||
|
|
||||||
/// Set the field of view of the camera in radians.
|
/// 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
|
/// Set the FOV in degrees
|
||||||
pub fn set_fov_deg(&mut self, fov: u16) {
|
pub fn set_fov_deg(&mut self, fov: u16) {
|
||||||
|
@ -72,6 +72,7 @@ pub struct SessionState {
|
|||||||
target_entity: Option<specs::Entity>,
|
target_entity: Option<specs::Entity>,
|
||||||
selected_entity: Option<(specs::Entity, std::time::Instant)>,
|
selected_entity: Option<(specs::Entity, std::time::Instant)>,
|
||||||
interactable: Option<Interactable>,
|
interactable: Option<Interactable>,
|
||||||
|
saved_zoom_dist: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an active game session (i.e., the one being played).
|
/// Represents an active game session (i.e., the one being played).
|
||||||
@ -118,6 +119,7 @@ impl SessionState {
|
|||||||
target_entity: None,
|
target_entity: None,
|
||||||
selected_entity: None,
|
selected_entity: None,
|
||||||
interactable: None,
|
interactable: None,
|
||||||
|
saved_zoom_dist: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,6 +297,31 @@ impl PlayState for SessionState {
|
|||||||
camera.set_orientation(cam_dir);
|
camera.set_orientation(cam_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let client = self.client.borrow();
|
||||||
|
let player_entity = client.entity();
|
||||||
|
|
||||||
|
let mut fov_scaling = 1.0;
|
||||||
|
if let Some(comp::CharacterState::ChargedRanged(cr)) = client
|
||||||
|
.state()
|
||||||
|
.read_storage::<comp::CharacterState>()
|
||||||
|
.get(player_entity)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
camera.set_fov((global_state.settings.graphics.fov as f32 * fov_scaling).to_radians());
|
||||||
|
|
||||||
// Compute camera data
|
// Compute camera data
|
||||||
camera.compute_dependents(&*self.client.borrow().state().terrain());
|
camera.compute_dependents(&*self.client.borrow().state().terrain());
|
||||||
let camera::Dependents {
|
let camera::Dependents {
|
||||||
@ -305,18 +332,17 @@ impl PlayState for SessionState {
|
|||||||
let cam_pos = cam_pos + focus_off;
|
let cam_pos = cam_pos + focus_off;
|
||||||
|
|
||||||
let (is_aiming, aim_dir_offset) = {
|
let (is_aiming, aim_dir_offset) = {
|
||||||
let client = self.client.borrow();
|
|
||||||
let is_aiming = client
|
let is_aiming = client
|
||||||
.state()
|
.state()
|
||||||
.read_storage::<comp::CharacterState>()
|
.read_storage::<comp::CharacterState>()
|
||||||
.get(client.entity())
|
.get(player_entity)
|
||||||
.map(|cs| cs.is_aimed())
|
.map(|cs| cs.is_aimed())
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
(
|
(
|
||||||
is_aiming,
|
is_aiming,
|
||||||
if is_aiming && self.scene.camera().get_mode() == CameraMode::ThirdPerson {
|
if is_aiming && self.scene.camera().get_mode() == CameraMode::ThirdPerson {
|
||||||
Vec3::unit_z() * 0.05
|
Vec3::unit_z() * 0.025
|
||||||
} else {
|
} else {
|
||||||
Vec3::zero()
|
Vec3::zero()
|
||||||
},
|
},
|
||||||
@ -324,25 +350,21 @@ impl PlayState for SessionState {
|
|||||||
};
|
};
|
||||||
self.is_aiming = is_aiming;
|
self.is_aiming = is_aiming;
|
||||||
|
|
||||||
let player_entity = self.client.borrow().entity();
|
let can_build = client
|
||||||
|
|
||||||
let can_build = self
|
|
||||||
.client
|
|
||||||
.borrow()
|
|
||||||
.state()
|
.state()
|
||||||
.read_storage::<comp::CanBuild>()
|
.read_storage::<comp::CanBuild>()
|
||||||
.get(player_entity)
|
.get(player_entity)
|
||||||
.map_or_else(|| false, |cb| cb.enabled);
|
.map_or_else(|| false, |cb| cb.enabled);
|
||||||
|
|
||||||
let is_mining = self
|
let is_mining = client
|
||||||
.client
|
|
||||||
.borrow()
|
|
||||||
.inventories()
|
.inventories()
|
||||||
.get(player_entity)
|
.get(player_entity)
|
||||||
.and_then(|inv| inv.equipped(EquipSlot::ActiveMainhand))
|
.and_then(|inv| inv.equipped(EquipSlot::ActiveMainhand))
|
||||||
.and_then(|item| item.tool())
|
.and_then(|item| item.tool())
|
||||||
.map_or(false, |tool| tool.kind == ToolKind::Pick)
|
.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
|
// Check to see whether we're aiming at anything
|
||||||
let (build_pos, select_pos, target_entity) =
|
let (build_pos, select_pos, target_entity) =
|
||||||
|
Reference in New Issue
Block a user