mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Create Dir type for better enforcement of non NaN, normalized representations of directions
This commit is contained in:
parent
df5a7ef0e3
commit
ba3fa16c33
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -4847,8 +4847,7 @@ checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vek"
|
name = "vek"
|
||||||
version = "0.9.12"
|
version = "0.9.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Imberflur/vek?branch=is_normalized#7442254deb67ad6930bedc671057d14ea8e885eb"
|
||||||
checksum = "b833a133490ae98e9e3db1c77fc28e844f8e51b12eb35b4ab8a2082cb7cb441a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"approx 0.1.1",
|
"approx 0.1.1",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
|
@ -68,3 +68,6 @@ debug = false
|
|||||||
[profile.releasedebuginfo]
|
[profile.releasedebuginfo]
|
||||||
inherits = 'release'
|
inherits = 'release'
|
||||||
debug = 1
|
debug = 1
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
vek = {git = "https://github.com/Imberflur/vek", branch = "is_normalized"}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::sync::Uid;
|
use crate::{sync::Uid, util::Dir};
|
||||||
use specs::{Component, FlaggedStorage};
|
use specs::{Component, FlaggedStorage};
|
||||||
use specs_idvs::IDVStorage;
|
use specs_idvs::IDVStorage;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -146,7 +146,7 @@ pub struct ControllerInputs {
|
|||||||
pub charge: Input,
|
pub charge: Input,
|
||||||
pub climb: Option<Climb>,
|
pub climb: Option<Climb>,
|
||||||
pub move_dir: Vec2<f32>,
|
pub move_dir: Vec2<f32>,
|
||||||
pub look_dir: Vec3<f32>,
|
pub look_dir: Dir,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
#[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::{Component, FlaggedStorage, NullStorage};
|
||||||
use specs_idvs::IDVStorage;
|
use specs_idvs::IDVStorage;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -21,7 +21,7 @@ impl Component for Vel {
|
|||||||
|
|
||||||
// Orientation
|
// Orientation
|
||||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Ori(pub Vec3<f32>);
|
pub struct Ori(pub Dir);
|
||||||
|
|
||||||
impl Component for Ori {
|
impl Component for Ori {
|
||||||
type Storage = IDVStorage<Self>;
|
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 comp::{item::ToolKind, InventoryUpdateEvent};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -87,7 +87,7 @@ pub enum ServerEvent {
|
|||||||
Respawn(EcsEntity),
|
Respawn(EcsEntity),
|
||||||
Shoot {
|
Shoot {
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
dir: Vec3<f32>,
|
dir: Dir,
|
||||||
body: comp::Body,
|
body: comp::Body,
|
||||||
light: Option<comp::LightEmitter>,
|
light: Option<comp::LightEmitter>,
|
||||||
projectile: comp::Projectile,
|
projectile: comp::Projectile,
|
||||||
|
@ -23,7 +23,7 @@ impl CharacterBehavior for Data {
|
|||||||
if self.only_up {
|
if self.only_up {
|
||||||
update.vel.0.z += 500.0 * data.dt.0;
|
update.vel.0.z += 500.0 * data.dt.0;
|
||||||
} else {
|
} 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 {
|
update.character = CharacterState::Boost(Data {
|
||||||
duration: self
|
duration: self
|
||||||
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
character_behavior::{CharacterBehavior, JoinData},
|
character_behavior::{CharacterBehavior, JoinData},
|
||||||
phys::GRAVITY,
|
phys::GRAVITY,
|
||||||
},
|
},
|
||||||
util::safe_slerp,
|
util::Dir,
|
||||||
};
|
};
|
||||||
use vek::{
|
use vek::{
|
||||||
vec::{Vec2, Vec3},
|
vec::{Vec2, Vec3},
|
||||||
@ -23,7 +23,13 @@ impl CharacterBehavior for Data {
|
|||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
|
|
||||||
// If no wall is in front of character or we stopped climbing;
|
// 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() {
|
if data.inputs.jump.is_pressed() {
|
||||||
// They've climbed atop something, give them a boost
|
// They've climbed atop something, give them a boost
|
||||||
update
|
update
|
||||||
@ -32,7 +38,7 @@ impl CharacterBehavior for Data {
|
|||||||
}
|
}
|
||||||
update.character = CharacterState::Idle {};
|
update.character = CharacterState::Idle {};
|
||||||
return update;
|
return update;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Move player
|
// Move player
|
||||||
update.vel.0 += Vec2::broadcast(data.dt.0)
|
update.vel.0 += Vec2::broadcast(data.dt.0)
|
||||||
@ -44,11 +50,9 @@ impl CharacterBehavior for Data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Expend energy if climbing
|
// Expend energy if climbing
|
||||||
let energy_use = match data.inputs.climb {
|
let energy_use = match climb {
|
||||||
Some(Climb::Up) | Some(Climb::Down) => 8,
|
Climb::Up | Climb::Down => 8,
|
||||||
Some(Climb::Hold) => 1,
|
Climb::Hold => 1,
|
||||||
// Note: this is currently unreachable
|
|
||||||
None => 0,
|
|
||||||
};
|
};
|
||||||
if let Err(_) = update
|
if let Err(_) = update
|
||||||
.energy
|
.energy
|
||||||
@ -58,25 +62,17 @@ impl CharacterBehavior for Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set orientation direction based on wall direction
|
// Set orientation direction based on wall direction
|
||||||
let ori_dir = if let Some(wall_dir) = data.physics.on_wall {
|
let ori_dir = Vec2::from(wall_dir);
|
||||||
Vec2::from(wall_dir)
|
|
||||||
} else {
|
|
||||||
Vec2::from(update.vel.0)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Smooth orientation
|
// Smooth orientation
|
||||||
update.ori.0 = safe_slerp(
|
update.ori.0 = Dir::slerp_to_vec3(
|
||||||
update.ori.0,
|
update.ori.0,
|
||||||
ori_dir.into(),
|
ori_dir.into(),
|
||||||
if data.physics.on_ground { 9.0 } else { 2.0 } * data.dt.0,
|
if data.physics.on_ground { 9.0 } else { 2.0 } * data.dt.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Apply Vertical Climbing Movement
|
// Apply Vertical Climbing Movement
|
||||||
if let (Some(climb), true, Some(_wall_dir)) = (
|
if update.vel.0.z <= CLIMB_SPEED {
|
||||||
data.inputs.climb,
|
|
||||||
update.vel.0.z <= CLIMB_SPEED,
|
|
||||||
data.physics.on_wall,
|
|
||||||
) {
|
|
||||||
match climb {
|
match climb {
|
||||||
Climb::Down => {
|
Climb::Down => {
|
||||||
update.vel.0 -=
|
update.vel.0 -=
|
||||||
|
@ -2,7 +2,7 @@ use crate::{
|
|||||||
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
||||||
states::utils::*,
|
states::utils::*,
|
||||||
sys::character_behavior::*,
|
sys::character_behavior::*,
|
||||||
util::safe_slerp,
|
util::Dir,
|
||||||
};
|
};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use vek::Vec3;
|
use vek::Vec3;
|
||||||
@ -27,9 +27,9 @@ impl CharacterBehavior for Data {
|
|||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
|
|
||||||
if self.initialize {
|
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() {
|
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
|
update
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
comp::{CharacterState, StateUpdate},
|
comp::{CharacterState, StateUpdate},
|
||||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||||
util::safe_slerp,
|
util::Dir,
|
||||||
};
|
};
|
||||||
use vek::Vec2;
|
use vek::Vec2;
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ impl CharacterBehavior for Data {
|
|||||||
|
|
||||||
// Determine orientation vector from movement direction vector
|
// Determine orientation vector from movement direction vector
|
||||||
let ori_dir = Vec2::from(update.vel.0);
|
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
|
// Apply Glide antigrav lift
|
||||||
if Vec2::<f32>::from(update.vel.0).magnitude_squared() < GLIDE_SPEED.powf(2.0)
|
if Vec2::<f32>::from(update.vel.0).magnitude_squared() < GLIDE_SPEED.powf(2.0)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
comp::{CharacterState, StateUpdate},
|
comp::{CharacterState, StateUpdate},
|
||||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||||
util::safe_slerp,
|
util::Dir,
|
||||||
};
|
};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use vek::Vec3;
|
use vek::Vec3;
|
||||||
@ -28,7 +28,7 @@ impl CharacterBehavior for Data {
|
|||||||
* ROLL_SPEED;
|
* ROLL_SPEED;
|
||||||
|
|
||||||
// Smooth orientation
|
// 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() {
|
if self.remaining_duration == Duration::default() {
|
||||||
// Roll duration has expired
|
// Roll duration has expired
|
||||||
|
@ -57,7 +57,7 @@ impl CharacterBehavior for Data {
|
|||||||
if !self.initialized {
|
if !self.initialized {
|
||||||
update.vel.0 = Vec3::zero();
|
update.vel.0 = Vec3::zero();
|
||||||
if let Some(dir) = data.inputs.look_dir.try_normalized() {
|
if let Some(dir) = data.inputs.look_dir.try_normalized() {
|
||||||
update.ori.0 = dir;
|
update.ori.0 = dir.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let initialized = true;
|
let initialized = true;
|
||||||
|
@ -3,7 +3,7 @@ use crate::{
|
|||||||
event::LocalEvent,
|
event::LocalEvent,
|
||||||
states::*,
|
states::*,
|
||||||
sys::{character_behavior::JoinData, phys::GRAVITY},
|
sys::{character_behavior::JoinData, phys::GRAVITY},
|
||||||
util::safe_slerp,
|
util::Dir,
|
||||||
};
|
};
|
||||||
use vek::vec::Vec2;
|
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) {
|
pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, strength: f32) {
|
||||||
// Set direction based on move direction
|
// Set direction based on move direction
|
||||||
let ori_dir = if update.character.is_attack() || update.character.is_block() {
|
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 {
|
} else {
|
||||||
Vec2::from(data.inputs.move_dir)
|
Vec2::from(data.inputs.move_dir)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Smooth orientation
|
// 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
|
/// Updates components to move player as if theyre swimming
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use crate::{
|
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,
|
path::Chaser,
|
||||||
state::Time,
|
state::Time,
|
||||||
sync::UidAllocator,
|
sync::UidAllocator,
|
||||||
terrain::TerrainGrid,
|
terrain::TerrainGrid,
|
||||||
|
util::Dir,
|
||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
};
|
};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
@ -21,6 +22,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
Read<'a, Time>,
|
Read<'a, Time>,
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
ReadStorage<'a, Pos>,
|
ReadStorage<'a, Pos>,
|
||||||
|
ReadStorage<'a, Ori>,
|
||||||
ReadStorage<'a, Stats>,
|
ReadStorage<'a, Stats>,
|
||||||
ReadExpect<'a, TerrainGrid>,
|
ReadExpect<'a, TerrainGrid>,
|
||||||
ReadStorage<'a, Alignment>,
|
ReadStorage<'a, Alignment>,
|
||||||
@ -36,6 +38,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
time,
|
time,
|
||||||
entities,
|
entities,
|
||||||
positions,
|
positions,
|
||||||
|
orientations,
|
||||||
stats,
|
stats,
|
||||||
terrain,
|
terrain,
|
||||||
alignments,
|
alignments,
|
||||||
@ -44,9 +47,10 @@ impl<'a> System<'a> for Sys {
|
|||||||
mount_states,
|
mount_states,
|
||||||
): Self::SystemData,
|
): Self::SystemData,
|
||||||
) {
|
) {
|
||||||
for (entity, pos, alignment, agent, controller, mount_state) in (
|
for (entity, pos, ori, alignment, agent, controller, mount_state) in (
|
||||||
&entities,
|
&entities,
|
||||||
&positions,
|
&positions,
|
||||||
|
&orientations,
|
||||||
alignments.maybe(),
|
alignments.maybe(),
|
||||||
&mut agents,
|
&mut agents,
|
||||||
&mut controllers,
|
&mut controllers,
|
||||||
@ -70,9 +74,11 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
controller.reset();
|
controller.reset();
|
||||||
|
|
||||||
//TODO: Make npcs have valid `look_dir` during all activities
|
|
||||||
let mut inputs = &mut controller.inputs;
|
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 AVG_FOLLOW_DIST: f32 = 6.0;
|
||||||
const MAX_FOLLOW_DIST: f32 = 12.0;
|
const MAX_FOLLOW_DIST: f32 = 12.0;
|
||||||
const MAX_CHASE_DIST: f32 = 24.0;
|
const MAX_CHASE_DIST: f32 = 24.0;
|
||||||
@ -162,7 +168,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(Alignment::Owned(*target)),
|
.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
|
// Don't attack entities we are passive towards
|
||||||
// TODO: This is here, it's a bit of a hack
|
// TODO: This is here, it's a bit of a hack
|
||||||
|
@ -4,6 +4,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
event::{EventBus, LocalEvent, ServerEvent},
|
event::{EventBus, LocalEvent, ServerEvent},
|
||||||
sync::Uid,
|
sync::Uid,
|
||||||
|
util::Dir,
|
||||||
};
|
};
|
||||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -92,7 +93,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
// 2D versions
|
// 2D versions
|
||||||
let pos2 = Vec2::from(pos.0);
|
let pos2 = Vec2::from(pos.0);
|
||||||
let pos_b2 = Vec2::<f32>::from(pos_b.0);
|
let pos_b2 = Vec2::<f32>::from(pos_b.0);
|
||||||
let ori2 = Vec2::from(ori.0);
|
let ori2 = Vec2::from(*ori.0);
|
||||||
|
|
||||||
// Scales
|
// Scales
|
||||||
let scale = scale_maybe.map_or(1.0, |s| s.0);
|
let scale = scale_maybe.map_or(1.0, |s| s.0);
|
||||||
@ -140,7 +141,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
if attack.knockback != 0.0 {
|
if attack.knockback != 0.0 {
|
||||||
local_emitter.emit(LocalEvent::ApplyForce {
|
local_emitter.emit(LocalEvent::ApplyForce {
|
||||||
entity: b,
|
entity: b,
|
||||||
dir: Vec3::slerp(ori.0, Vec3::new(0.0, 0.0, 1.0), 0.5),
|
dir: *Dir::slerp(ori.0, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5),
|
||||||
force: attack.knockback,
|
force: attack.knockback,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -63,12 +63,6 @@ impl<'a> System<'a> for Sys {
|
|||||||
inputs.move_dir
|
inputs.move_dir
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update `inputs.look_dir`
|
|
||||||
inputs
|
|
||||||
.look_dir
|
|
||||||
.try_normalized()
|
|
||||||
.unwrap_or(inputs.move_dir.into());
|
|
||||||
|
|
||||||
// Process other controller events
|
// Process other controller events
|
||||||
for event in controller.events.drain(..) {
|
for event in controller.events.drain(..) {
|
||||||
match event {
|
match event {
|
||||||
|
@ -5,6 +5,7 @@ use crate::{
|
|||||||
event::{EventBus, LocalEvent, ServerEvent},
|
event::{EventBus, LocalEvent, ServerEvent},
|
||||||
state::DeltaTime,
|
state::DeltaTime,
|
||||||
sync::UidAllocator,
|
sync::UidAllocator,
|
||||||
|
util::Dir,
|
||||||
};
|
};
|
||||||
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
|
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -107,7 +108,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
{
|
{
|
||||||
local_emitter.emit(LocalEvent::ApplyForce {
|
local_emitter.emit(LocalEvent::ApplyForce {
|
||||||
entity,
|
entity,
|
||||||
dir: Vec3::slerp(ori.0, Vec3::new(0.0, 0.0, 1.0), 0.5),
|
dir: *Dir::slerp(ori.0, Dir::new(Vec3::unit_z()), 0.5),
|
||||||
force: knockback,
|
force: knockback,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -145,7 +146,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
.get(entity)
|
.get(entity)
|
||||||
.and_then(|vel| vel.0.try_normalized())
|
.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 color;
|
||||||
|
mod dir;
|
||||||
|
|
||||||
pub const GIT_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/githash"));
|
pub const GIT_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/githash"));
|
||||||
|
|
||||||
@ -8,84 +9,4 @@ lazy_static::lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
|
pub use dir::*;
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
@ -12,6 +12,7 @@ use common::{
|
|||||||
state::TimeOfDay,
|
state::TimeOfDay,
|
||||||
sync::{Uid, WorldSyncExt},
|
sync::{Uid, WorldSyncExt},
|
||||||
terrain::TerrainChunkSize,
|
terrain::TerrainChunkSize,
|
||||||
|
util::Dir,
|
||||||
vol::RectVolSize,
|
vol::RectVolSize,
|
||||||
};
|
};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
@ -711,15 +712,14 @@ fn handle_object(server: &mut Server, entity: EcsEntity, args: String, _action:
|
|||||||
.with(comp::Ori(
|
.with(comp::Ori(
|
||||||
// converts player orientation into a 90° rotation for the object by using the axis
|
// converts player orientation into a 90° rotation for the object by using the axis
|
||||||
// with the highest value
|
// with the highest value
|
||||||
ori.0
|
Dir::from_unnormalized(ori.0.map(|e| {
|
||||||
.map(|e| {
|
if e.abs() == ori.0.map(|e| e.abs()).reduce_partial_max() {
|
||||||
if e.abs() == ori.0.map(|e| e.abs()).reduce_partial_max() {
|
e
|
||||||
e
|
} else {
|
||||||
} else {
|
0.0
|
||||||
0.0
|
}
|
||||||
}
|
}))
|
||||||
})
|
.unwrap_or_default(),
|
||||||
.normalized(),
|
|
||||||
))
|
))
|
||||||
.build();
|
.build();
|
||||||
server.notify_client(
|
server.notify_client(
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use crate::{sys, Server, StateExt};
|
use crate::{sys, Server, StateExt};
|
||||||
use common::comp::{
|
use common::{
|
||||||
self, Agent, Alignment, Body, Gravity, LightEmitter, Loadout, Pos, Projectile, Scale, Stats,
|
comp::{
|
||||||
Vel, WaypointArea,
|
self, Agent, Alignment, Body, Gravity, LightEmitter, Loadout, Pos, Projectile, Scale,
|
||||||
|
Stats, Vel, WaypointArea,
|
||||||
|
},
|
||||||
|
util::Dir,
|
||||||
};
|
};
|
||||||
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||||
use vek::{Rgb, Vec3};
|
use vek::{Rgb, Vec3};
|
||||||
@ -42,7 +45,7 @@ pub fn handle_create_npc(
|
|||||||
pub fn handle_shoot(
|
pub fn handle_shoot(
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
dir: Vec3<f32>,
|
dir: Dir,
|
||||||
body: Body,
|
body: Body,
|
||||||
light: Option<LightEmitter>,
|
light: Option<LightEmitter>,
|
||||||
projectile: Projectile,
|
projectile: Projectile,
|
||||||
@ -60,7 +63,7 @@ pub fn handle_shoot(
|
|||||||
// TODO: Player height
|
// TODO: Player height
|
||||||
pos.z += 1.2;
|
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 {
|
if let Some(light) = light {
|
||||||
builder = builder.with(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>()
|
.read_storage::<comp::Ori>()
|
||||||
.get(entity)
|
.get(entity)
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(comp::Ori(Vec3::unit_y())),
|
.unwrap_or_default(),
|
||||||
item,
|
item,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -269,7 +269,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
|||||||
|
|
||||||
// Drop items
|
// Drop items
|
||||||
for (pos, ori, item) in dropped_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::unit_z() * 10.0
|
||||||
+ Vec3::<f32>::zero().map(|_| rand::thread_rng().gen::<f32>() - 0.5) * 4.0;
|
+ Vec3::<f32>::zero().map(|_| rand::thread_rng().gen::<f32>() - 0.5) * 4.0;
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ use common::{
|
|||||||
msg::{ClientState, ServerMsg},
|
msg::{ClientState, ServerMsg},
|
||||||
state::State,
|
state::State,
|
||||||
sync::{Uid, WorldSyncExt},
|
sync::{Uid, WorldSyncExt},
|
||||||
|
util::Dir,
|
||||||
};
|
};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use specs::{Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder, Join, WorldExt};
|
use specs::{Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder, Join, WorldExt};
|
||||||
@ -89,7 +90,7 @@ impl StateExt for State {
|
|||||||
.create_entity_synced()
|
.create_entity_synced()
|
||||||
.with(pos)
|
.with(pos)
|
||||||
.with(comp::Vel(Vec3::zero()))
|
.with(comp::Vel(Vec3::zero()))
|
||||||
.with(comp::Ori(Vec3::unit_y()))
|
.with(comp::Ori::default())
|
||||||
.with(comp::Controller::default())
|
.with(comp::Controller::default())
|
||||||
.with(body)
|
.with(body)
|
||||||
.with(stats)
|
.with(stats)
|
||||||
@ -106,7 +107,7 @@ impl StateExt for State {
|
|||||||
.create_entity_synced()
|
.create_entity_synced()
|
||||||
.with(pos)
|
.with(pos)
|
||||||
.with(comp::Vel(Vec3::zero()))
|
.with(comp::Vel(Vec3::zero()))
|
||||||
.with(comp::Ori(Vec3::unit_y()))
|
.with(comp::Ori::default())
|
||||||
.with(comp::Body::Object(object))
|
.with(comp::Body::Object(object))
|
||||||
.with(comp::Mass(100.0))
|
.with(comp::Mass(100.0))
|
||||||
.with(comp::Gravity(1.0))
|
.with(comp::Gravity(1.0))
|
||||||
@ -125,7 +126,7 @@ impl StateExt for State {
|
|||||||
.create_entity_synced()
|
.create_entity_synced()
|
||||||
.with(pos)
|
.with(pos)
|
||||||
.with(vel)
|
.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(comp::Mass(0.0))
|
||||||
.with(body)
|
.with(body)
|
||||||
.with(projectile)
|
.with(projectile)
|
||||||
@ -151,7 +152,7 @@ impl StateExt for State {
|
|||||||
self.write_component(entity, comp::Controller::default());
|
self.write_component(entity, comp::Controller::default());
|
||||||
self.write_component(entity, comp::Pos(spawn_point));
|
self.write_component(entity, comp::Pos(spawn_point));
|
||||||
self.write_component(entity, comp::Vel(Vec3::zero()));
|
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::Gravity(1.0));
|
||||||
self.write_component(entity, comp::CharacterState::default());
|
self.write_component(entity, comp::CharacterState::default());
|
||||||
self.write_component(entity, comp::Alignment::Owned(entity));
|
self.write_component(entity, comp::Alignment::Owned(entity));
|
||||||
|
@ -70,10 +70,12 @@ impl SfxMgr {
|
|||||||
.get(player_entity)
|
.get(player_entity)
|
||||||
.map_or(Vec3::zero(), |pos| pos.0);
|
.map_or(Vec3::zero(), |pos| pos.0);
|
||||||
|
|
||||||
let player_ori = ecs
|
let player_ori = *ecs
|
||||||
.read_storage::<Ori>()
|
.read_storage::<Ori>()
|
||||||
.get(player_entity)
|
.get(player_entity)
|
||||||
.map_or(Vec3::zero(), |pos| pos.0);
|
.copied()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.0;
|
||||||
|
|
||||||
audio.set_listener_pos(&player_position, &player_ori);
|
audio.set_listener_pos(&player_position, &player_ori);
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use common::util::Dir;
|
||||||
use specs::Component;
|
use specs::Component;
|
||||||
use specs_idvs::IDVStorage;
|
use specs_idvs::IDVStorage;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -32,7 +33,7 @@ impl Component for HpFloaterList {
|
|||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Interpolated {
|
pub struct Interpolated {
|
||||||
pub pos: Vec3<f32>,
|
pub pos: Vec3<f32>,
|
||||||
pub ori: Vec3<f32>,
|
pub ori: Dir,
|
||||||
}
|
}
|
||||||
impl Component for Interpolated {
|
impl Component for Interpolated {
|
||||||
type Storage = IDVStorage<Self>;
|
type Storage = IDVStorage<Self>;
|
||||||
|
@ -2,7 +2,7 @@ use crate::ecs::comp::Interpolated;
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{Ori, Pos, Vel},
|
comp::{Ori, Pos, Vel},
|
||||||
state::DeltaTime,
|
state::DeltaTime,
|
||||||
util::safe_slerp,
|
util::Dir,
|
||||||
};
|
};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||||
@ -30,7 +30,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
// Update interpolation values
|
// Update interpolation values
|
||||||
if i.pos.distance_squared(pos.0) < 64.0 * 64.0 {
|
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.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 {
|
} else {
|
||||||
i.pos = pos.0;
|
i.pos = pos.0;
|
||||||
i.ori = ori.0;
|
i.ori = ori.0;
|
||||||
|
@ -142,8 +142,8 @@ impl FigureMgr {
|
|||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
let (pos, ori) = interpolated
|
let (pos, ori) = interpolated
|
||||||
.map(|i| (Pos(i.pos), Ori(i.ori)))
|
.map(|i| (Pos(i.pos), *i.ori))
|
||||||
.unwrap_or((*pos, Ori(Vec3::unit_y())));
|
.unwrap_or((*pos, Vec3::unit_y()));
|
||||||
|
|
||||||
// Don't process figures outside the vd
|
// Don't process figures outside the vd
|
||||||
let vd_frac = Vec2::from(pos.0 - player_pos)
|
let vd_frac = Vec2::from(pos.0 - player_pos)
|
||||||
@ -439,7 +439,7 @@ impl FigureMgr {
|
|||||||
// Running
|
// Running
|
||||||
(true, true, _) => anim::character::RunAnimation::update_skeleton(
|
(true, true, _) => anim::character::RunAnimation::update_skeleton(
|
||||||
&CharacterSkeleton::new(),
|
&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,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -455,7 +455,7 @@ impl FigureMgr {
|
|||||||
// Swim
|
// Swim
|
||||||
(false, _, true) => anim::character::SwimAnimation::update_skeleton(
|
(false, _, true) => anim::character::SwimAnimation::update_skeleton(
|
||||||
&CharacterSkeleton::new(),
|
&CharacterSkeleton::new(),
|
||||||
(active_tool_kind, vel.0, ori.0.magnitude(), time),
|
(active_tool_kind, vel.0, ori.magnitude(), time),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -465,7 +465,7 @@ impl FigureMgr {
|
|||||||
CharacterState::Roll { .. } => {
|
CharacterState::Roll { .. } => {
|
||||||
anim::character::RollAnimation::update_skeleton(
|
anim::character::RollAnimation::update_skeleton(
|
||||||
&target_base,
|
&target_base,
|
||||||
(active_tool_kind, ori.0, state.last_ori, time),
|
(active_tool_kind, ori, state.last_ori, time),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -592,7 +592,7 @@ impl FigureMgr {
|
|||||||
CharacterState::Glide { .. } => {
|
CharacterState::Glide { .. } => {
|
||||||
anim::character::GlidingAnimation::update_skeleton(
|
anim::character::GlidingAnimation::update_skeleton(
|
||||||
&target_base,
|
&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,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -601,7 +601,7 @@ impl FigureMgr {
|
|||||||
CharacterState::Climb { .. } => {
|
CharacterState::Climb { .. } => {
|
||||||
anim::character::ClimbAnimation::update_skeleton(
|
anim::character::ClimbAnimation::update_skeleton(
|
||||||
&CharacterSkeleton::new(),
|
&CharacterSkeleton::new(),
|
||||||
(active_tool_kind, vel.0, ori.0, time),
|
(active_tool_kind, vel.0, ori, time),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -623,7 +623,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -703,7 +703,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -785,7 +785,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -859,7 +859,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -933,7 +933,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -1007,7 +1007,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -1081,7 +1081,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -1155,7 +1155,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -1229,7 +1229,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -1303,7 +1303,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
@ -1322,7 +1322,7 @@ impl FigureMgr {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
pos.0,
|
pos.0,
|
||||||
ori.0,
|
ori,
|
||||||
scale,
|
scale,
|
||||||
col,
|
col,
|
||||||
dt,
|
dt,
|
||||||
|
@ -17,6 +17,7 @@ use common::{
|
|||||||
comp::{Pos, Vel, MAX_PICKUP_RANGE_SQR},
|
comp::{Pos, Vel, MAX_PICKUP_RANGE_SQR},
|
||||||
msg::ClientState,
|
msg::ClientState,
|
||||||
terrain::{Block, BlockKind},
|
terrain::{Block, BlockKind},
|
||||||
|
util::Dir,
|
||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
ChatType,
|
ChatType,
|
||||||
};
|
};
|
||||||
@ -446,7 +447,7 @@ impl PlayState for SessionState {
|
|||||||
|
|
||||||
if !free_look {
|
if !free_look {
|
||||||
ori = self.scene.camera().get_orientation();
|
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
|
// Calculate the movement input vector of the player from the current key
|
||||||
// presses and the camera direction.
|
// presses and the camera direction.
|
||||||
|
Loading…
Reference in New Issue
Block a user