mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'lboklin/quat-ori' into 'master'
Redefine Ori as a quaternion See merge request veloren/veloren!1755
This commit is contained in:
commit
4d19308612
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6058,6 +6058,7 @@ dependencies = [
|
|||||||
name = "veloren-common"
|
name = "veloren-common"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"approx 0.4.0",
|
||||||
"arraygen",
|
"arraygen",
|
||||||
"assets_manager",
|
"assets_manager",
|
||||||
"criterion",
|
"criterion",
|
||||||
|
@ -13,6 +13,7 @@ bin_csv = ["csv", "structopt"]
|
|||||||
default = ["simd"]
|
default = ["simd"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
approx = "0.4.0"
|
||||||
arraygen = "0.1.13"
|
arraygen = "0.1.13"
|
||||||
crossbeam-utils = "0.8.1"
|
crossbeam-utils = "0.8.1"
|
||||||
crossbeam-channel = "0.5"
|
crossbeam-channel = "0.5"
|
||||||
|
@ -18,6 +18,7 @@ pub mod invite;
|
|||||||
mod last;
|
mod last;
|
||||||
mod location;
|
mod location;
|
||||||
mod misc;
|
mod misc;
|
||||||
|
pub mod ori;
|
||||||
mod phys;
|
mod phys;
|
||||||
mod player;
|
mod player;
|
||||||
pub mod poise;
|
pub mod poise;
|
||||||
@ -62,9 +63,9 @@ pub use inventory::{
|
|||||||
pub use last::Last;
|
pub use last::Last;
|
||||||
pub use location::{Waypoint, WaypointArea};
|
pub use location::{Waypoint, WaypointArea};
|
||||||
pub use misc::Object;
|
pub use misc::Object;
|
||||||
|
pub use ori::Ori;
|
||||||
pub use phys::{
|
pub use phys::{
|
||||||
Collider, ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, PreviousVelDtCache, Scale,
|
Collider, ForceUpdate, Gravity, Mass, PhysicsState, Pos, PreviousVelDtCache, Scale, Sticky, Vel,
|
||||||
Sticky, Vel,
|
|
||||||
};
|
};
|
||||||
pub use player::Player;
|
pub use player::Player;
|
||||||
pub use poise::{Poise, PoiseChange, PoiseSource, PoiseState};
|
pub use poise::{Poise, PoiseChange, PoiseSource, PoiseState};
|
||||||
|
332
common/src/comp/ori.rs
Normal file
332
common/src/comp/ori.rs
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
use crate::util::{Dir, Plane, Projection};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use specs::Component;
|
||||||
|
use specs_idvs::IdvStorage;
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
use vek::{Quaternion, Vec2, Vec3};
|
||||||
|
|
||||||
|
// Orientation
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(into = "SerdeOri")]
|
||||||
|
#[serde(from = "SerdeOri")]
|
||||||
|
pub struct Ori(Quaternion<f32>);
|
||||||
|
|
||||||
|
impl Default for Ori {
|
||||||
|
/// Returns the default orientation (no rotation; default Dir)
|
||||||
|
fn default() -> Self { Self(Quaternion::identity()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ori {
|
||||||
|
pub fn new(quat: Quaternion<f32>) -> Self {
|
||||||
|
#[cfg(debug_assert)]
|
||||||
|
{
|
||||||
|
let v4 = quat.into_vec4();
|
||||||
|
debug_assert!(v4.map(f32::is_finite).reduce_and());
|
||||||
|
debug_assert!(v4.is_normalized());
|
||||||
|
}
|
||||||
|
Self(quat)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to convert into a Dir and then the appropriate rotation
|
||||||
|
pub fn from_unnormalized_vec<T>(vec: T) -> Option<Self>
|
||||||
|
where
|
||||||
|
T: Into<Vec3<f32>>,
|
||||||
|
{
|
||||||
|
Dir::from_unnormalized(vec.into()).map(Self::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Look direction as a vector (no pedantic normalization performed)
|
||||||
|
pub fn look_vec(self) -> Vec3<f32> { self.to_quat() * *Dir::default() }
|
||||||
|
|
||||||
|
/// Get the internal quaternion representing the rotation from
|
||||||
|
/// `Dir::default()` to this orientation.
|
||||||
|
///
|
||||||
|
/// The operation is a cheap copy.
|
||||||
|
pub fn to_quat(self) -> Quaternion<f32> {
|
||||||
|
debug_assert!(self.is_normalized());
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Look direction (as a Dir it is pedantically normalized)
|
||||||
|
pub fn look_dir(&self) -> Dir { self.to_quat() * Dir::default() }
|
||||||
|
|
||||||
|
pub fn up(&self) -> Dir { self.pitched_up(PI / 2.0).look_dir() }
|
||||||
|
|
||||||
|
pub fn down(&self) -> Dir { self.pitched_down(PI / 2.0).look_dir() }
|
||||||
|
|
||||||
|
pub fn left(&self) -> Dir { self.yawed_left(PI / 2.0).look_dir() }
|
||||||
|
|
||||||
|
pub fn right(&self) -> Dir { self.yawed_right(PI / 2.0).look_dir() }
|
||||||
|
|
||||||
|
pub fn slerp(ori1: Self, ori2: Self, s: f32) -> Self {
|
||||||
|
Self(Quaternion::slerp(ori1.0, ori2.0, s).normalized())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn slerped_towards(self, ori: Ori, s: f32) -> Self { Self::slerp(self, ori, s) }
|
||||||
|
|
||||||
|
/// Multiply rotation quaternion by `q`
|
||||||
|
/// (the rotations are in local vector space).
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use vek::{Quaternion, Vec3};
|
||||||
|
/// use veloren_common::{comp::Ori, util::Dir};
|
||||||
|
///
|
||||||
|
/// let ang = 90_f32.to_radians();
|
||||||
|
/// let roll_right = Quaternion::rotation_y(ang);
|
||||||
|
/// let pitch_up = Quaternion::rotation_x(ang);
|
||||||
|
///
|
||||||
|
/// let ori1 = Ori::from(Dir::new(Vec3::unit_x()));
|
||||||
|
/// let ori2 = Ori::default().rotated(roll_right).rotated(pitch_up);
|
||||||
|
///
|
||||||
|
/// assert!((ori1.look_dir().dot(*ori2.look_dir()) - 1.0).abs() <= std::f32::EPSILON);
|
||||||
|
/// ```
|
||||||
|
pub fn rotated(self, q: Quaternion<f32>) -> Self {
|
||||||
|
Self((self.to_quat() * q.normalized()).normalized())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Premultiply rotation quaternion by `q`
|
||||||
|
/// (the rotations are in global vector space).
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use vek::{Quaternion, Vec3};
|
||||||
|
/// use veloren_common::{comp::Ori, util::Dir};
|
||||||
|
///
|
||||||
|
/// let ang = 90_f32.to_radians();
|
||||||
|
/// let roll_right = Quaternion::rotation_y(ang);
|
||||||
|
/// let pitch_up = Quaternion::rotation_x(ang);
|
||||||
|
///
|
||||||
|
/// let ori1 = Ori::from(Dir::up());
|
||||||
|
/// let ori2 = Ori::default().prerotated(roll_right).prerotated(pitch_up);
|
||||||
|
///
|
||||||
|
/// assert!((ori1.look_dir().dot(*ori2.look_dir()) - 1.0).abs() <= std::f32::EPSILON);
|
||||||
|
/// ```
|
||||||
|
pub fn prerotated(self, q: Quaternion<f32>) -> Self {
|
||||||
|
Self((q.normalized() * self.to_quat()).normalized())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take `global` into this Ori's local vector space
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use vek::Vec3;
|
||||||
|
/// use veloren_common::{comp::Ori, util::Dir};
|
||||||
|
///
|
||||||
|
/// let ang = 90_f32.to_radians();
|
||||||
|
/// let (fw, left, up) = (Dir::default(), Dir::left(), Dir::up());
|
||||||
|
///
|
||||||
|
/// let ori = Ori::default().rolled_left(ang).pitched_up(ang);
|
||||||
|
/// approx::assert_relative_eq!(ori.global_to_local(fw).dot(*-up), 1.0);
|
||||||
|
/// approx::assert_relative_eq!(ori.global_to_local(left).dot(*fw), 1.0);
|
||||||
|
/// let ori = Ori::default().rolled_right(ang).pitched_up(2.0 * ang);
|
||||||
|
/// approx::assert_relative_eq!(ori.global_to_local(up).dot(*left), 1.0);
|
||||||
|
/// ```
|
||||||
|
pub fn global_to_local<T>(&self, global: T) -> <Quaternion<f32> as std::ops::Mul<T>>::Output
|
||||||
|
where
|
||||||
|
Quaternion<f32>: std::ops::Mul<T>,
|
||||||
|
{
|
||||||
|
self.to_quat().inverse() * global
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take `local` into the global vector space
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use vek::Vec3;
|
||||||
|
/// use veloren_common::{comp::Ori, util::Dir};
|
||||||
|
///
|
||||||
|
/// let ang = 90_f32.to_radians();
|
||||||
|
/// let (fw, left, up) = (Dir::default(), Dir::left(), Dir::up());
|
||||||
|
///
|
||||||
|
/// let ori = Ori::default().rolled_left(ang).pitched_up(ang);
|
||||||
|
/// approx::assert_relative_eq!(ori.local_to_global(fw).dot(*left), 1.0);
|
||||||
|
/// approx::assert_relative_eq!(ori.local_to_global(left).dot(*-up), 1.0);
|
||||||
|
/// let ori = Ori::default().rolled_right(ang).pitched_up(2.0 * ang);
|
||||||
|
/// approx::assert_relative_eq!(ori.local_to_global(up).dot(*left), 1.0);
|
||||||
|
/// ```
|
||||||
|
pub fn local_to_global<T>(&self, local: T) -> <Quaternion<f32> as std::ops::Mul<T>>::Output
|
||||||
|
where
|
||||||
|
Quaternion<f32>: std::ops::Mul<T>,
|
||||||
|
{
|
||||||
|
self.to_quat() * local
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pitched_up(self, angle_radians: f32) -> Self {
|
||||||
|
self.rotated(Quaternion::rotation_x(angle_radians))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pitched_down(self, angle_radians: f32) -> Self {
|
||||||
|
self.rotated(Quaternion::rotation_x(-angle_radians))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn yawed_left(self, angle_radians: f32) -> Self {
|
||||||
|
self.rotated(Quaternion::rotation_z(angle_radians))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn yawed_right(self, angle_radians: f32) -> Self {
|
||||||
|
self.rotated(Quaternion::rotation_z(-angle_radians))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rolled_left(self, angle_radians: f32) -> Self {
|
||||||
|
self.rotated(Quaternion::rotation_y(-angle_radians))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rolled_right(self, angle_radians: f32) -> Self {
|
||||||
|
self.rotated(Quaternion::rotation_y(angle_radians))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a version without sideways tilt (roll)
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use veloren_common::comp::Ori;
|
||||||
|
///
|
||||||
|
/// let ang = 45_f32.to_radians();
|
||||||
|
/// let zenith = vek::Vec3::unit_z();
|
||||||
|
///
|
||||||
|
/// let rl = Ori::default().rolled_left(ang);
|
||||||
|
/// assert!((rl.up().angle_between(zenith) - ang).abs() <= std::f32::EPSILON);
|
||||||
|
/// assert!(rl.uprighted().up().angle_between(zenith) <= std::f32::EPSILON);
|
||||||
|
///
|
||||||
|
/// let pd_rr = Ori::default().pitched_down(ang).rolled_right(ang);
|
||||||
|
/// let pd_upr = pd_rr.uprighted();
|
||||||
|
///
|
||||||
|
/// assert!((pd_upr.up().angle_between(zenith) - ang).abs() <= std::f32::EPSILON);
|
||||||
|
///
|
||||||
|
/// let ang1 = pd_upr.rolled_right(ang).up().angle_between(zenith);
|
||||||
|
/// let ang2 = pd_rr.up().angle_between(zenith);
|
||||||
|
/// assert!((ang1 - ang2).abs() <= std::f32::EPSILON);
|
||||||
|
/// ```
|
||||||
|
pub fn uprighted(self) -> Self {
|
||||||
|
let fw = self.look_dir();
|
||||||
|
match Dir::up().projected(&Plane::from(fw)) {
|
||||||
|
Some(dir_p) => {
|
||||||
|
let up = self.up();
|
||||||
|
let go_right_s = fw.cross(*up).dot(*dir_p).signum();
|
||||||
|
self.rolled_right(up.angle_between(*dir_p) * go_right_s)
|
||||||
|
},
|
||||||
|
None => self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_normalized(&self) -> bool { self.0.into_vec4().is_normalized() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Dir> for Ori {
|
||||||
|
fn from(dir: Dir) -> Self {
|
||||||
|
let from = Dir::default();
|
||||||
|
let q = Quaternion::<f32>::rotation_from_to_3d(*from, *dir).normalized();
|
||||||
|
|
||||||
|
Self(q).uprighted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Quaternion<f32>> for Ori {
|
||||||
|
fn from(quat: Quaternion<f32>) -> Self { Self::new(quat) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<vek::quaternion::repr_simd::Quaternion<f32>> for Ori {
|
||||||
|
fn from(
|
||||||
|
vek::quaternion::repr_simd::Quaternion { x, y, z, w }: vek::quaternion::repr_simd::Quaternion<f32>,
|
||||||
|
) -> Self {
|
||||||
|
Self::from(Quaternion { x, y, z, w })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ori> for Quaternion<f32> {
|
||||||
|
fn from(Ori(q): Ori) -> Self { q }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ori> for vek::quaternion::repr_simd::Quaternion<f32> {
|
||||||
|
fn from(Ori(Quaternion { x, y, z, w }): Ori) -> Self {
|
||||||
|
vek::quaternion::repr_simd::Quaternion { x, y, z, w }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ori> for Dir {
|
||||||
|
fn from(ori: Ori) -> Self { ori.look_dir() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ori> for Vec3<f32> {
|
||||||
|
fn from(ori: Ori) -> Self { ori.look_vec() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ori> for vek::vec::repr_simd::Vec3<f32> {
|
||||||
|
fn from(ori: Ori) -> Self { vek::vec::repr_simd::Vec3::from(ori.look_vec()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ori> for Vec2<f32> {
|
||||||
|
fn from(ori: Ori) -> Self { ori.look_vec().xy() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ori> for vek::vec::repr_simd::Vec2<f32> {
|
||||||
|
fn from(ori: Ori) -> Self { vek::vec::repr_simd::Vec2::from(ori.look_vec().xy()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate at Deserialization
|
||||||
|
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct SerdeOri(Quaternion<f32>);
|
||||||
|
|
||||||
|
impl From<SerdeOri> for Ori {
|
||||||
|
fn from(serde_quat: SerdeOri) -> Self {
|
||||||
|
let quat: Quaternion<f32> = serde_quat.0;
|
||||||
|
if quat.into_vec4().map(f32::is_nan).reduce_or() {
|
||||||
|
tracing::warn!(
|
||||||
|
?quat,
|
||||||
|
"Deserialized rotation quaternion containing NaNs, replacing with default"
|
||||||
|
);
|
||||||
|
Default::default()
|
||||||
|
} else if !Self(quat).is_normalized() {
|
||||||
|
tracing::warn!(
|
||||||
|
?quat,
|
||||||
|
"Deserialized unnormalized rotation quaternion (magnitude: {}), replacing with \
|
||||||
|
default",
|
||||||
|
quat.magnitude()
|
||||||
|
);
|
||||||
|
Default::default()
|
||||||
|
} else {
|
||||||
|
Self::new(quat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<SerdeOri> for Ori {
|
||||||
|
fn into(self) -> SerdeOri { SerdeOri(self.to_quat()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Ori {
|
||||||
|
type Storage = IdvStorage<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_to_dir() {
|
||||||
|
let from_to = |dir: Dir| {
|
||||||
|
let ori = Ori::from(dir);
|
||||||
|
|
||||||
|
approx::assert_relative_eq!(ori.look_dir().dot(*dir), 1.0);
|
||||||
|
approx::assert_relative_eq!((ori.to_quat() * Dir::default()).dot(*dir), 1.0);
|
||||||
|
};
|
||||||
|
|
||||||
|
let angles = 32;
|
||||||
|
for i in 0..angles {
|
||||||
|
let theta = PI * 2. * (i as f32) / (angles as f32);
|
||||||
|
let v = Vec3::unit_y();
|
||||||
|
let q = Quaternion::rotation_x(theta);
|
||||||
|
from_to(Dir::new(q * v));
|
||||||
|
let v = Vec3::unit_z();
|
||||||
|
let q = Quaternion::rotation_y(theta);
|
||||||
|
from_to(Dir::new(q * v));
|
||||||
|
let v = Vec3::unit_x();
|
||||||
|
let q = Quaternion::rotation_z(theta);
|
||||||
|
from_to(Dir::new(q * v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dirs() {
|
||||||
|
let ori = Ori::default();
|
||||||
|
let def = Dir::default();
|
||||||
|
for dir in &[ori.up(), ori.down(), ori.left(), ori.right()] {
|
||||||
|
approx::assert_relative_eq!(dir.dot(*def), 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{uid::Uid, util::Dir};
|
use crate::uid::Uid;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use specs::{Component, DerefFlaggedStorage, NullStorage};
|
use specs::{Component, DerefFlaggedStorage, NullStorage};
|
||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
@ -20,18 +20,6 @@ impl Component for Vel {
|
|||||||
type Storage = IdvStorage<Self>;
|
type Storage = IdvStorage<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orientation
|
|
||||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct Ori(pub Dir);
|
|
||||||
|
|
||||||
impl Ori {
|
|
||||||
pub fn vec(&self) -> &Vec3<f32> { &*self.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Ori {
|
|
||||||
type Storage = IdvStorage<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cache of Velocity (of last tick) * dt (of curent tick)
|
/// Cache of Velocity (of last tick) * dt (of curent tick)
|
||||||
/// It's updated and read in physics sys to speed up entity<->entity collisions
|
/// It's updated and read in physics sys to speed up entity<->entity collisions
|
||||||
/// no need to send it via network
|
/// no need to send it via network
|
||||||
|
@ -183,7 +183,7 @@ impl CharacterBehavior for Data {
|
|||||||
update.server_events.push_front(ServerEvent::BeamSegment {
|
update.server_events.push_front(ServerEvent::BeamSegment {
|
||||||
properties,
|
properties,
|
||||||
pos,
|
pos,
|
||||||
ori: Ori(data.inputs.look_dir),
|
ori: Ori::from(data.inputs.look_dir),
|
||||||
});
|
});
|
||||||
update.character = CharacterState::BasicBeam(Data {
|
update.character = CharacterState::BasicBeam(Data {
|
||||||
timer: self
|
timer: self
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
comp::{CharacterState, Climb, EnergySource, StateUpdate},
|
comp::{CharacterState, Climb, EnergySource, Ori, StateUpdate},
|
||||||
consts::GRAVITY,
|
consts::GRAVITY,
|
||||||
event::LocalEvent,
|
event::LocalEvent,
|
||||||
states::behavior::{CharacterBehavior, JoinData},
|
states::behavior::{CharacterBehavior, JoinData},
|
||||||
@ -64,14 +64,13 @@ impl CharacterBehavior for Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set orientation direction based on wall direction
|
// Set orientation direction based on wall direction
|
||||||
let ori_dir = Vec2::from(wall_dir);
|
if let Some(ori_dir) = Dir::from_unnormalized(Vec2::from(wall_dir).into()) {
|
||||||
|
|
||||||
// Smooth orientation
|
// Smooth orientation
|
||||||
update.ori.0 = Dir::slerp_to_vec3(
|
update.ori = update.ori.slerped_towards(
|
||||||
update.ori.0,
|
Ori::from(ori_dir),
|
||||||
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 update.vel.0.z <= CLIMB_SPEED {
|
if update.vel.0.z <= CLIMB_SPEED {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::utils::handle_climb;
|
use super::utils::handle_climb;
|
||||||
use crate::{
|
use crate::{
|
||||||
comp::{inventory::slot::EquipSlot, CharacterState, StateUpdate},
|
comp::{inventory::slot::EquipSlot, CharacterState, Ori, StateUpdate},
|
||||||
states::behavior::{CharacterBehavior, JoinData},
|
states::behavior::{CharacterBehavior, JoinData},
|
||||||
util::Dir,
|
util::Dir,
|
||||||
};
|
};
|
||||||
@ -49,8 +49,10 @@ impl CharacterBehavior for Data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Determine orientation vector from movement direction vector
|
// Determine orientation vector from movement direction vector
|
||||||
let horiz_vel = Vec2::from(update.vel.0);
|
let horiz_vel = Vec2::<f32>::from(update.vel.0);
|
||||||
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, horiz_vel.into(), 2.0 * data.dt.0);
|
if let Some(dir) = Dir::from_unnormalized(update.vel.0) {
|
||||||
|
update.ori = update.ori.slerped_towards(Ori::from(dir), 2.0 * data.dt.0);
|
||||||
|
};
|
||||||
|
|
||||||
// Apply Glide antigrav lift
|
// Apply Glide antigrav lift
|
||||||
let horiz_speed_sq = horiz_vel.magnitude_squared();
|
let horiz_speed_sq = horiz_vel.magnitude_squared();
|
||||||
|
@ -188,7 +188,7 @@ pub fn handle_forced_movement(
|
|||||||
|
|
||||||
update.vel.0 += Vec2::broadcast(data.dt.0)
|
update.vel.0 += Vec2::broadcast(data.dt.0)
|
||||||
* accel
|
* accel
|
||||||
* (data.inputs.move_dir * efficiency + (*update.ori.0).xy() * strength);
|
* (data.inputs.move_dir * efficiency + Vec2::from(update.ori) * strength);
|
||||||
},
|
},
|
||||||
ForcedMovement::Leap {
|
ForcedMovement::Leap {
|
||||||
vertical,
|
vertical,
|
||||||
@ -231,11 +231,11 @@ pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, rate: f32)
|
|||||||
} else if !data.inputs.move_dir.is_approx_zero() {
|
} else if !data.inputs.move_dir.is_approx_zero() {
|
||||||
data.inputs.move_dir
|
data.inputs.move_dir
|
||||||
} else {
|
} else {
|
||||||
update.ori.0.xy()
|
update.ori.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Smooth orientation
|
// Smooth orientation
|
||||||
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, ori_dir.into(), rate * data.dt.0);
|
update.ori = Dir::slerp_to_vec3(update.ori.look_dir(), ori_dir.into(), rate * data.dt.0).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates components to move player as if theyre swimming
|
/// Updates components to move player as if theyre swimming
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use super::{Plane, Projection};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -10,7 +11,7 @@ use vek::*;
|
|||||||
#[serde(from = "SerdeDir")]
|
#[serde(from = "SerdeDir")]
|
||||||
pub struct Dir(Vec3<f32>);
|
pub struct Dir(Vec3<f32>);
|
||||||
impl Default for Dir {
|
impl Default for Dir {
|
||||||
fn default() -> Self { Self(Vec3::unit_y()) }
|
fn default() -> Self { Self::forward() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate at Deserialization
|
// Validate at Deserialization
|
||||||
@ -81,12 +82,38 @@ impl Dir {
|
|||||||
Self(slerp_normalized(from.0, to.0, factor))
|
Self(slerp_normalized(from.0, to.0, factor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn slerped_to(self, to: Self, factor: f32) -> Self {
|
||||||
|
Self(slerp_normalized(self.0, to.0, factor))
|
||||||
|
}
|
||||||
|
|
||||||
/// Note: this uses `from` if `to` is unnormalizable
|
/// Note: this uses `from` if `to` is unnormalizable
|
||||||
pub fn slerp_to_vec3(from: Self, to: Vec3<f32>, factor: f32) -> Self {
|
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))
|
Self(slerp_to_unnormalized(from.0, to, factor).unwrap_or_else(|e| e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rotation_between(&self, to: Self) -> Quaternion<f32> {
|
||||||
|
Quaternion::<f32>::rotation_from_to_3d(self.0, to.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotation(&self) -> Quaternion<f32> { Self::default().rotation_between(*self) }
|
||||||
|
|
||||||
pub fn is_valid(&self) -> bool { !self.0.map(f32::is_nan).reduce_or() && self.is_normalized() }
|
pub fn is_valid(&self) -> bool { !self.0.map(f32::is_nan).reduce_or() && self.is_normalized() }
|
||||||
|
|
||||||
|
pub fn up() -> Self { Dir::new(Vec3::<f32>::unit_z()) }
|
||||||
|
|
||||||
|
pub fn down() -> Self { -Dir::new(Vec3::<f32>::unit_z()) }
|
||||||
|
|
||||||
|
pub fn left() -> Self { -Dir::new(Vec3::<f32>::unit_x()) }
|
||||||
|
|
||||||
|
pub fn right() -> Self { Dir::new(Vec3::<f32>::unit_x()) }
|
||||||
|
|
||||||
|
pub fn forward() -> Self { Dir::new(Vec3::<f32>::unit_y()) }
|
||||||
|
|
||||||
|
pub fn back() -> Self { -Dir::new(Vec3::<f32>::unit_y()) }
|
||||||
|
|
||||||
|
pub fn vec(&self) -> &Vec3<f32> { &self.0 }
|
||||||
|
|
||||||
|
pub fn to_vec(self) -> Vec3<f32> { self.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for Dir {
|
impl std::ops::Deref for Dir {
|
||||||
@ -95,8 +122,31 @@ impl std::ops::Deref for Dir {
|
|||||||
fn deref(&self) -> &Vec3<f32> { &self.0 }
|
fn deref(&self) -> &Vec3<f32> { &self.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec3<f32>> for Dir {
|
impl From<Dir> for Vec3<f32> {
|
||||||
fn from(dir: Vec3<f32>) -> Self { Dir::new(dir) }
|
fn from(dir: Dir) -> Self { *dir }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Projection<Plane> for Dir {
|
||||||
|
type Output = Option<Self>;
|
||||||
|
|
||||||
|
fn projected(self, plane: &Plane) -> Self::Output {
|
||||||
|
Dir::from_unnormalized(plane.projection(*self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Projection<Dir> for Vec3<f32> {
|
||||||
|
type Output = Vec3<f32>;
|
||||||
|
|
||||||
|
fn projected(self, dir: &Dir) -> Self::Output {
|
||||||
|
let dir = **dir;
|
||||||
|
self.dot(dir) * dir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul<Dir> for Quaternion<f32> {
|
||||||
|
type Output = Dir;
|
||||||
|
|
||||||
|
fn mul(self, dir: Dir) -> Self::Output { Dir((self * *dir).normalized()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Neg for Dir {
|
impl std::ops::Neg for Dir {
|
||||||
|
@ -2,6 +2,8 @@ mod color;
|
|||||||
pub mod dir;
|
pub mod dir;
|
||||||
pub mod find_dist;
|
pub mod find_dist;
|
||||||
mod option;
|
mod option;
|
||||||
|
pub mod plane;
|
||||||
|
pub mod projection;
|
||||||
pub mod userdata_dir;
|
pub mod userdata_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"));
|
||||||
@ -28,6 +30,8 @@ lazy_static::lazy_static! {
|
|||||||
pub use color::*;
|
pub use color::*;
|
||||||
pub use dir::*;
|
pub use dir::*;
|
||||||
pub use option::*;
|
pub use option::*;
|
||||||
|
pub use plane::*;
|
||||||
|
pub use projection::*;
|
||||||
|
|
||||||
#[cfg(feature = "tracy")] pub use tracy_client;
|
#[cfg(feature = "tracy")] pub use tracy_client;
|
||||||
|
|
||||||
|
53
common/src/util/plane.rs
Normal file
53
common/src/util/plane.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
use super::{Dir, Projection};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
/// Plane
|
||||||
|
|
||||||
|
// plane defined by its normal and origin
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Plane {
|
||||||
|
pub normal: Dir,
|
||||||
|
/// Distance from origin in the direction of normal
|
||||||
|
pub d: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plane {
|
||||||
|
pub fn new(dir: Dir) -> Self { Self::from(dir) }
|
||||||
|
|
||||||
|
pub fn distance(&self, to: Vec3<f32>) -> f32 { self.normal.dot(to) - self.d }
|
||||||
|
|
||||||
|
// fn center(&self) -> Vec3<f32> { *self.normal * self.d }
|
||||||
|
|
||||||
|
pub fn projection(&self, v: Vec3<f32>) -> Vec3<f32> { v - *self.normal * self.distance(v) }
|
||||||
|
|
||||||
|
pub fn xy() -> Self { Plane::from(Dir::new(Vec3::unit_z())) }
|
||||||
|
|
||||||
|
pub fn yz() -> Self { Plane::from(Dir::new(Vec3::unit_x())) }
|
||||||
|
|
||||||
|
pub fn zx() -> Self { Plane::from(Dir::new(Vec3::unit_y())) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Dir> for Plane {
|
||||||
|
fn from(dir: Dir) -> Self {
|
||||||
|
Plane {
|
||||||
|
normal: dir,
|
||||||
|
d: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Projection<Plane> for Vec3<f32> {
|
||||||
|
type Output = Vec3<f32>;
|
||||||
|
|
||||||
|
fn projected(self, plane: &Plane) -> Self::Output { plane.projection(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Projection<Plane> for Extent2<T>
|
||||||
|
where
|
||||||
|
T: Projection<Plane, Output = T>,
|
||||||
|
{
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn projected(self, plane: &Plane) -> Self::Output { self.map(|v| v.projected(plane)) }
|
||||||
|
}
|
28
common/src/util/projection.rs
Normal file
28
common/src/util/projection.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
use vek::{Vec2, Vec3};
|
||||||
|
|
||||||
|
/// Projection trait for projection of linear types and shapes
|
||||||
|
pub trait Projection<T> {
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
fn projected(self, onto: &T) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Impls
|
||||||
|
|
||||||
|
impl Projection<Vec2<f32>> for Vec2<f32> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn projected(self, v: &Self) -> Self::Output {
|
||||||
|
let v = *v;
|
||||||
|
self.dot(v) * v / v.magnitude_squared()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Projection<Vec3<f32>> for Vec3<f32> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn projected(self, v: &Self) -> Self::Output {
|
||||||
|
let v = *v;
|
||||||
|
v * self.dot(v) / v.magnitude_squared()
|
||||||
|
}
|
||||||
|
}
|
@ -149,8 +149,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
let hit = entity != b
|
let hit = entity != b
|
||||||
&& !health_b.is_dead
|
&& !health_b.is_dead
|
||||||
// Collision shapes
|
// Collision shapes
|
||||||
&& (sphere_wedge_cylinder_collision(pos.0, frame_start_dist, frame_end_dist, *ori.0, beam_segment.angle, pos_b.0, rad_b, height_b)
|
&& (sphere_wedge_cylinder_collision(pos.0, frame_start_dist, frame_end_dist, *ori.look_dir(), beam_segment.angle, pos_b.0, rad_b, height_b)
|
||||||
|| last_pos_b_maybe.map_or(false, |pos_maybe| {sphere_wedge_cylinder_collision(pos.0, frame_start_dist, frame_end_dist, *ori.0, beam_segment.angle, (pos_maybe.0).0, rad_b, height_b)}));
|
|| last_pos_b_maybe.map_or(false, |pos_maybe| {sphere_wedge_cylinder_collision(pos.0, frame_start_dist, frame_end_dist, *ori.look_dir(), beam_segment.angle, (pos_maybe.0).0, rad_b, height_b)}));
|
||||||
|
|
||||||
if hit {
|
if hit {
|
||||||
// See if entities are in the same group
|
// See if entities are in the same group
|
||||||
@ -183,7 +183,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
attacker_info,
|
attacker_info,
|
||||||
b,
|
b,
|
||||||
inventory_b_maybe,
|
inventory_b_maybe,
|
||||||
ori.0,
|
ori.look_dir(),
|
||||||
false,
|
false,
|
||||||
1.0,
|
1.0,
|
||||||
|e| server_emitter.emit(e),
|
|e| server_emitter.emit(e),
|
||||||
|
@ -95,10 +95,12 @@ impl<'a> System<'a> for Sys {
|
|||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
|
let look_dir = *ori.look_dir();
|
||||||
|
|
||||||
// 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(look_dir);
|
||||||
|
|
||||||
// Scales
|
// Scales
|
||||||
let scale = scale_maybe.map_or(1.0, |s| s.0);
|
let scale = scale_maybe.map_or(1.0, |s| s.0);
|
||||||
@ -128,7 +130,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
GroupTarget::OutOfGroup
|
GroupTarget::OutOfGroup
|
||||||
};
|
};
|
||||||
|
|
||||||
let dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
|
let dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(look_dir));
|
||||||
|
|
||||||
let attacker_info = Some(AttackerInfo {
|
let attacker_info = Some(AttackerInfo {
|
||||||
entity,
|
entity,
|
||||||
|
@ -8,6 +8,7 @@ use common::{
|
|||||||
resources::DeltaTime,
|
resources::DeltaTime,
|
||||||
span,
|
span,
|
||||||
uid::UidAllocator,
|
uid::UidAllocator,
|
||||||
|
util::Dir,
|
||||||
GroupTarget,
|
GroupTarget,
|
||||||
};
|
};
|
||||||
use specs::{
|
use specs::{
|
||||||
@ -125,7 +126,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
attacker_info,
|
attacker_info,
|
||||||
target_entity,
|
target_entity,
|
||||||
inventories.get(target_entity),
|
inventories.get(target_entity),
|
||||||
ori.0,
|
ori.look_dir(),
|
||||||
false,
|
false,
|
||||||
1.0,
|
1.0,
|
||||||
|e| server_emitter.emit(e),
|
|e| server_emitter.emit(e),
|
||||||
@ -192,9 +193,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
}
|
}
|
||||||
} else if let Some(dir) = velocities
|
} else if let Some(dir) = velocities
|
||||||
.get(entity)
|
.get(entity)
|
||||||
.and_then(|vel| vel.0.try_normalized())
|
.and_then(|vel| Dir::from_unnormalized(vel.0))
|
||||||
{
|
{
|
||||||
ori.0 = dir.into();
|
*ori = dir.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectile.time_left == Duration::default() {
|
if projectile.time_left == Duration::default() {
|
||||||
|
@ -104,13 +104,14 @@ impl<'a> System<'a> for Sys {
|
|||||||
let frame_start_dist = (shockwave.speed * (time_since_creation - dt)).max(0.0);
|
let frame_start_dist = (shockwave.speed * (time_since_creation - dt)).max(0.0);
|
||||||
let frame_end_dist = (shockwave.speed * time_since_creation).max(frame_start_dist);
|
let frame_end_dist = (shockwave.speed * time_since_creation).max(frame_start_dist);
|
||||||
let pos2 = Vec2::from(pos.0);
|
let pos2 = Vec2::from(pos.0);
|
||||||
|
let look_dir = ori.look_dir();
|
||||||
|
|
||||||
// From one frame to the next a shockwave travels over a strip of an arc
|
// From one frame to the next a shockwave travels over a strip of an arc
|
||||||
// This is used for collision detection
|
// This is used for collision detection
|
||||||
let arc_strip = ArcStrip {
|
let arc_strip = ArcStrip {
|
||||||
origin: pos2,
|
origin: pos2,
|
||||||
// TODO: make sure this is not Vec2::new(0.0, 0.0)
|
// TODO: make sure this is not Vec2::new(0.0, 0.0)
|
||||||
dir: ori.0.xy(),
|
dir: look_dir.xy(),
|
||||||
angle: shockwave.angle,
|
angle: shockwave.angle,
|
||||||
start: frame_start_dist,
|
start: frame_start_dist,
|
||||||
end: frame_end_dist,
|
end: frame_end_dist,
|
||||||
@ -194,7 +195,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
&& (!shockwave.requires_ground || physics_state_b.on_ground);
|
&& (!shockwave.requires_ground || physics_state_b.on_ground);
|
||||||
|
|
||||||
if hit {
|
if hit {
|
||||||
let dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
|
let dir = Dir::from_unnormalized(pos_b.0 - pos.0).unwrap_or(look_dir);
|
||||||
|
|
||||||
let attacker_info =
|
let attacker_info =
|
||||||
shockwave_owner
|
shockwave_owner
|
||||||
|
@ -6,7 +6,7 @@ let
|
|||||||
|
|
||||||
channel = mozPkgs.rustChannelOf {
|
channel = mozPkgs.rustChannelOf {
|
||||||
rustToolchain = ../rust-toolchain;
|
rustToolchain = ../rust-toolchain;
|
||||||
sha256 = "sha256-kDtMqYvrTbahqYHYFQOWyvT0+F5o4UVcqkMZt0c43kc=";
|
sha256 = "sha256-9wp6afVeZqCOEgXxYQiryYeF07kW5IHh3fQaOKF2oRI=";
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
channel // {
|
channel // {
|
||||||
|
@ -22,7 +22,6 @@ use common::{
|
|||||||
resources::TimeOfDay,
|
resources::TimeOfDay,
|
||||||
terrain::{Block, BlockKind, SpriteKind, TerrainChunkSize},
|
terrain::{Block, BlockKind, SpriteKind, TerrainChunkSize},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
util::Dir,
|
|
||||||
vol::RectVolSize,
|
vol::RectVolSize,
|
||||||
Damage, DamageSource, Explosion, LoadoutBuilder, RadiusEffect,
|
Damage, DamageSource, Explosion, LoadoutBuilder, RadiusEffect,
|
||||||
};
|
};
|
||||||
@ -1164,18 +1163,23 @@ fn handle_object(
|
|||||||
server
|
server
|
||||||
.state
|
.state
|
||||||
.create_object(pos, *obj_type)
|
.create_object(pos, *obj_type)
|
||||||
.with(comp::Ori(
|
.with(
|
||||||
// converts player orientation into a 90° rotation for the object by using the
|
comp::Ori::from_unnormalized_vec(
|
||||||
// axis with the highest value
|
// converts player orientation into a 90° rotation for the object by using
|
||||||
Dir::from_unnormalized(ori.0.map(|e| {
|
// the axis with the highest value
|
||||||
if e.abs() == ori.0.map(|e| e.abs()).reduce_partial_max() {
|
{
|
||||||
|
let look_dir = ori.look_dir();
|
||||||
|
look_dir.map(|e| {
|
||||||
|
if e.abs() == look_dir.map(|e| e.abs()).reduce_partial_max() {
|
||||||
e
|
e
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
))
|
)
|
||||||
.build();
|
.build();
|
||||||
server.notify_client(
|
server.notify_client(
|
||||||
client,
|
client,
|
||||||
|
@ -518,7 +518,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Slo
|
|||||||
for (pos, ori, item) in dropped_items {
|
for (pos, ori, item) in dropped_items {
|
||||||
state
|
state
|
||||||
.create_object(Default::default(), comp::object::Body::Pouch)
|
.create_object(Default::default(), comp::object::Body::Pouch)
|
||||||
.with(comp::Pos(pos.0 + *ori.0 + Vec3::unit_z()))
|
.with(comp::Pos(pos.0 + *ori.look_dir() + Vec3::unit_z()))
|
||||||
.with(item)
|
.with(item)
|
||||||
.with(comp::Vel(Vec3::zero()))
|
.with(comp::Vel(Vec3::zero()))
|
||||||
.build();
|
.build();
|
||||||
@ -536,7 +536,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Slo
|
|||||||
),
|
),
|
||||||
_ => {
|
_ => {
|
||||||
vel.0
|
vel.0
|
||||||
+ *ori.0 * 20.0
|
+ *ori.look_dir() * 20.0
|
||||||
+ Vec3::unit_z() * 15.0
|
+ Vec3::unit_z() * 15.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
|
||||||
},
|
},
|
||||||
|
@ -11,7 +11,6 @@ use common::{
|
|||||||
},
|
},
|
||||||
effect::Effect,
|
effect::Effect,
|
||||||
uid::{Uid, UidAllocator},
|
uid::{Uid, UidAllocator},
|
||||||
util::Dir,
|
|
||||||
};
|
};
|
||||||
use common_net::{
|
use common_net::{
|
||||||
msg::{CharacterInfo, PlayerListUpdate, PresenceKind, ServerGeneral},
|
msg::{CharacterInfo, PlayerListUpdate, PresenceKind, ServerGeneral},
|
||||||
@ -148,15 +147,14 @@ 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(Dir::new(
|
.with(
|
||||||
Vec3::new(
|
comp::Ori::from_unnormalized_vec(Vec3::new(
|
||||||
thread_rng().gen_range(-1.0..1.0),
|
thread_rng().gen_range(-1.0..1.0),
|
||||||
thread_rng().gen_range(-1.0..1.0),
|
thread_rng().gen_range(-1.0..1.0),
|
||||||
0.0,
|
0.0,
|
||||||
)
|
))
|
||||||
.try_normalized()
|
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
)))
|
)
|
||||||
.with(comp::Collider::Box {
|
.with(comp::Collider::Box {
|
||||||
radius: body.radius(),
|
radius: body.radius(),
|
||||||
z_min: 0.0,
|
z_min: 0.0,
|
||||||
@ -209,7 +207,7 @@ impl StateExt for State {
|
|||||||
.create_entity_synced()
|
.create_entity_synced()
|
||||||
.with(pos)
|
.with(pos)
|
||||||
.with(vel)
|
.with(vel)
|
||||||
.with(comp::Ori(Dir::from_unnormalized(vel.0).unwrap_or_default()))
|
.with(comp::Ori::from_unnormalized_vec(vel.0).unwrap_or_default())
|
||||||
.with(comp::Mass(0.0))
|
.with(comp::Mass(0.0))
|
||||||
.with(comp::Collider::Point)
|
.with(comp::Collider::Point)
|
||||||
.with(body)
|
.with(body)
|
||||||
|
@ -198,7 +198,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
let mut inputs = &mut controller.inputs;
|
let mut inputs = &mut controller.inputs;
|
||||||
|
|
||||||
// Default to looking in orientation direction (can be overridden below)
|
// Default to looking in orientation direction (can be overridden below)
|
||||||
inputs.look_dir = ori.0;
|
inputs.look_dir = ori.look_dir();
|
||||||
|
|
||||||
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;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use common::util::Dir;
|
use common::comp::Ori;
|
||||||
use specs::Component;
|
use specs::Component;
|
||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -33,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: Dir,
|
pub ori: Ori,
|
||||||
}
|
}
|
||||||
impl Component for Interpolated {
|
impl Component for Interpolated {
|
||||||
type Storage = IdvStorage<Self>;
|
type Storage = IdvStorage<Self>;
|
||||||
|
@ -2,7 +2,6 @@ use crate::ecs::comp::Interpolated;
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{Ori, Pos, Vel},
|
comp::{Ori, Pos, Vel},
|
||||||
resources::DeltaTime,
|
resources::DeltaTime,
|
||||||
util::Dir,
|
|
||||||
};
|
};
|
||||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
@ -31,16 +30,16 @@ 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 = Dir::slerp(i.ori, ori.0, 5.0 * dt.0);
|
i.ori = Ori::slerp(i.ori, *ori, 5.0 * dt.0);
|
||||||
} else {
|
} else {
|
||||||
i.pos = pos.0;
|
i.pos = pos.0;
|
||||||
i.ori = ori.0;
|
i.ori = *ori;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert interpolation components for entities which don't have them
|
// Insert interpolation components for entities which don't have them
|
||||||
for (entity, pos, ori) in (&entities, &positions, &orientations, !&interpolated)
|
for (entity, pos, ori) in (&entities, &positions, &orientations, !&interpolated)
|
||||||
.join()
|
.join()
|
||||||
.map(|(e, p, o, _)| (e, p.0, o.0))
|
.map(|(e, p, o, _)| (e, p.0, *o))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
{
|
{
|
||||||
interpolated
|
interpolated
|
||||||
|
@ -1736,10 +1736,13 @@ impl Hud {
|
|||||||
.set(self.ids.velocity, ui_widgets);
|
.set(self.ids.velocity, ui_widgets);
|
||||||
// Player's orientation vector
|
// Player's orientation vector
|
||||||
let orientation_text = match debug_info.ori {
|
let orientation_text = match debug_info.ori {
|
||||||
Some(ori) => format!(
|
Some(ori) => {
|
||||||
|
let look_dir = ori.look_dir();
|
||||||
|
format!(
|
||||||
"Orientation: ({:.1}, {:.1}, {:.1})",
|
"Orientation: ({:.1}, {:.1}, {:.1})",
|
||||||
ori.0.x, ori.0.y, ori.0.z,
|
look_dir.x, look_dir.y, look_dir.z,
|
||||||
),
|
)
|
||||||
|
},
|
||||||
None => "Player has no Ori component".to_owned(),
|
None => "Player has no Ori component".to_owned(),
|
||||||
};
|
};
|
||||||
Text::new(&orientation_text)
|
Text::new(&orientation_text)
|
||||||
|
@ -584,12 +584,12 @@ impl FigureMgr {
|
|||||||
.map(|i| {
|
.map(|i| {
|
||||||
(
|
(
|
||||||
(anim::vek::Vec3::from(i.pos),),
|
(anim::vek::Vec3::from(i.pos),),
|
||||||
anim::vek::Vec3::from(*i.ori),
|
anim::vek::Quaternion::<f32>::from(i.ori),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or((
|
.unwrap_or((
|
||||||
(anim::vek::Vec3::<f32>::from(pos.0),),
|
(anim::vek::Vec3::<f32>::from(pos.0),),
|
||||||
anim::vek::Vec3::<f32>::unit_y(),
|
anim::vek::Quaternion::<f32>::default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
// Maintaining figure data and sending new figure data to the GPU turns out to
|
// Maintaining figure data and sending new figure data to the GPU turns out to
|
||||||
@ -754,8 +754,9 @@ impl FigureMgr {
|
|||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
vel.0,
|
vel.0,
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
state.avg_vel,
|
state.avg_vel,
|
||||||
state.acc_vel,
|
state.acc_vel,
|
||||||
@ -770,8 +771,9 @@ impl FigureMgr {
|
|||||||
(
|
(
|
||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
),
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
@ -785,8 +787,9 @@ impl FigureMgr {
|
|||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
vel.0,
|
vel.0,
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
state.avg_vel,
|
state.avg_vel,
|
||||||
),
|
),
|
||||||
@ -816,8 +819,9 @@ impl FigureMgr {
|
|||||||
(
|
(
|
||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
Some(s.stage_section),
|
Some(s.stage_section),
|
||||||
),
|
),
|
||||||
@ -861,8 +865,9 @@ impl FigureMgr {
|
|||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
vel.0.magnitude(),
|
vel.0.magnitude(),
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
Some(s.stage_section),
|
Some(s.stage_section),
|
||||||
),
|
),
|
||||||
@ -891,8 +896,9 @@ impl FigureMgr {
|
|||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
vel.0.magnitude(),
|
vel.0.magnitude(),
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
Some(s.stage_section),
|
Some(s.stage_section),
|
||||||
),
|
),
|
||||||
@ -967,7 +973,14 @@ impl FigureMgr {
|
|||||||
CharacterState::Sneak { .. } => {
|
CharacterState::Sneak { .. } => {
|
||||||
anim::character::SneakAnimation::update_skeleton(
|
anim::character::SneakAnimation::update_skeleton(
|
||||||
&target_base,
|
&target_base,
|
||||||
(active_tool_kind, vel.0, ori, state.last_ori, time),
|
(
|
||||||
|
active_tool_kind,
|
||||||
|
vel.0,
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -1308,8 +1321,9 @@ impl FigureMgr {
|
|||||||
(
|
(
|
||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
vel.0,
|
vel.0,
|
||||||
time,
|
time,
|
||||||
),
|
),
|
||||||
@ -1326,8 +1340,9 @@ impl FigureMgr {
|
|||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
vel.0,
|
vel.0,
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
),
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
@ -1338,7 +1353,14 @@ impl FigureMgr {
|
|||||||
CharacterState::Climb { .. } => {
|
CharacterState::Climb { .. } => {
|
||||||
anim::character::ClimbAnimation::update_skeleton(
|
anim::character::ClimbAnimation::update_skeleton(
|
||||||
&target_base,
|
&target_base,
|
||||||
(active_tool_kind, second_tool_kind, vel.0, ori, time),
|
(
|
||||||
|
active_tool_kind,
|
||||||
|
second_tool_kind,
|
||||||
|
vel.0,
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -1360,8 +1382,9 @@ impl FigureMgr {
|
|||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
vel.0,
|
vel.0,
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
),
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
@ -1448,7 +1471,14 @@ impl FigureMgr {
|
|||||||
(true, true, false) => {
|
(true, true, false) => {
|
||||||
anim::quadruped_small::RunAnimation::update_skeleton(
|
anim::quadruped_small::RunAnimation::update_skeleton(
|
||||||
&QuadrupedSmallSkeleton::default(),
|
&QuadrupedSmallSkeleton::default(),
|
||||||
(vel.0.magnitude(), ori, state.last_ori, time, state.avg_vel),
|
(
|
||||||
|
vel.0.magnitude(),
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
state.avg_vel,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -1457,7 +1487,14 @@ impl FigureMgr {
|
|||||||
// Running
|
// Running
|
||||||
(false, _, true) => anim::quadruped_small::RunAnimation::update_skeleton(
|
(false, _, true) => anim::quadruped_small::RunAnimation::update_skeleton(
|
||||||
&QuadrupedSmallSkeleton::default(),
|
&QuadrupedSmallSkeleton::default(),
|
||||||
(vel.0.magnitude(), ori, state.last_ori, time, state.avg_vel),
|
(
|
||||||
|
vel.0.magnitude(),
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
state.avg_vel,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -1644,8 +1681,9 @@ impl FigureMgr {
|
|||||||
&QuadrupedMediumSkeleton::default(),
|
&QuadrupedMediumSkeleton::default(),
|
||||||
(
|
(
|
||||||
vel.0.magnitude(),
|
vel.0.magnitude(),
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
state.avg_vel,
|
state.avg_vel,
|
||||||
state.acc_vel,
|
state.acc_vel,
|
||||||
@ -1660,8 +1698,9 @@ impl FigureMgr {
|
|||||||
&QuadrupedMediumSkeleton::default(),
|
&QuadrupedMediumSkeleton::default(),
|
||||||
(
|
(
|
||||||
vel.0.magnitude(),
|
vel.0.magnitude(),
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
state.avg_vel,
|
state.avg_vel,
|
||||||
state.acc_vel,
|
state.acc_vel,
|
||||||
@ -1962,7 +2001,14 @@ impl FigureMgr {
|
|||||||
// Running
|
// Running
|
||||||
(true, true, false) => anim::quadruped_low::RunAnimation::update_skeleton(
|
(true, true, false) => anim::quadruped_low::RunAnimation::update_skeleton(
|
||||||
&QuadrupedLowSkeleton::default(),
|
&QuadrupedLowSkeleton::default(),
|
||||||
(vel.0.magnitude(), ori, state.last_ori, time, state.avg_vel),
|
(
|
||||||
|
vel.0.magnitude(),
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
state.avg_vel,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -1970,7 +2016,14 @@ impl FigureMgr {
|
|||||||
// Swimming
|
// Swimming
|
||||||
(false, _, true) => anim::quadruped_low::RunAnimation::update_skeleton(
|
(false, _, true) => anim::quadruped_low::RunAnimation::update_skeleton(
|
||||||
&QuadrupedLowSkeleton::default(),
|
&QuadrupedLowSkeleton::default(),
|
||||||
(vel.0.magnitude(), ori, state.last_ori, time, state.avg_vel),
|
(
|
||||||
|
vel.0.magnitude(),
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
state.avg_vel,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -2397,7 +2450,14 @@ impl FigureMgr {
|
|||||||
// Idle
|
// Idle
|
||||||
(_, false, _) => anim::fish_medium::IdleAnimation::update_skeleton(
|
(_, false, _) => anim::fish_medium::IdleAnimation::update_skeleton(
|
||||||
&FishMediumSkeleton::default(),
|
&FishMediumSkeleton::default(),
|
||||||
(vel.0, ori, state.last_ori, time, state.avg_vel),
|
(
|
||||||
|
vel.0,
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
state.avg_vel,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -2407,8 +2467,9 @@ impl FigureMgr {
|
|||||||
&FishMediumSkeleton::default(),
|
&FishMediumSkeleton::default(),
|
||||||
(
|
(
|
||||||
vel.0,
|
vel.0,
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
state.avg_vel,
|
state.avg_vel,
|
||||||
state.acc_vel,
|
state.acc_vel,
|
||||||
@ -2479,7 +2540,14 @@ impl FigureMgr {
|
|||||||
// Running
|
// Running
|
||||||
(true, true, false) => anim::dragon::RunAnimation::update_skeleton(
|
(true, true, false) => anim::dragon::RunAnimation::update_skeleton(
|
||||||
&DragonSkeleton::default(),
|
&DragonSkeleton::default(),
|
||||||
(vel.0.magnitude(), ori, state.last_ori, time, state.avg_vel),
|
(
|
||||||
|
vel.0.magnitude(),
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
state.avg_vel,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -2563,7 +2631,14 @@ impl FigureMgr {
|
|||||||
// Running
|
// Running
|
||||||
(true, true, false) => anim::theropod::RunAnimation::update_skeleton(
|
(true, true, false) => anim::theropod::RunAnimation::update_skeleton(
|
||||||
&TheropodSkeleton::default(),
|
&TheropodSkeleton::default(),
|
||||||
(vel.0.magnitude(), ori, state.last_ori, time, state.avg_vel),
|
(
|
||||||
|
vel.0.magnitude(),
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
state.avg_vel,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -2571,7 +2646,14 @@ impl FigureMgr {
|
|||||||
// In air
|
// In air
|
||||||
(false, _, false) => anim::theropod::JumpAnimation::update_skeleton(
|
(false, _, false) => anim::theropod::JumpAnimation::update_skeleton(
|
||||||
&TheropodSkeleton::default(),
|
&TheropodSkeleton::default(),
|
||||||
(vel.0.magnitude(), ori, state.last_ori, time, state.avg_vel),
|
(
|
||||||
|
vel.0.magnitude(),
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
state.avg_vel,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -2782,7 +2864,14 @@ impl FigureMgr {
|
|||||||
// Idle
|
// Idle
|
||||||
(_, false, _) => anim::fish_small::IdleAnimation::update_skeleton(
|
(_, false, _) => anim::fish_small::IdleAnimation::update_skeleton(
|
||||||
&FishSmallSkeleton::default(),
|
&FishSmallSkeleton::default(),
|
||||||
(vel.0, ori, state.last_ori, time, state.avg_vel),
|
(
|
||||||
|
vel.0,
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
state.avg_vel,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -2792,8 +2881,9 @@ impl FigureMgr {
|
|||||||
&FishSmallSkeleton::default(),
|
&FishSmallSkeleton::default(),
|
||||||
(
|
(
|
||||||
vel.0,
|
vel.0,
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
state.avg_vel,
|
state.avg_vel,
|
||||||
state.acc_vel,
|
state.acc_vel,
|
||||||
@ -2863,8 +2953,9 @@ impl FigureMgr {
|
|||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
vel.0.magnitude(),
|
vel.0.magnitude(),
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
state.avg_vel,
|
state.avg_vel,
|
||||||
),
|
),
|
||||||
@ -2942,8 +3033,9 @@ impl FigureMgr {
|
|||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
vel.0.magnitude(),
|
vel.0.magnitude(),
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
Some(s.stage_section),
|
Some(s.stage_section),
|
||||||
),
|
),
|
||||||
@ -2972,8 +3064,9 @@ impl FigureMgr {
|
|||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
vel.0.magnitude(),
|
vel.0.magnitude(),
|
||||||
ori,
|
// TODO: Update to use the quaternion.
|
||||||
state.last_ori,
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
time,
|
time,
|
||||||
Some(s.stage_section),
|
Some(s.stage_section),
|
||||||
),
|
),
|
||||||
@ -3271,7 +3364,13 @@ impl FigureMgr {
|
|||||||
// Running
|
// Running
|
||||||
(true, true, false) => anim::golem::RunAnimation::update_skeleton(
|
(true, true, false) => anim::golem::RunAnimation::update_skeleton(
|
||||||
&GolemSkeleton::default(),
|
&GolemSkeleton::default(),
|
||||||
(vel.0.magnitude(), ori, state.last_ori, time),
|
(
|
||||||
|
vel.0.magnitude(),
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
&mut state_animation_rate,
|
&mut state_animation_rate,
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
@ -3974,7 +4073,7 @@ pub struct FigureStateMeta {
|
|||||||
locals: Consts<FigureLocals>,
|
locals: Consts<FigureLocals>,
|
||||||
lantern_offset: anim::vek::Vec3<f32>,
|
lantern_offset: anim::vek::Vec3<f32>,
|
||||||
state_time: f64,
|
state_time: f64,
|
||||||
last_ori: anim::vek::Vec3<f32>,
|
last_ori: anim::vek::Quaternion<f32>,
|
||||||
lpindex: u8,
|
lpindex: u8,
|
||||||
can_shadow_sun: bool,
|
can_shadow_sun: bool,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
@ -4021,7 +4120,7 @@ impl<S: Skeleton> FigureState<S> {
|
|||||||
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
|
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
|
||||||
lantern_offset,
|
lantern_offset,
|
||||||
state_time: 0.0,
|
state_time: 0.0,
|
||||||
last_ori: anim::vek::Vec3::zero(),
|
last_ori: Ori::default().into(),
|
||||||
lpindex: 0,
|
lpindex: 0,
|
||||||
visible: false,
|
visible: false,
|
||||||
can_shadow_sun: false,
|
can_shadow_sun: false,
|
||||||
@ -4040,7 +4139,7 @@ impl<S: Skeleton> FigureState<S> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
pos: anim::vek::Vec3<f32>,
|
pos: anim::vek::Vec3<f32>,
|
||||||
ori: anim::vek::Vec3<f32>,
|
ori: anim::vek::Quaternion<f32>,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
col: vek::Rgba<f32>,
|
col: vek::Rgba<f32>,
|
||||||
dt: f32,
|
dt: f32,
|
||||||
@ -4079,13 +4178,14 @@ impl<S: Skeleton> FigureState<S> {
|
|||||||
/* let radius = vek::Extent3::<f32>::from(model.bounds.half_size()).reduce_partial_max();
|
/* let radius = vek::Extent3::<f32>::from(model.bounds.half_size()).reduce_partial_max();
|
||||||
let _bounds = BoundingSphere::new(pos.into_array(), scale * 0.8 * radius); */
|
let _bounds = BoundingSphere::new(pos.into_array(), scale * 0.8 * radius); */
|
||||||
|
|
||||||
self.last_ori = vek::Lerp::lerp(self.last_ori, ori, 15.0 * dt);
|
self.last_ori = vek::Lerp::lerp(self.last_ori, ori, 15.0 * dt).normalized();
|
||||||
|
|
||||||
self.state_time += (dt * state_animation_rate) as f64;
|
self.state_time += (dt * state_animation_rate) as f64;
|
||||||
|
|
||||||
let mat = anim::vek::Mat4::rotation_z(-ori.x.atan2(ori.y))
|
let mat = {
|
||||||
* anim::vek::Mat4::rotation_x(ori.z.atan2(anim::vek::Vec2::from(ori).magnitude()))
|
anim::vek::Mat4::from(ori)
|
||||||
* anim::vek::Mat4::scaling_3d(anim::vek::Vec3::from(0.8 * scale));
|
* anim::vek::Mat4::scaling_3d(anim::vek::Vec3::from(0.8 * scale))
|
||||||
|
};
|
||||||
|
|
||||||
let atlas_offs = model.allocation.rectangle.min;
|
let atlas_offs = model.allocation.rectangle.min;
|
||||||
|
|
||||||
|
@ -571,17 +571,12 @@ impl Scene {
|
|||||||
})
|
})
|
||||||
.map(|(pos, ori, interpolated, light_anim)| {
|
.map(|(pos, ori, interpolated, light_anim)| {
|
||||||
// Use interpolated values if they are available
|
// Use interpolated values if they are available
|
||||||
let (pos, ori) =
|
let (pos, rot) = interpolated
|
||||||
interpolated.map_or((pos.0, ori.map(|o| o.0)), |i| (i.pos, Some(i.ori)));
|
.map_or((pos.0, ori.copied().unwrap_or_default()), |i| {
|
||||||
let rot = {
|
(i.pos, i.ori)
|
||||||
if let Some(o) = ori {
|
});
|
||||||
Mat3::rotation_z(-o.x.atan2(o.y))
|
|
||||||
} else {
|
|
||||||
Mat3::identity()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Light::new(
|
Light::new(
|
||||||
pos + (rot * light_anim.offset),
|
pos + (rot.to_quat() * light_anim.offset),
|
||||||
light_anim.col,
|
light_anim.col,
|
||||||
light_anim.strength,
|
light_anim.strength,
|
||||||
)
|
)
|
||||||
|
@ -375,7 +375,7 @@ impl ParticleMgr {
|
|||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
if let CharacterState::BasicBeam(b) = character_state {
|
if let CharacterState::BasicBeam(b) = character_state {
|
||||||
let particle_ori = b.particle_ori.unwrap_or(*ori.vec());
|
let particle_ori = b.particle_ori.unwrap_or_else(|| ori.look_vec());
|
||||||
if b.stage_section == StageSection::Cast {
|
if b.stage_section == StageSection::Cast {
|
||||||
if b.static_data.base_hps > 0.0 {
|
if b.static_data.base_hps > 0.0 {
|
||||||
// Emit a light when using healing
|
// Emit a light when using healing
|
||||||
@ -586,7 +586,8 @@ impl ParticleMgr {
|
|||||||
|
|
||||||
let radians = shockwave.properties.angle.to_radians();
|
let radians = shockwave.properties.angle.to_radians();
|
||||||
|
|
||||||
let theta = ori.0.y.atan2(ori.0.x);
|
let ori_vec = ori.look_vec();
|
||||||
|
let theta = ori_vec.y.atan2(ori_vec.x);
|
||||||
let dtheta = radians / distance;
|
let dtheta = radians / distance;
|
||||||
|
|
||||||
let heartbeats = self.scheduler.heartbeats(Duration::from_millis(1));
|
let heartbeats = self.scheduler.heartbeats(Duration::from_millis(1));
|
||||||
|
@ -183,7 +183,10 @@ impl Scene {
|
|||||||
state.update(
|
state.update(
|
||||||
renderer,
|
renderer,
|
||||||
anim::vek::Vec3::zero(),
|
anim::vek::Vec3::zero(),
|
||||||
|
anim::vek::Quaternion::rotation_from_to_3d(
|
||||||
|
anim::vek::Vec3::unit_y(),
|
||||||
anim::vek::Vec3::new(start_angle.sin(), -start_angle.cos(), 0.0),
|
anim::vek::Vec3::new(start_angle.sin(), -start_angle.cos(), 0.0),
|
||||||
|
),
|
||||||
1.0,
|
1.0,
|
||||||
Rgba::broadcast(1.0),
|
Rgba::broadcast(1.0),
|
||||||
15.0, // Want to get there immediately.
|
15.0, // Want to get there immediately.
|
||||||
@ -350,7 +353,10 @@ impl Scene {
|
|||||||
self.figure_state.update(
|
self.figure_state.update(
|
||||||
renderer,
|
renderer,
|
||||||
anim::vek::Vec3::zero(),
|
anim::vek::Vec3::zero(),
|
||||||
|
anim::vek::Quaternion::rotation_from_to_3d(
|
||||||
|
anim::vek::Vec3::unit_y(),
|
||||||
anim::vek::Vec3::new(self.char_ori.sin(), -self.char_ori.cos(), 0.0),
|
anim::vek::Vec3::new(self.char_ori.sin(), -self.char_ori.cos(), 0.0),
|
||||||
|
),
|
||||||
1.0,
|
1.0,
|
||||||
Rgba::broadcast(1.0),
|
Rgba::broadcast(1.0),
|
||||||
scene_data.delta_time,
|
scene_data.delta_time,
|
||||||
|
Loading…
Reference in New Issue
Block a user