mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'combat' of https://gitlab.com/veloren/veloren into combat
This commit is contained in:
commit
8fd774f21a
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -4847,8 +4847,7 @@ checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
[[package]]
|
||||
name = "vek"
|
||||
version = "0.9.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b833a133490ae98e9e3db1c77fc28e844f8e51b12eb35b4ab8a2082cb7cb441a"
|
||||
source = "git+https://github.com/Imberflur/vek?branch=is_normalized#7442254deb67ad6930bedc671057d14ea8e885eb"
|
||||
dependencies = [
|
||||
"approx 0.1.1",
|
||||
"num-integer",
|
||||
|
@ -68,3 +68,6 @@ debug = false
|
||||
[profile.releasedebuginfo]
|
||||
inherits = 'release'
|
||||
debug = 1
|
||||
|
||||
[patch.crates-io]
|
||||
vek = {git = "https://github.com/Imberflur/vek", branch = "is_normalized"}
|
||||
|
@ -307,11 +307,49 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_loadout(&mut self) { self.control_action(ControlAction::SwapLoadout); }
|
||||
pub fn swap_loadout(&mut self) {
|
||||
let can_swap = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<comp::CharacterState>()
|
||||
.get(self.entity)
|
||||
.map(|cs| cs.can_swap());
|
||||
match can_swap {
|
||||
Some(true) => self.control_action(ControlAction::SwapLoadout),
|
||||
Some(false) => {},
|
||||
None => warn!("Can't swap, client entity doesn't have a `CharacterState`"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_wield(&mut self) { self.control_action(ControlAction::ToggleWield); }
|
||||
pub fn toggle_wield(&mut self) {
|
||||
let is_wielding = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<comp::CharacterState>()
|
||||
.get(self.entity)
|
||||
.map(|cs| cs.is_wield());
|
||||
|
||||
pub fn toggle_sit(&mut self) { self.control_action(ControlAction::ToggleSit); }
|
||||
match is_wielding {
|
||||
Some(true) => self.control_action(ControlAction::Unwield),
|
||||
Some(false) => self.control_action(ControlAction::Wield),
|
||||
None => warn!("Can't toggle wield, client entity doesn't have a `CharacterState`"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_sit(&mut self) {
|
||||
let is_sitting = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<comp::CharacterState>()
|
||||
.get(self.entity)
|
||||
.map(|cs| matches!(cs, comp::CharacterState::Sit));
|
||||
|
||||
match is_sitting {
|
||||
Some(true) => self.control_action(ControlAction::Stand),
|
||||
Some(false) => self.control_action(ControlAction::Sit),
|
||||
None => warn!("Can't toggle sit, client entity doesn't have a `CharacterState`"),
|
||||
}
|
||||
}
|
||||
|
||||
fn control_action(&mut self, control_action: ControlAction) {
|
||||
if let Some(controller) = self
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::sync::Uid;
|
||||
use crate::{sync::Uid, util::Dir};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
use std::time::Duration;
|
||||
@ -18,8 +18,10 @@ pub enum ControlEvent {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ControlAction {
|
||||
SwapLoadout,
|
||||
ToggleWield,
|
||||
ToggleSit,
|
||||
Wield,
|
||||
Unwield,
|
||||
Sit,
|
||||
Stand,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -144,7 +146,7 @@ pub struct ControllerInputs {
|
||||
pub charge: Input,
|
||||
pub climb: Option<Climb>,
|
||||
pub move_dir: Vec2<f32>,
|
||||
pub look_dir: Vec3<f32>,
|
||||
pub look_dir: Dir,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::sync::Uid;
|
||||
use crate::{sync::Uid, util::Dir};
|
||||
use specs::{Component, FlaggedStorage, NullStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
use vek::*;
|
||||
@ -21,7 +21,7 @@ impl Component for Vel {
|
||||
|
||||
// Orientation
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Ori(pub Vec3<f32>);
|
||||
pub struct Ori(pub Dir);
|
||||
|
||||
impl Component for Ori {
|
||||
type Storage = IDVStorage<Self>;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{comp, sync::Uid};
|
||||
use crate::{comp, sync::Uid, util::Dir};
|
||||
use comp::{item::ToolKind, InventoryUpdateEvent};
|
||||
use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
@ -47,19 +47,11 @@ pub enum SfxEvent {
|
||||
pub enum LocalEvent {
|
||||
/// Applies upward force to entity's `Vel`
|
||||
Jump(EcsEntity),
|
||||
/// Applies the `force` + implicit upward force, in `dir` direction to
|
||||
/// Applies the `force` + implicit upward force to
|
||||
/// `entity`'s `Vel`
|
||||
KnockUp {
|
||||
entity: EcsEntity,
|
||||
dir: Vec3<f32>,
|
||||
force: f32,
|
||||
},
|
||||
/// Applies the `force`, in `dir` direction to `entity`'s `Vel`
|
||||
ApplyForce {
|
||||
entity: EcsEntity,
|
||||
dir: Vec3<f32>,
|
||||
force: f32,
|
||||
},
|
||||
KnockUp { entity: EcsEntity, force: Vec3<f32> },
|
||||
/// Applies the `force` to `entity`'s `Vel`
|
||||
ApplyForce { entity: EcsEntity, force: Vec3<f32> },
|
||||
/// Applies leaping force to `entity`'s `Vel` away from `wall_dir` direction
|
||||
WallLeap {
|
||||
entity: EcsEntity,
|
||||
@ -87,7 +79,7 @@ pub enum ServerEvent {
|
||||
Respawn(EcsEntity),
|
||||
Shoot {
|
||||
entity: EcsEntity,
|
||||
dir: Vec3<f32>,
|
||||
dir: Dir,
|
||||
body: comp::Body,
|
||||
light: Option<comp::LightEmitter>,
|
||||
projectile: comp::Projectile,
|
||||
|
@ -355,15 +355,17 @@ impl State {
|
||||
vel.0.z = HUMANOID_JUMP_ACCEL;
|
||||
}
|
||||
},
|
||||
LocalEvent::KnockUp { entity, dir, force } => {
|
||||
LocalEvent::KnockUp { entity, force } => {
|
||||
if let Some(vel) = velocities.get_mut(entity) {
|
||||
vel.0 = dir * force;
|
||||
vel.0 = force;
|
||||
vel.0.z = HUMANOID_JUMP_ACCEL;
|
||||
}
|
||||
},
|
||||
LocalEvent::ApplyForce { entity, dir, force } => {
|
||||
LocalEvent::ApplyForce { entity, force } => {
|
||||
// TODO: this sets the velocity directly to the value of `force`, consider
|
||||
// renaming the event or changing the behavior
|
||||
if let Some(vel) = velocities.get_mut(entity) {
|
||||
vel.0 = dir * force;
|
||||
vel.0 = force;
|
||||
}
|
||||
},
|
||||
LocalEvent::WallLeap { entity, wall_dir } => {
|
||||
|
@ -23,7 +23,7 @@ impl CharacterBehavior for Data {
|
||||
if self.only_up {
|
||||
update.vel.0.z += 500.0 * data.dt.0;
|
||||
} else {
|
||||
update.vel.0 += data.inputs.look_dir * 500.0 * data.dt.0;
|
||||
update.vel.0 += *data.inputs.look_dir * 500.0 * data.dt.0;
|
||||
}
|
||||
update.character = CharacterState::Boost(Data {
|
||||
duration: self
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
character_behavior::{CharacterBehavior, JoinData},
|
||||
phys::GRAVITY,
|
||||
},
|
||||
util::safe_slerp,
|
||||
util::Dir,
|
||||
};
|
||||
use vek::{
|
||||
vec::{Vec2, Vec3},
|
||||
@ -23,7 +23,13 @@ impl CharacterBehavior for Data {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
// If no wall is in front of character or we stopped climbing;
|
||||
if data.physics.on_wall.is_none() || data.physics.on_ground || data.inputs.climb.is_none() {
|
||||
let (wall_dir, climb) = if let (Some(wall_dir), Some(climb), false) = (
|
||||
data.physics.on_wall,
|
||||
data.inputs.climb,
|
||||
data.physics.on_ground,
|
||||
) {
|
||||
(wall_dir, climb)
|
||||
} else {
|
||||
if data.inputs.jump.is_pressed() {
|
||||
// They've climbed atop something, give them a boost
|
||||
update
|
||||
@ -32,7 +38,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
update.character = CharacterState::Idle {};
|
||||
return update;
|
||||
}
|
||||
};
|
||||
|
||||
// Move player
|
||||
update.vel.0 += Vec2::broadcast(data.dt.0)
|
||||
@ -44,11 +50,9 @@ impl CharacterBehavior for Data {
|
||||
};
|
||||
|
||||
// Expend energy if climbing
|
||||
let energy_use = match data.inputs.climb {
|
||||
Some(Climb::Up) | Some(Climb::Down) => 8,
|
||||
Some(Climb::Hold) => 1,
|
||||
// Note: this is currently unreachable
|
||||
None => 0,
|
||||
let energy_use = match climb {
|
||||
Climb::Up | Climb::Down => 8,
|
||||
Climb::Hold => 1,
|
||||
};
|
||||
if let Err(_) = update
|
||||
.energy
|
||||
@ -58,25 +62,17 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// Set orientation direction based on wall direction
|
||||
let ori_dir = if let Some(wall_dir) = data.physics.on_wall {
|
||||
Vec2::from(wall_dir)
|
||||
} else {
|
||||
Vec2::from(update.vel.0)
|
||||
};
|
||||
let ori_dir = Vec2::from(wall_dir);
|
||||
|
||||
// Smooth orientation
|
||||
update.ori.0 = safe_slerp(
|
||||
update.ori.0 = Dir::slerp_to_vec3(
|
||||
update.ori.0,
|
||||
ori_dir.into(),
|
||||
if data.physics.on_ground { 9.0 } else { 2.0 } * data.dt.0,
|
||||
);
|
||||
|
||||
// Apply Vertical Climbing Movement
|
||||
if let (Some(climb), true, Some(_wall_dir)) = (
|
||||
data.inputs.climb,
|
||||
update.vel.0.z <= CLIMB_SPEED,
|
||||
data.physics.on_wall,
|
||||
) {
|
||||
if update.vel.0.z <= CLIMB_SPEED {
|
||||
match climb {
|
||||
Climb::Down => {
|
||||
update.vel.0 -=
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
||||
states::utils::*,
|
||||
sys::character_behavior::*,
|
||||
util::safe_slerp,
|
||||
util::Dir,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
@ -27,9 +27,9 @@ impl CharacterBehavior for Data {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
if self.initialize {
|
||||
update.vel.0 = data.inputs.look_dir * 20.0;
|
||||
update.vel.0 = *data.inputs.look_dir * 20.0;
|
||||
if let Some(dir) = Vec3::from(data.vel.0.xy()).try_normalized() {
|
||||
update.ori.0 = dir;
|
||||
update.ori.0 = dir.into();
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
}
|
||||
|
||||
update.ori.0 = safe_slerp(update.ori.0, update.vel.0, 9.0 * data.dt.0);
|
||||
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, update.vel.0, 9.0 * data.dt.0);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{CharacterState, StateUpdate},
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
util::safe_slerp,
|
||||
util::Dir,
|
||||
};
|
||||
use vek::Vec2;
|
||||
|
||||
@ -40,7 +40,7 @@ impl CharacterBehavior for Data {
|
||||
|
||||
// Determine orientation vector from movement direction vector
|
||||
let ori_dir = Vec2::from(update.vel.0);
|
||||
update.ori.0 = safe_slerp(update.ori.0, ori_dir.into(), 0.1);
|
||||
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, ori_dir.into(), 2.0 * data.dt.0);
|
||||
|
||||
// Apply Glide antigrav lift
|
||||
if Vec2::<f32>::from(update.vel.0).magnitude_squared() < GLIDE_SPEED.powf(2.0)
|
||||
|
@ -20,13 +20,13 @@ impl CharacterBehavior for Data {
|
||||
update
|
||||
}
|
||||
|
||||
fn toggle_wield(&self, data: &JoinData) -> StateUpdate {
|
||||
fn wield(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_wield(data, &mut update);
|
||||
update
|
||||
}
|
||||
|
||||
fn toggle_sit(&self, data: &JoinData) -> StateUpdate {
|
||||
fn sit(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_sit(data, &mut update);
|
||||
update
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{CharacterState, StateUpdate},
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
util::safe_slerp,
|
||||
util::Dir,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
@ -28,7 +28,7 @@ impl CharacterBehavior for Data {
|
||||
* ROLL_SPEED;
|
||||
|
||||
// Smooth orientation
|
||||
update.ori.0 = safe_slerp(update.ori.0, update.vel.0.into(), 9.0 * data.dt.0);
|
||||
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, update.vel.0, 9.0 * data.dt.0);
|
||||
|
||||
if self.remaining_duration == Duration::default() {
|
||||
// Roll duration has expired
|
||||
|
@ -21,13 +21,13 @@ impl CharacterBehavior for Data {
|
||||
update
|
||||
}
|
||||
|
||||
fn toggle_wield(&self, data: &JoinData) -> StateUpdate {
|
||||
fn wield(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_wield(data, &mut update);
|
||||
update
|
||||
}
|
||||
|
||||
fn toggle_sit(&self, data: &JoinData) -> StateUpdate {
|
||||
fn stand(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
// Try to Fall/Stand up/Move
|
||||
update.character = CharacterState::Idle;
|
||||
|
@ -57,7 +57,7 @@ impl CharacterBehavior for Data {
|
||||
if !self.initialized {
|
||||
update.vel.0 = Vec3::zero();
|
||||
if let Some(dir) = data.inputs.look_dir.try_normalized() {
|
||||
update.ori.0 = dir;
|
||||
update.ori.0 = dir.into();
|
||||
}
|
||||
}
|
||||
let initialized = true;
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
event::LocalEvent,
|
||||
states::*,
|
||||
sys::{character_behavior::JoinData, phys::GRAVITY},
|
||||
util::safe_slerp,
|
||||
util::Dir,
|
||||
};
|
||||
use vek::vec::Vec2;
|
||||
|
||||
@ -68,13 +68,13 @@ fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
||||
pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, strength: f32) {
|
||||
// Set direction based on move direction
|
||||
let ori_dir = if update.character.is_attack() || update.character.is_block() {
|
||||
Vec2::from(data.inputs.look_dir)
|
||||
Vec2::from(*data.inputs.look_dir)
|
||||
} else {
|
||||
Vec2::from(data.inputs.move_dir)
|
||||
};
|
||||
|
||||
// Smooth orientation
|
||||
update.ori.0 = safe_slerp(update.ori.0, ori_dir.into(), strength * data.dt.0);
|
||||
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, ori_dir.into(), strength * data.dt.0);
|
||||
}
|
||||
|
||||
/// Updates components to move player as if theyre swimming
|
||||
|
@ -22,13 +22,13 @@ impl CharacterBehavior for Data {
|
||||
update
|
||||
}
|
||||
|
||||
fn toggle_sit(&self, data: &JoinData) -> StateUpdate {
|
||||
fn sit(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_sit(data, &mut update);
|
||||
update
|
||||
}
|
||||
|
||||
fn toggle_wield(&self, data: &JoinData) -> StateUpdate {
|
||||
fn unwield(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
update.character = CharacterState::Idle;
|
||||
update
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::{
|
||||
comp::{self, agent::Activity, Agent, Alignment, Controller, MountState, Pos, Stats},
|
||||
comp::{self, agent::Activity, Agent, Alignment, Controller, MountState, Ori, Pos, Stats},
|
||||
path::Chaser,
|
||||
state::Time,
|
||||
sync::UidAllocator,
|
||||
terrain::TerrainGrid,
|
||||
util::Dir,
|
||||
vol::ReadVol,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
@ -21,6 +22,7 @@ impl<'a> System<'a> for Sys {
|
||||
Read<'a, Time>,
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Ori>,
|
||||
ReadStorage<'a, Stats>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
ReadStorage<'a, Alignment>,
|
||||
@ -36,6 +38,7 @@ impl<'a> System<'a> for Sys {
|
||||
time,
|
||||
entities,
|
||||
positions,
|
||||
orientations,
|
||||
stats,
|
||||
terrain,
|
||||
alignments,
|
||||
@ -44,9 +47,10 @@ impl<'a> System<'a> for Sys {
|
||||
mount_states,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
for (entity, pos, alignment, agent, controller, mount_state) in (
|
||||
for (entity, pos, ori, alignment, agent, controller, mount_state) in (
|
||||
&entities,
|
||||
&positions,
|
||||
&orientations,
|
||||
alignments.maybe(),
|
||||
&mut agents,
|
||||
&mut controllers,
|
||||
@ -70,9 +74,11 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
controller.reset();
|
||||
|
||||
//TODO: Make npcs have valid `look_dir` during all activities
|
||||
let mut inputs = &mut controller.inputs;
|
||||
|
||||
// Default to looking in orientation direction
|
||||
inputs.look_dir = ori.0;
|
||||
|
||||
const AVG_FOLLOW_DIST: f32 = 6.0;
|
||||
const MAX_FOLLOW_DIST: f32 = 12.0;
|
||||
const MAX_CHASE_DIST: f32 = 24.0;
|
||||
@ -162,7 +168,9 @@ impl<'a> System<'a> for Sys {
|
||||
.copied()
|
||||
.unwrap_or(Alignment::Owned(*target)),
|
||||
) {
|
||||
inputs.look_dir = tgt_pos.0 - pos.0;
|
||||
if let Some(dir) = Dir::from_unnormalized(tgt_pos.0 - pos.0) {
|
||||
inputs.look_dir = dir;
|
||||
}
|
||||
|
||||
// Don't attack entities we are passive towards
|
||||
// TODO: This is here, it's a bit of a hack
|
||||
|
@ -17,13 +17,17 @@ pub trait CharacterBehavior {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate;
|
||||
// Impl these to provide behavior for these inputs
|
||||
fn swap_loadout(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn toggle_wield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn toggle_sit(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn wield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn unwield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn sit(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn stand(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn handle_event(&self, data: &JoinData, event: ControlAction) -> StateUpdate {
|
||||
match event {
|
||||
ControlAction::SwapLoadout => self.swap_loadout(data),
|
||||
ControlAction::ToggleWield => self.toggle_wield(data),
|
||||
ControlAction::ToggleSit => self.toggle_sit(data),
|
||||
ControlAction::Wield => self.wield(data),
|
||||
ControlAction::Unwield => self.unwield(data),
|
||||
ControlAction::Sit => self.sit(data),
|
||||
ControlAction::Stand => self.stand(data),
|
||||
}
|
||||
}
|
||||
// fn init(data: &JoinData) -> CharacterState;
|
||||
|
@ -4,6 +4,7 @@ use crate::{
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
sync::Uid,
|
||||
util::Dir,
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
@ -92,7 +93,7 @@ impl<'a> System<'a> for Sys {
|
||||
// 2D versions
|
||||
let pos2 = Vec2::from(pos.0);
|
||||
let pos_b2 = Vec2::<f32>::from(pos_b.0);
|
||||
let ori2 = Vec2::from(ori.0);
|
||||
let ori2 = Vec2::from(*ori.0);
|
||||
|
||||
// Scales
|
||||
let scale = scale_maybe.map_or(1.0, |s| s.0);
|
||||
@ -140,8 +141,8 @@ impl<'a> System<'a> for Sys {
|
||||
if attack.knockback != 0.0 {
|
||||
local_emitter.emit(LocalEvent::ApplyForce {
|
||||
entity: b,
|
||||
dir: Vec3::slerp(ori.0, Vec3::new(0.0, 0.0, 1.0), 0.5),
|
||||
force: attack.knockback,
|
||||
force: attack.knockback
|
||||
* *Dir::slerp(ori.0, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5),
|
||||
});
|
||||
}
|
||||
attack.hit_count += 1;
|
||||
|
@ -63,12 +63,6 @@ impl<'a> System<'a> for Sys {
|
||||
inputs.move_dir
|
||||
};
|
||||
|
||||
// Update `inputs.look_dir`
|
||||
inputs
|
||||
.look_dir
|
||||
.try_normalized()
|
||||
.unwrap_or(inputs.move_dir.into());
|
||||
|
||||
// Process other controller events
|
||||
for event in controller.events.drain(..) {
|
||||
match event {
|
||||
|
@ -5,6 +5,7 @@ use crate::{
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
state::DeltaTime,
|
||||
sync::UidAllocator,
|
||||
util::Dir,
|
||||
};
|
||||
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
use std::time::Duration;
|
||||
@ -107,8 +108,8 @@ impl<'a> System<'a> for Sys {
|
||||
{
|
||||
local_emitter.emit(LocalEvent::ApplyForce {
|
||||
entity,
|
||||
dir: Vec3::slerp(ori.0, Vec3::new(0.0, 0.0, 1.0), 0.5),
|
||||
force: knockback,
|
||||
force: knockback
|
||||
* *Dir::slerp(ori.0, Dir::new(Vec3::unit_z()), 0.5),
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -145,7 +146,7 @@ impl<'a> System<'a> for Sys {
|
||||
.get(entity)
|
||||
.and_then(|vel| vel.0.try_normalized())
|
||||
{
|
||||
ori.0 = dir;
|
||||
ori.0 = dir.into();
|
||||
}
|
||||
}
|
||||
|
||||
|
186
common/src/util/dir.rs
Normal file
186
common/src/util/dir.rs
Normal file
@ -0,0 +1,186 @@
|
||||
use vek::*;
|
||||
|
||||
/// Type representing a direction using Vec3 that is normalized and NaN free
|
||||
/// These properties are enforced actively via panics when `debug_assertions` is
|
||||
/// enabled
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(into = "SerdeDir")]
|
||||
#[serde(from = "SerdeDir")]
|
||||
pub struct Dir(Vec3<f32>);
|
||||
impl Default for Dir {
|
||||
fn default() -> Self { Self(Vec3::unit_y()) }
|
||||
}
|
||||
|
||||
// Validate at Deserialization
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
struct SerdeDir(Vec3<f32>);
|
||||
impl From<SerdeDir> for Dir {
|
||||
fn from(dir: SerdeDir) -> Self {
|
||||
let dir = dir.0;
|
||||
if dir.map(f32::is_nan).reduce_or() {
|
||||
warn!("Deserialized dir containing NaNs, replacing with default");
|
||||
Default::default()
|
||||
} else if !dir.is_normalized() {
|
||||
warn!("Deserialized unnormalized dir, replacing with default");
|
||||
Default::default()
|
||||
} else {
|
||||
Self(dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Into<SerdeDir> for Dir {
|
||||
fn into(self) -> SerdeDir { SerdeDir(*self) }
|
||||
}
|
||||
/*pub enum TryFromVec3Error {
|
||||
ContainsNans,
|
||||
NotNormalized,
|
||||
}
|
||||
|
||||
impl TryFrom<Vec3<f32>> for Dir {
|
||||
type Error = TryFromVec3Error;
|
||||
|
||||
fn try_from(v: Vec3) -> Result<Self, TryFromVec3Error> {
|
||||
if v.map(f32::is_nan).reduce_or() {
|
||||
Err(TryFromVec3Error::ContainsNans)
|
||||
} else {
|
||||
v.try_normalized()
|
||||
.map(|n| Self(n))
|
||||
.ok_or(TryFromVec3Error::NotNormalized)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
impl Dir {
|
||||
pub fn new(dir: Vec3<f32>) -> Self {
|
||||
debug_assert!(!dir.map(f32::is_nan).reduce_or());
|
||||
debug_assert!(dir.is_normalized());
|
||||
Self(dir)
|
||||
}
|
||||
|
||||
pub fn from_unnormalized(dirs: Vec3<f32>) -> Option<Self> {
|
||||
dirs.try_normalized().map(|dir| {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if dir.map(f32::is_nan).reduce_or() {
|
||||
panic!("{} => {}", dirs, dir);
|
||||
}
|
||||
}
|
||||
Self(dir)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn slerp(from: Self, to: Self, factor: f32) -> Self {
|
||||
Self(slerp_normalized(from.0, to.0, factor))
|
||||
}
|
||||
|
||||
/// Note: this uses `from` if `to` is unormalizable
|
||||
pub fn slerp_to_vec3(from: Self, to: Vec3<f32>, factor: f32) -> Self {
|
||||
Self(slerp_to_unnormalized(from.0, to, factor).unwrap_or_else(|e| e))
|
||||
}
|
||||
|
||||
pub fn is_valid(&self) -> bool { !self.0.map(f32::is_nan).reduce_or() && self.is_normalized() }
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Dir {
|
||||
type Target = Vec3<f32>;
|
||||
|
||||
fn deref(&self) -> &Vec3<f32> { &self.0 }
|
||||
}
|
||||
|
||||
impl From<Vec3<f32>> for Dir {
|
||||
fn from(dir: Vec3<f32>) -> Self { Dir::new(dir.into()) }
|
||||
}
|
||||
/// Begone ye NaN's
|
||||
/// Slerp two `Vec3`s skipping the slerp if their directions are very close
|
||||
/// This avoids a case where `vek`s slerp produces NaN's
|
||||
/// Additionally, it avoids unnecessary calculations if they are near identical
|
||||
/// Assumes `from` and `to` are normalized and returns a normalized vector
|
||||
#[inline(always)]
|
||||
fn slerp_normalized(from: vek::Vec3<f32>, to: vek::Vec3<f32>, factor: f32) -> vek::Vec3<f32> {
|
||||
debug_assert!(!to.map(f32::is_nan).reduce_or());
|
||||
debug_assert!(!from.map(f32::is_nan).reduce_or());
|
||||
// Ensure from is normalized
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if {
|
||||
let len_sq = from.magnitude_squared();
|
||||
len_sq < 0.999 || len_sq > 1.001
|
||||
} {
|
||||
panic!("Called slerp_normalized with unnormalized from: {:?}", from);
|
||||
}
|
||||
}
|
||||
// Ensure to is normalized
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if {
|
||||
let len_sq = from.magnitude_squared();
|
||||
len_sq < 0.999 || len_sq > 1.001
|
||||
} {
|
||||
panic!("Called slerp_normalized with unnormalized to: {:?}", to);
|
||||
}
|
||||
}
|
||||
|
||||
let dot = from.dot(to);
|
||||
if dot >= 1.0 - 1E-6 {
|
||||
// Close together, just use to
|
||||
return to;
|
||||
}
|
||||
|
||||
let (from, to, factor) = if dot < -0.999 {
|
||||
// Not linearly independent (slerp will fail since it doesn't check for this)
|
||||
// Instead we will choose a midpoint and slerp from or to that depending on the
|
||||
// factor
|
||||
let mid_dir = if from.z.abs() > 0.999 {
|
||||
// If vec's lie along the z-axis default to (1, 0, 0) as midpoint
|
||||
Vec3::unit_x()
|
||||
} else {
|
||||
// Default to picking midpoint in the xy plane
|
||||
Vec3::new(from.y, -from.x, 0.0).normalized()
|
||||
};
|
||||
|
||||
if factor > 0.5 {
|
||||
(mid_dir, to, factor * 2.0 - 1.0)
|
||||
} else {
|
||||
(from, mid_dir, factor * 2.0)
|
||||
}
|
||||
} else {
|
||||
(from, to, factor)
|
||||
};
|
||||
|
||||
let slerped = Vec3::slerp(from, to, factor);
|
||||
let slerped_normalized = slerped.normalized();
|
||||
// Ensure normalization worked
|
||||
// This should not be possible but I will leave it here for now just in case
|
||||
// something was missed
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if !slerped_normalized.is_normalized() || slerped_normalized.map(f32::is_nan).reduce_or() {
|
||||
panic!(
|
||||
"Failed to normalize {:?} produced from:\nslerp(\n {:?},\n {:?},\n \
|
||||
{:?},\n)\nWith result: {:?})",
|
||||
slerped, from, to, factor, slerped_normalized
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
slerped_normalized
|
||||
}
|
||||
|
||||
/// Begone ye NaN's
|
||||
/// Slerp two `Vec3`s skipping the slerp if their directions are very close
|
||||
/// This avoids a case where `vek`s slerp produces NaN's
|
||||
/// Additionally, it avoids unnecessary calculations if they are near identical
|
||||
/// Assumes `from` is normalized and returns a normalized vector, but `to`
|
||||
/// doesn't need to be normalized
|
||||
/// Returns `Err(from)`` if `to` is unormalizable
|
||||
// TODO: in some cases we might want to base the slerp rate on the magnitude of
|
||||
// `to` for example when `to` is velocity and `from` is orientation
|
||||
fn slerp_to_unnormalized(
|
||||
from: Vec3<f32>,
|
||||
to: Vec3<f32>,
|
||||
factor: f32,
|
||||
) -> Result<Vec3<f32>, Vec3<f32>> {
|
||||
to.try_normalized()
|
||||
.map(|to| slerp_normalized(from, to, factor))
|
||||
.ok_or(from)
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
mod color;
|
||||
mod dir;
|
||||
|
||||
pub const GIT_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/githash"));
|
||||
|
||||
@ -8,84 +9,4 @@ lazy_static::lazy_static! {
|
||||
}
|
||||
|
||||
pub use color::*;
|
||||
|
||||
/// Begone ye NaN's
|
||||
/// Slerp two `Vec3`s skipping the slerp if their directions are very close
|
||||
/// This avoids a case where `vek`s slerp produces NaN's
|
||||
/// Additionally, it avoids unnecessary calculations if they are near identical
|
||||
/// Assumes `from` is normalized and returns a normalized vector, but `to`
|
||||
/// doesn't need to be normalized
|
||||
// TODO: in some cases we might want to base the slerp rate on the magnitude of
|
||||
// `to` for example when `to` is velocity and `from` is orientation
|
||||
#[inline(always)]
|
||||
pub fn safe_slerp(from: vek::Vec3<f32>, to: vek::Vec3<f32>, factor: f32) -> vek::Vec3<f32> {
|
||||
use vek::Vec3;
|
||||
|
||||
debug_assert!(!to.map(f32::is_nan).reduce_or());
|
||||
debug_assert!(!from.map(f32::is_nan).reduce_or());
|
||||
// Ensure from is normalized
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if {
|
||||
let len_sq = from.magnitude_squared();
|
||||
len_sq < 0.999 || len_sq > 1.001
|
||||
} {
|
||||
panic!("Called safe_slerp with unnormalized from: {:?}", from);
|
||||
}
|
||||
}
|
||||
|
||||
let to = if to.magnitude_squared() > 0.001 {
|
||||
to.normalized()
|
||||
} else {
|
||||
return from;
|
||||
};
|
||||
|
||||
let dot = from.dot(to);
|
||||
if dot >= 1.0 - 1E-6 {
|
||||
// Close together, just use to
|
||||
return to;
|
||||
}
|
||||
|
||||
let (from, to, factor) = if dot < -0.999 {
|
||||
// Not linearly independent (slerp will fail since it doesn't check for this)
|
||||
// Instead we will choose a midpoint and slerp from or to that depending on the
|
||||
// factor
|
||||
let mid_dir = if from.z > 0.999 {
|
||||
// If vec's lie along the z-axis default to (1, 0, 0) as midpoint
|
||||
Vec3::unit_x()
|
||||
} else {
|
||||
// Default to picking midpoint in the xy plane
|
||||
Vec3::new(from.y, -from.x, 0.0).normalized()
|
||||
};
|
||||
|
||||
if factor > 0.5 {
|
||||
(mid_dir, to, factor * 2.0 - 1.0)
|
||||
} else {
|
||||
(from, mid_dir, factor * 2.0)
|
||||
}
|
||||
} else {
|
||||
(from, to, factor)
|
||||
};
|
||||
|
||||
let slerped = Vec3::slerp(from, to, factor);
|
||||
let slerped_normalized = slerped.normalized();
|
||||
// Ensure normalization worked
|
||||
// This should not be possible but I will leave it here for now just in case
|
||||
// something was missed
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if {
|
||||
let len_sq = slerped_normalized.magnitude_squared();
|
||||
len_sq < 0.999 || len_sq > 1.001
|
||||
} || slerped_normalized.map(f32::is_nan).reduce_or()
|
||||
{
|
||||
panic!(
|
||||
"Failed to normalize {:?} produced from:\nslerp(\n {:?},\n {:?},\n \
|
||||
{:?},\n)\nWith result: {:?})",
|
||||
slerped, from, to, factor, slerped_normalized
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
slerped_normalized
|
||||
}
|
||||
pub use dir::*;
|
||||
|
@ -12,6 +12,7 @@ use common::{
|
||||
state::TimeOfDay,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
terrain::TerrainChunkSize,
|
||||
util::Dir,
|
||||
vol::RectVolSize,
|
||||
};
|
||||
use rand::Rng;
|
||||
@ -711,15 +712,14 @@ fn handle_object(server: &mut Server, entity: EcsEntity, args: String, _action:
|
||||
.with(comp::Ori(
|
||||
// converts player orientation into a 90° rotation for the object by using the axis
|
||||
// with the highest value
|
||||
ori.0
|
||||
.map(|e| {
|
||||
if e.abs() == ori.0.map(|e| e.abs()).reduce_partial_max() {
|
||||
e
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
})
|
||||
.normalized(),
|
||||
Dir::from_unnormalized(ori.0.map(|e| {
|
||||
if e.abs() == ori.0.map(|e| e.abs()).reduce_partial_max() {
|
||||
e
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}))
|
||||
.unwrap_or_default(),
|
||||
))
|
||||
.build();
|
||||
server.notify_client(
|
||||
|
@ -1,7 +1,10 @@
|
||||
use crate::{sys, Server, StateExt};
|
||||
use common::comp::{
|
||||
self, Agent, Alignment, Body, Gravity, LightEmitter, Loadout, Pos, Projectile, Scale, Stats,
|
||||
Vel, WaypointArea,
|
||||
use common::{
|
||||
comp::{
|
||||
self, Agent, Alignment, Body, Gravity, LightEmitter, Loadout, Pos, Projectile, Scale,
|
||||
Stats, Vel, WaypointArea,
|
||||
},
|
||||
util::Dir,
|
||||
};
|
||||
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||
use vek::{Rgb, Vec3};
|
||||
@ -42,7 +45,7 @@ pub fn handle_create_npc(
|
||||
pub fn handle_shoot(
|
||||
server: &mut Server,
|
||||
entity: EcsEntity,
|
||||
dir: Vec3<f32>,
|
||||
dir: Dir,
|
||||
body: Body,
|
||||
light: Option<LightEmitter>,
|
||||
projectile: Projectile,
|
||||
@ -60,7 +63,7 @@ pub fn handle_shoot(
|
||||
// TODO: Player height
|
||||
pos.z += 1.2;
|
||||
|
||||
let mut builder = state.create_projectile(Pos(pos), Vel(dir * 100.0), body, projectile);
|
||||
let mut builder = state.create_projectile(Pos(pos), Vel(*dir * 100.0), body, projectile);
|
||||
if let Some(light) = light {
|
||||
builder = builder.with(light)
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
.read_storage::<comp::Ori>()
|
||||
.get(entity)
|
||||
.copied()
|
||||
.unwrap_or(comp::Ori(Vec3::unit_y())),
|
||||
.unwrap_or_default(),
|
||||
item,
|
||||
));
|
||||
}
|
||||
@ -269,7 +269,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
|
||||
// Drop items
|
||||
for (pos, ori, item) in dropped_items {
|
||||
let vel = ori.0.normalized() * 5.0
|
||||
let vel = *ori.0 * 5.0
|
||||
+ Vec3::unit_z() * 10.0
|
||||
+ Vec3::<f32>::zero().map(|_| rand::thread_rng().gen::<f32>() - 0.5) * 4.0;
|
||||
|
||||
|
@ -5,6 +5,7 @@ use common::{
|
||||
msg::{ClientState, ServerMsg},
|
||||
state::State,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
util::Dir,
|
||||
};
|
||||
use log::warn;
|
||||
use specs::{Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder, Join, WorldExt};
|
||||
@ -89,7 +90,7 @@ impl StateExt for State {
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori(Vec3::unit_y()))
|
||||
.with(comp::Ori::default())
|
||||
.with(comp::Controller::default())
|
||||
.with(body)
|
||||
.with(stats)
|
||||
@ -106,7 +107,7 @@ impl StateExt for State {
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori(Vec3::unit_y()))
|
||||
.with(comp::Ori::default())
|
||||
.with(comp::Body::Object(object))
|
||||
.with(comp::Mass(100.0))
|
||||
.with(comp::Gravity(1.0))
|
||||
@ -125,7 +126,7 @@ impl StateExt for State {
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(vel)
|
||||
.with(comp::Ori(vel.0.normalized()))
|
||||
.with(comp::Ori(Dir::from_unnormalized(vel.0).unwrap_or_default()))
|
||||
.with(comp::Mass(0.0))
|
||||
.with(body)
|
||||
.with(projectile)
|
||||
@ -151,7 +152,7 @@ impl StateExt for State {
|
||||
self.write_component(entity, comp::Controller::default());
|
||||
self.write_component(entity, comp::Pos(spawn_point));
|
||||
self.write_component(entity, comp::Vel(Vec3::zero()));
|
||||
self.write_component(entity, comp::Ori(Vec3::unit_y()));
|
||||
self.write_component(entity, comp::Ori::default());
|
||||
self.write_component(entity, comp::Gravity(1.0));
|
||||
self.write_component(entity, comp::CharacterState::default());
|
||||
self.write_component(entity, comp::Alignment::Owned(entity));
|
||||
|
@ -70,10 +70,12 @@ impl SfxMgr {
|
||||
.get(player_entity)
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
let player_ori = ecs
|
||||
let player_ori = *ecs
|
||||
.read_storage::<Ori>()
|
||||
.get(player_entity)
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
.copied()
|
||||
.unwrap_or_default()
|
||||
.0;
|
||||
|
||||
audio.set_listener_pos(&player_position, &player_ori);
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use common::util::Dir;
|
||||
use specs::Component;
|
||||
use specs_idvs::IDVStorage;
|
||||
use vek::*;
|
||||
@ -32,7 +33,7 @@ impl Component for HpFloaterList {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Interpolated {
|
||||
pub pos: Vec3<f32>,
|
||||
pub ori: Vec3<f32>,
|
||||
pub ori: Dir,
|
||||
}
|
||||
impl Component for Interpolated {
|
||||
type Storage = IDVStorage<Self>;
|
||||
|
@ -2,7 +2,7 @@ use crate::ecs::comp::Interpolated;
|
||||
use common::{
|
||||
comp::{Ori, Pos, Vel},
|
||||
state::DeltaTime,
|
||||
util::safe_slerp,
|
||||
util::Dir,
|
||||
};
|
||||
use log::warn;
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
@ -30,7 +30,7 @@ impl<'a> System<'a> for Sys {
|
||||
// Update interpolation values
|
||||
if i.pos.distance_squared(pos.0) < 64.0 * 64.0 {
|
||||
i.pos = Lerp::lerp(i.pos, pos.0 + vel.0 * 0.03, 10.0 * dt.0);
|
||||
i.ori = safe_slerp(i.ori, ori.0, 5.0 * dt.0);
|
||||
i.ori = Dir::slerp(i.ori, ori.0, 5.0 * dt.0);
|
||||
} else {
|
||||
i.pos = pos.0;
|
||||
i.ori = ori.0;
|
||||
|
@ -142,8 +142,8 @@ impl FigureMgr {
|
||||
.join()
|
||||
{
|
||||
let (pos, ori) = interpolated
|
||||
.map(|i| (Pos(i.pos), Ori(i.ori)))
|
||||
.unwrap_or((*pos, Ori(Vec3::unit_y())));
|
||||
.map(|i| (Pos(i.pos), *i.ori))
|
||||
.unwrap_or((*pos, Vec3::unit_y()));
|
||||
|
||||
// Don't process figures outside the vd
|
||||
let vd_frac = Vec2::from(pos.0 - player_pos)
|
||||
@ -439,7 +439,7 @@ impl FigureMgr {
|
||||
// Running
|
||||
(true, true, _) => anim::character::RunAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(active_tool_kind, vel.0, ori.0, state.last_ori, time),
|
||||
(active_tool_kind, vel.0, ori, state.last_ori, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
@ -455,7 +455,7 @@ impl FigureMgr {
|
||||
// Swim
|
||||
(false, _, true) => anim::character::SwimAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(active_tool_kind, vel.0, ori.0.magnitude(), time),
|
||||
(active_tool_kind, vel.0, ori.magnitude(), time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
@ -465,7 +465,7 @@ impl FigureMgr {
|
||||
CharacterState::Roll { .. } => {
|
||||
anim::character::RollAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, ori.0, state.last_ori, time),
|
||||
(active_tool_kind, ori, state.last_ori, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
@ -602,7 +602,7 @@ impl FigureMgr {
|
||||
CharacterState::Glide { .. } => {
|
||||
anim::character::GlidingAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, vel.0, ori.0, state.last_ori, time),
|
||||
(active_tool_kind, vel.0, ori, state.last_ori, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
@ -611,7 +611,7 @@ impl FigureMgr {
|
||||
CharacterState::Climb { .. } => {
|
||||
anim::character::ClimbAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(active_tool_kind, vel.0, ori.0, time),
|
||||
(active_tool_kind, vel.0, ori, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
@ -633,7 +633,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -713,7 +713,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -795,7 +795,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -869,7 +869,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -943,7 +943,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -1017,7 +1017,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -1091,7 +1091,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -1165,7 +1165,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -1239,7 +1239,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -1313,7 +1313,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
@ -1332,7 +1332,7 @@ impl FigureMgr {
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
ori,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
|
@ -17,6 +17,7 @@ use common::{
|
||||
comp::{Pos, Vel, MAX_PICKUP_RANGE_SQR},
|
||||
msg::ClientState,
|
||||
terrain::{Block, BlockKind},
|
||||
util::Dir,
|
||||
vol::ReadVol,
|
||||
ChatType,
|
||||
};
|
||||
@ -446,7 +447,7 @@ impl PlayState for SessionState {
|
||||
|
||||
if !free_look {
|
||||
ori = self.scene.camera().get_orientation();
|
||||
self.inputs.look_dir = cam_dir;
|
||||
self.inputs.look_dir = Dir::from_unnormalized(cam_dir).unwrap();
|
||||
}
|
||||
// Calculate the movement input vector of the player from the current key
|
||||
// presses and the camera direction.
|
||||
|
Loading…
Reference in New Issue
Block a user