mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Exponential interpolation for linear damping
With an additional approximation to allow for the same size jumps given different framerates.
This commit is contained in:
parent
980bbbb711
commit
3f2e22f039
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -3197,11 +3197,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sphynx"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.com/veloren/sphynx.git?rev=11cdc7422568aaabd376c87242a60f636e68b40d#11cdc7422568aaabd376c87242a60f636e68b40d"
|
||||
source = "git+https://gitlab.com/veloren/sphynx.git?rev=ac4adf54d181339a789907acd27f61fe81daa455#ac4adf54d181339a789907acd27f61fe81daa455"
|
||||
dependencies = [
|
||||
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shred 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sum_type 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -3601,7 +3600,7 @@ dependencies = [
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"specs-idvs 0.1.0 (git+https://gitlab.com/veloren/specs-idvs.git)",
|
||||
"sphynx 0.1.0 (git+https://gitlab.com/veloren/sphynx.git?rev=11cdc7422568aaabd376c87242a60f636e68b40d)",
|
||||
"sphynx 0.1.0 (git+https://gitlab.com/veloren/sphynx.git?rev=ac4adf54d181339a789907acd27f61fe81daa455)",
|
||||
"vek 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -4258,7 +4257,7 @@ dependencies = [
|
||||
"checksum smithay-client-toolkit 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2ccb8c57049b2a34d2cc2b203fa785020ba0129d31920ef0d317430adaf748fa"
|
||||
"checksum specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "de65613ada4338aa7ba71eca60eca24c60483433eec0077bc4f33cfc31f4bdf0"
|
||||
"checksum specs-idvs 0.1.0 (git+https://gitlab.com/veloren/specs-idvs.git)" = "<none>"
|
||||
"checksum sphynx 0.1.0 (git+https://gitlab.com/veloren/sphynx.git?rev=11cdc7422568aaabd376c87242a60f636e68b40d)" = "<none>"
|
||||
"checksum sphynx 0.1.0 (git+https://gitlab.com/veloren/sphynx.git?rev=ac4adf54d181339a789907acd27f61fe81daa455)" = "<none>"
|
||||
"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
|
||||
|
BIN
assets/voxygen/element/skillbar/stamina_wheel-0.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skillbar/stamina_wheel-0.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/skillbar/stamina_wheel-1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skillbar/stamina_wheel-1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/skillbar/stamina_wheel-2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skillbar/stamina_wheel-2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/skillbar/stamina_wheel-3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skillbar/stamina_wheel-3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/skillbar/stamina_wheel-4.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skillbar/stamina_wheel-4.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/skillbar/stamina_wheel-5.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skillbar/stamina_wheel-5.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/skillbar/stamina_wheel-6.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skillbar/stamina_wheel-6.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/skillbar/stamina_wheel-7.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skillbar/stamina_wheel-7.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/skillbar/stamina_wheel-empty.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skillbar/stamina_wheel-empty.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -155,7 +155,7 @@ float fog(vec3 f_pos, vec3 focus_pos, uint medium) {
|
||||
float max_fog = 1.0;
|
||||
|
||||
if (medium == 1u) {
|
||||
mist_radius = 32.0;
|
||||
mist_radius = 96.0;
|
||||
min_fog = 0.0;
|
||||
}
|
||||
|
||||
|
@ -163,6 +163,10 @@ vec3 hsv2rgb(vec3 c) {
|
||||
void main() {
|
||||
vec2 uv = (f_pos + 1.0) * 0.5;
|
||||
|
||||
if (medium.x == 1u) {
|
||||
uv = clamp(uv + vec2(sin(uv.y * 16.0 + tick.x), sin(uv.x * 24.0 + tick.x)) * 0.005, 0, 1);
|
||||
}
|
||||
|
||||
vec4 fxaa_color = fxaa_apply(src_color, uv * screen_res.xy, screen_res.xy);
|
||||
//vec4 fxaa_color = texture(src_color, uv);
|
||||
|
||||
@ -173,5 +177,9 @@ void main() {
|
||||
vec4 final_color = fxaa_color;
|
||||
//vec4 final_color = vec4(hsv2rgb(hsva_color.rgb), hsva_color.a);
|
||||
|
||||
if (medium.x == 1u) {
|
||||
final_color *= vec4(0.2, 0.2, 0.8, 1.0);
|
||||
}
|
||||
|
||||
tgt_color = vec4(final_color.rgb, 1);
|
||||
}
|
||||
|
@ -194,6 +194,14 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_mounted(&self) -> bool {
|
||||
self.state
|
||||
.ecs()
|
||||
.read_storage::<comp::Mounting>()
|
||||
.get(self.entity)
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn view_distance(&self) -> Option<u32> {
|
||||
self.view_distance
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>", "Maciej Ćwięka <mc
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
sphynx = { git = "https://gitlab.com/veloren/sphynx.git", features = ["serde1"], rev = "11cdc7422568aaabd376c87242a60f636e68b40d" }
|
||||
sphynx = { git = "https://gitlab.com/veloren/sphynx.git", features = ["serde1"], rev = "ac4adf54d181339a789907acd27f61fe81daa455" }
|
||||
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git" }
|
||||
|
||||
specs = { version = "0.14.2", features = ["serde", "nightly"] }
|
||||
|
@ -5,11 +5,13 @@ use std::time::Duration;
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum MovementState {
|
||||
Stand,
|
||||
Sit,
|
||||
Run,
|
||||
Jump,
|
||||
Glide,
|
||||
Roll { time_left: Duration },
|
||||
//Swim,
|
||||
Swim,
|
||||
Climb,
|
||||
}
|
||||
|
||||
impl MovementState {
|
||||
|
@ -1,19 +1,62 @@
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
use sphynx::Uid;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ControlEvent {
|
||||
Mount(Uid),
|
||||
Unmount,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Controller {
|
||||
pub primary: bool,
|
||||
pub secondary: bool,
|
||||
pub move_dir: Vec2<f32>,
|
||||
pub look_dir: Vec3<f32>,
|
||||
pub sit: bool,
|
||||
pub jump: bool,
|
||||
pub roll: bool,
|
||||
pub glide: bool,
|
||||
pub climb: bool,
|
||||
pub climb_down: bool,
|
||||
pub wall_leap: bool,
|
||||
pub respawn: bool,
|
||||
pub events: Vec<ControlEvent>,
|
||||
}
|
||||
|
||||
impl Controller {
|
||||
pub fn reset(&mut self) {
|
||||
*self = Self::default();
|
||||
}
|
||||
|
||||
pub fn clear_events(&mut self) {
|
||||
self.events.clear();
|
||||
}
|
||||
|
||||
pub fn push_event(&mut self, event: ControlEvent) {
|
||||
self.events.push(event);
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Controller {
|
||||
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MountState {
|
||||
Unmounted,
|
||||
MountedBy(Uid),
|
||||
}
|
||||
|
||||
impl Component for MountState {
|
||||
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Mounting(pub Uid);
|
||||
|
||||
impl Component for Mounting {
|
||||
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ pub use admin::Admin;
|
||||
pub use agent::Agent;
|
||||
pub use body::{humanoid, object, quadruped, quadruped_medium, Body};
|
||||
pub use character_state::{ActionState, CharacterState, MovementState};
|
||||
pub use controller::Controller;
|
||||
pub use controller::{ControlEvent, Controller, MountState, Mounting};
|
||||
pub use inputs::CanBuild;
|
||||
pub use inventory::{item, Inventory, InventoryUpdate, Item};
|
||||
pub use last::Last;
|
||||
|
@ -38,6 +38,8 @@ impl Component for Scale {
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PhysicsState {
|
||||
pub on_ground: bool,
|
||||
pub on_wall: Option<Vec3<f32>>,
|
||||
pub in_fluid: bool,
|
||||
}
|
||||
|
||||
impl Component for PhysicsState {
|
||||
|
@ -6,8 +6,18 @@ use vek::*;
|
||||
|
||||
pub enum LocalEvent {
|
||||
Jump(EcsEntity),
|
||||
Boost { entity: EcsEntity, vel: Vec3<f32> },
|
||||
LandOnGround { entity: EcsEntity, vel: Vec3<f32> },
|
||||
WallLeap {
|
||||
entity: EcsEntity,
|
||||
wall_dir: Vec3<f32>,
|
||||
},
|
||||
Boost {
|
||||
entity: EcsEntity,
|
||||
vel: Vec3<f32>,
|
||||
},
|
||||
LandOnGround {
|
||||
entity: EcsEntity,
|
||||
vel: Vec3<f32>,
|
||||
},
|
||||
}
|
||||
|
||||
pub enum ServerEvent {
|
||||
@ -21,6 +31,8 @@ pub enum ServerEvent {
|
||||
},
|
||||
Respawn(EcsEntity),
|
||||
Shoot(EcsEntity),
|
||||
Mount(EcsEntity, EcsEntity),
|
||||
Unmount(EcsEntity),
|
||||
}
|
||||
|
||||
pub struct EventBus<E> {
|
||||
|
@ -27,6 +27,8 @@ sphynx::sum_type! {
|
||||
LightEmitter(comp::LightEmitter),
|
||||
Item(comp::Item),
|
||||
Scale(comp::Scale),
|
||||
MountState(comp::MountState),
|
||||
Mounting(comp::Mounting),
|
||||
}
|
||||
}
|
||||
// Automatically derive From<T> for EcsCompPhantom
|
||||
@ -44,6 +46,8 @@ sphynx::sum_type! {
|
||||
LightEmitter(PhantomData<comp::LightEmitter>),
|
||||
Item(PhantomData<comp::Item>),
|
||||
Scale(PhantomData<comp::Scale>),
|
||||
MountState(PhantomData<comp::MountState>),
|
||||
Mounting(PhantomData<comp::Mounting>),
|
||||
}
|
||||
}
|
||||
impl sphynx::CompPacket for EcsCompPacket {
|
||||
|
@ -13,9 +13,10 @@ use hashbrown::{HashMap, HashSet};
|
||||
use rayon::{ThreadPool, ThreadPoolBuilder};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use specs::{
|
||||
saveload::Marker,
|
||||
shred::{Fetch, FetchMut},
|
||||
storage::{MaskedStorage as EcsMaskedStorage, Storage as EcsStorage},
|
||||
Component, DispatcherBuilder, Entity as EcsEntity,
|
||||
Component, DispatcherBuilder, Entity as EcsEntity, Join,
|
||||
};
|
||||
use sphynx;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
@ -42,7 +43,7 @@ pub struct DeltaTime(pub f32);
|
||||
/// upper limit. If delta time exceeds this value, the game's physics will begin to produce time
|
||||
/// lag. Ideally, we'd avoid such a situation.
|
||||
const MAX_DELTA_TIME: f32 = 1.0;
|
||||
const HUMANOID_JUMP_ACCEL: f32 = 18.0;
|
||||
const HUMANOID_JUMP_ACCEL: f32 = 16.0;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BlockChange {
|
||||
@ -119,6 +120,8 @@ impl State {
|
||||
ecs.register_synced::<comp::LightEmitter>();
|
||||
ecs.register_synced::<comp::Item>();
|
||||
ecs.register_synced::<comp::Scale>();
|
||||
ecs.register_synced::<comp::Mounting>();
|
||||
ecs.register_synced::<comp::MountState>();
|
||||
|
||||
// Register components send from clients -> server
|
||||
ecs.register::<comp::Controller>();
|
||||
@ -145,7 +148,7 @@ impl State {
|
||||
ecs.register::<comp::Admin>();
|
||||
|
||||
// Register synced resources used by the ECS.
|
||||
ecs.add_resource_synced(TimeOfDay(0.0));
|
||||
ecs.insert_synced(TimeOfDay(0.0));
|
||||
|
||||
// Register unsynced resources used by the ECS.
|
||||
ecs.add_resource(Time(0.0));
|
||||
@ -171,6 +174,11 @@ impl State {
|
||||
let _ = self.ecs.write_storage().insert(entity, comp);
|
||||
}
|
||||
|
||||
/// Delete a component attributed to a particular entity.
|
||||
pub fn delete_component<C: Component>(&mut self, entity: EcsEntity) -> Option<C> {
|
||||
self.ecs.write_storage().remove(entity)
|
||||
}
|
||||
|
||||
/// Read a component attributed to a particular entity.
|
||||
pub fn read_component_cloned<C: Component + Clone>(&self, entity: EcsEntity) -> Option<C> {
|
||||
self.ecs.read_storage().get(entity).cloned()
|
||||
@ -289,6 +297,68 @@ impl State {
|
||||
// Beyond a delta time of MAX_DELTA_TIME, start lagging to avoid skipping important physics events.
|
||||
self.ecs.write_resource::<DeltaTime>().0 = dt.as_secs_f32().min(MAX_DELTA_TIME);
|
||||
|
||||
// Mounted entities. We handle this here because we need access to the Uid registry and I
|
||||
// forgot how to access that within a system. Anyhow, here goes.
|
||||
for (entity, mount_state) in (
|
||||
&self.ecs.entities(),
|
||||
&mut self.ecs.write_storage::<comp::MountState>(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
match mount_state {
|
||||
comp::MountState::Unmounted => {}
|
||||
comp::MountState::MountedBy(mounter) => {
|
||||
if let Some((controller, mounter)) =
|
||||
self.ecs.entity_from_uid(mounter.id()).and_then(|mounter| {
|
||||
self.ecs
|
||||
.read_storage::<comp::Controller>()
|
||||
.get(mounter)
|
||||
.cloned()
|
||||
.map(|x| (x, mounter))
|
||||
})
|
||||
{
|
||||
let pos = self.ecs.read_storage::<comp::Pos>().get(entity).copied();
|
||||
let ori = self.ecs.read_storage::<comp::Ori>().get(entity).copied();
|
||||
let vel = self.ecs.read_storage::<comp::Vel>().get(entity).copied();
|
||||
if let (Some(pos), Some(ori), Some(vel)) = (pos, ori, vel) {
|
||||
let _ = self
|
||||
.ecs
|
||||
.write_storage()
|
||||
.insert(mounter, comp::Pos(pos.0 + Vec3::unit_z() * 1.0));
|
||||
let _ = self.ecs.write_storage().insert(mounter, ori);
|
||||
let _ = self.ecs.write_storage().insert(mounter, vel);
|
||||
}
|
||||
let _ = self
|
||||
.ecs
|
||||
.write_storage::<comp::Controller>()
|
||||
.insert(entity, controller);
|
||||
} else {
|
||||
*mount_state = comp::MountState::Unmounted;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut to_unmount = Vec::new();
|
||||
for (entity, comp::Mounting(mountee)) in (
|
||||
&self.ecs.entities(),
|
||||
&self.ecs.read_storage::<comp::Mounting>(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
if self
|
||||
.ecs
|
||||
.entity_from_uid(mountee.id())
|
||||
.filter(|mountee| self.ecs.is_alive(*mountee))
|
||||
.is_none()
|
||||
{
|
||||
to_unmount.push(entity);
|
||||
}
|
||||
}
|
||||
for entity in to_unmount {
|
||||
self.ecs.write_storage::<comp::Mounting>().remove(entity);
|
||||
}
|
||||
|
||||
// Run systems to update the world.
|
||||
// Create and run a dispatcher for ecs systems.
|
||||
let mut dispatch_builder = DispatcherBuilder::new().with_pool(self.thread_pool.clone());
|
||||
@ -316,6 +386,7 @@ impl State {
|
||||
let events = self.ecs.read_resource::<EventBus<LocalEvent>>().recv_all();
|
||||
for event in events {
|
||||
let mut velocities = self.ecs.write_storage::<comp::Vel>();
|
||||
let mut controllers = self.ecs.write_storage::<comp::Controller>();
|
||||
match event {
|
||||
LocalEvent::LandOnGround { entity, vel } => {
|
||||
if let Some(stats) = self.ecs.write_storage::<comp::Stats>().get_mut(entity) {
|
||||
@ -325,13 +396,26 @@ impl State {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LocalEvent::Jump(entity) => {
|
||||
if let Some(vel) = velocities.get_mut(entity) {
|
||||
vel.0.z = HUMANOID_JUMP_ACCEL;
|
||||
}
|
||||
}
|
||||
|
||||
LocalEvent::WallLeap { entity, wall_dir } => {
|
||||
if let (Some(vel), Some(_controller)) =
|
||||
(velocities.get_mut(entity), controllers.get_mut(entity))
|
||||
{
|
||||
let hspeed = Vec2::<f32>::from(vel.0).magnitude();
|
||||
if hspeed > 0.001 && hspeed < 0.5 {
|
||||
vel.0 += vel.0.normalized()
|
||||
* Vec3::new(1.0, 1.0, 0.0)
|
||||
* HUMANOID_JUMP_ACCEL
|
||||
* 1.5
|
||||
- wall_dir * 0.03;
|
||||
vel.0.z = HUMANOID_JUMP_ACCEL * 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
LocalEvent::Boost {
|
||||
entity,
|
||||
vel: extra_vel,
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::comp::{Agent, CharacterState, Controller, MovementState::Glide, Pos, Stats};
|
||||
use crate::comp::{
|
||||
Agent, CharacterState, Controller, MountState, MovementState::Glide, Pos, Stats,
|
||||
};
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use specs::{Entities, Join, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
@ -13,15 +15,38 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, CharacterState>,
|
||||
WriteStorage<'a, Agent>,
|
||||
WriteStorage<'a, Controller>,
|
||||
ReadStorage<'a, MountState>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(entities, positions, stats, character_states, mut agents, mut controllers): Self::SystemData,
|
||||
(entities, positions, stats, character_states, mut agents, mut controllers, mount_states): Self::SystemData,
|
||||
) {
|
||||
for (entity, pos, agent, controller) in
|
||||
(&entities, &positions, &mut agents, &mut controllers).join()
|
||||
for (entity, pos, agent, controller, mount_state) in (
|
||||
&entities,
|
||||
&positions,
|
||||
&mut agents,
|
||||
&mut controllers,
|
||||
mount_states.maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
// Skip mounted entities
|
||||
if mount_state
|
||||
.map(|ms| {
|
||||
if let MountState::Unmounted = ms {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
controller.reset();
|
||||
|
||||
match agent {
|
||||
Agent::Wanderer(bearing) => {
|
||||
*bearing += Vec2::new(rand::random::<f32>() - 0.5, rand::random::<f32>() - 0.5)
|
||||
@ -29,7 +54,7 @@ impl<'a> System<'a> for Sys {
|
||||
- *bearing * 0.01
|
||||
- pos.0 * 0.0002;
|
||||
|
||||
if bearing.magnitude_squared() != 0.0 {
|
||||
if bearing.magnitude_squared() > 0.001 {
|
||||
controller.move_dir = bearing.normalized();
|
||||
}
|
||||
}
|
||||
@ -47,7 +72,7 @@ impl<'a> System<'a> for Sys {
|
||||
let dist: f32 = Vec2::from(tgt_pos - pos.0).magnitude();
|
||||
controller.move_dir = if dist > 5.0 {
|
||||
Vec2::from(tgt_pos - pos.0).normalized()
|
||||
} else if dist < 1.5 && dist > 0.0 {
|
||||
} else if dist < 1.5 && dist > 0.001 {
|
||||
Vec2::from(pos.0 - tgt_pos).normalized()
|
||||
} else {
|
||||
Vec2::zero()
|
||||
@ -82,7 +107,7 @@ impl<'a> System<'a> for Sys {
|
||||
let dist = Vec2::<f32>::from(target_pos.0 - pos.0).magnitude();
|
||||
if target_stats.is_dead {
|
||||
choose_new = true;
|
||||
} else if dist < MIN_ATTACK_DIST {
|
||||
} else if dist < MIN_ATTACK_DIST && dist > 0.001 {
|
||||
// Fight (and slowly move closer)
|
||||
controller.move_dir =
|
||||
Vec2::<f32>::from(target_pos.0 - pos.0).normalized() * 0.01;
|
||||
@ -109,7 +134,7 @@ impl<'a> System<'a> for Sys {
|
||||
* 0.1
|
||||
- *bearing * 0.005;
|
||||
|
||||
controller.move_dir = if bearing.magnitude_squared() > 0.1 {
|
||||
controller.move_dir = if bearing.magnitude_squared() > 0.001 {
|
||||
bearing.normalized()
|
||||
} else {
|
||||
Vec2::zero()
|
||||
|
@ -1,14 +1,12 @@
|
||||
use crate::comp::Controller;
|
||||
use specs::{Join, System, WriteStorage};
|
||||
use specs::{System, WriteStorage};
|
||||
|
||||
/// This system will allow NPCs to modify their controller
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = WriteStorage<'a, Controller>;
|
||||
|
||||
fn run(&mut self, mut controllers: Self::SystemData) {
|
||||
for controller in (&mut controllers).join() {
|
||||
*controller = Controller::default();
|
||||
}
|
||||
fn run(&mut self, _controllers: Self::SystemData) {
|
||||
// TODO: More stuff here
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,16 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
comp::{
|
||||
item, ActionState::*, Body, CharacterState, Controller, Item, MovementState::*,
|
||||
PhysicsState, Stats, Vel,
|
||||
item, ActionState::*, Body, CharacterState, ControlEvent, Controller, Item,
|
||||
MovementState::*, PhysicsState, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
use specs::{
|
||||
saveload::{Marker, MarkerAllocator},
|
||||
Entities, Join, Read, ReadStorage, System, WriteStorage,
|
||||
};
|
||||
use sphynx::UidAllocator;
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
|
||||
@ -17,6 +21,7 @@ use vek::*;
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Read<'a, UidAllocator>,
|
||||
Entities<'a>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
Read<'a, EventBus<LocalEvent>>,
|
||||
@ -31,6 +36,7 @@ impl<'a> System<'a> for Sys {
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
uid_allocator,
|
||||
entities,
|
||||
server_bus,
|
||||
local_bus,
|
||||
@ -96,6 +102,20 @@ impl<'a> System<'a> for Sys {
|
||||
character.movement = Jump;
|
||||
}
|
||||
|
||||
// Sit
|
||||
if controller.sit
|
||||
&& physics.on_ground
|
||||
&& character.action == Idle
|
||||
&& character.movement != Sit
|
||||
&& body.is_humanoid()
|
||||
{
|
||||
character.movement = Sit;
|
||||
} else if character.movement == Sit
|
||||
&& (controller.move_dir.magnitude_squared() > 0.0 || !physics.on_ground)
|
||||
{
|
||||
character.movement = Run;
|
||||
}
|
||||
|
||||
// Wield
|
||||
if controller.primary
|
||||
&& character.action == Idle
|
||||
@ -180,9 +200,34 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
// Jump
|
||||
if controller.jump && physics.on_ground && vel.0.z <= 0.0 {
|
||||
if controller.jump
|
||||
&& physics.on_ground
|
||||
&& vel.0.z <= 0.0
|
||||
&& !character.movement.is_roll()
|
||||
{
|
||||
local_emitter.emit(LocalEvent::Jump(entity));
|
||||
}
|
||||
|
||||
// Wall leap
|
||||
if controller.wall_leap {
|
||||
if let (Some(_wall_dir), Climb) = (physics.on_wall, character.movement) {
|
||||
//local_emitter.emit(LocalEvent::WallLeap { entity, wall_dir });
|
||||
}
|
||||
}
|
||||
|
||||
// Process controller events
|
||||
for event in std::mem::replace(&mut controller.events, Vec::new()) {
|
||||
match event {
|
||||
ControlEvent::Mount(mountee_uid) => {
|
||||
if let Some(mountee_entity) =
|
||||
uid_allocator.retrieve_entity_internal(mountee_uid.id())
|
||||
{
|
||||
server_emitter.emit(ServerEvent::Mount(entity, mountee_entity));
|
||||
}
|
||||
}
|
||||
ControlEvent::Unmount => server_emitter.emit(ServerEvent::Unmount(entity)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,13 @@ const CLEANUP_SYS: &str = "cleanup_sys";
|
||||
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
|
||||
dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[AGENT_SYS]);
|
||||
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS]);
|
||||
dispatch_builder.add(movement::Sys, MOVEMENT_SYS, &[PHYS_SYS]);
|
||||
dispatch_builder.add(movement::Sys, MOVEMENT_SYS, &[]);
|
||||
dispatch_builder.add(combat::Sys, COMBAT_SYS, &[CONTROLLER_SYS]);
|
||||
dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]);
|
||||
dispatch_builder.add(cleanup::Sys, CLEANUP_SYS, &[STATS_SYS, MOVEMENT_SYS]);
|
||||
dispatch_builder.add(
|
||||
phys::Sys,
|
||||
PHYS_SYS,
|
||||
&[CONTROLLER_SYS, MOVEMENT_SYS, COMBAT_SYS, STATS_SYS],
|
||||
);
|
||||
dispatch_builder.add(cleanup::Sys, CLEANUP_SYS, &[PHYS_SYS]);
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
use super::phys::GRAVITY;
|
||||
use crate::{
|
||||
comp::{
|
||||
ActionState::*, CharacterState, Controller, MovementState::*, Ori, PhysicsState, Pos,
|
||||
Stats, Vel,
|
||||
ActionState::*, CharacterState, Controller, Mounting, MovementState::*, Ori, PhysicsState,
|
||||
Pos, Stats, Vel,
|
||||
},
|
||||
state::DeltaTime,
|
||||
terrain::TerrainGrid,
|
||||
};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use specs::prelude::*;
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
|
||||
@ -16,13 +17,17 @@ const HUMANOID_ACCEL: f32 = 70.0;
|
||||
const HUMANOID_SPEED: f32 = 120.0;
|
||||
const HUMANOID_AIR_ACCEL: f32 = 10.0;
|
||||
const HUMANOID_AIR_SPEED: f32 = 100.0;
|
||||
const HUMANOID_WATER_ACCEL: f32 = 70.0;
|
||||
const HUMANOID_WATER_SPEED: f32 = 120.0;
|
||||
const HUMANOID_CLIMB_ACCEL: f32 = 5.0;
|
||||
const ROLL_SPEED: f32 = 13.0;
|
||||
const GLIDE_ACCEL: f32 = 15.0;
|
||||
const GLIDE_SPEED: f32 = 45.0;
|
||||
const BLOCK_ACCEL: f32 = 30.0;
|
||||
const BLOCK_SPEED: f32 = 75.0;
|
||||
// Gravity is 9.81 * 4, so this makes gravity equal to .15
|
||||
const GLIDE_ANTIGRAV: f32 = 9.81 * 3.95;
|
||||
const GLIDE_ANTIGRAV: f32 = GRAVITY * 0.96;
|
||||
const CLIMB_SPEED: f32 = 5.0;
|
||||
|
||||
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
|
||||
|
||||
@ -30,6 +35,7 @@ pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, Stats>,
|
||||
@ -39,11 +45,13 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Pos>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, Ori>,
|
||||
ReadStorage<'a, Mounting>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
_terrain,
|
||||
dt,
|
||||
stats,
|
||||
@ -53,10 +61,22 @@ impl<'a> System<'a> for Sys {
|
||||
mut positions,
|
||||
mut velocities,
|
||||
mut orientations,
|
||||
mountings,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
// Apply movement inputs
|
||||
for (stats, controller, physics, mut character, mut _pos, mut vel, mut ori) in (
|
||||
for (
|
||||
_entity,
|
||||
stats,
|
||||
controller,
|
||||
physics,
|
||||
mut character,
|
||||
mut _pos,
|
||||
mut vel,
|
||||
mut ori,
|
||||
mounting,
|
||||
) in (
|
||||
&entities,
|
||||
&stats,
|
||||
&controllers,
|
||||
&physics_states,
|
||||
@ -64,6 +84,7 @@ impl<'a> System<'a> for Sys {
|
||||
&mut positions,
|
||||
&mut velocities,
|
||||
&mut orientations,
|
||||
mountings.maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -71,6 +92,11 @@ impl<'a> System<'a> for Sys {
|
||||
continue;
|
||||
}
|
||||
|
||||
if mounting.is_some() {
|
||||
character.movement = Sit;
|
||||
continue;
|
||||
}
|
||||
|
||||
if character.movement.is_roll() {
|
||||
vel.0 = Vec3::new(0.0, 0.0, vel.0.z)
|
||||
+ controller
|
||||
@ -94,6 +120,9 @@ impl<'a> System<'a> for Sys {
|
||||
(true, Run) if vel.0.magnitude_squared() < HUMANOID_SPEED.powf(2.0) => {
|
||||
HUMANOID_ACCEL
|
||||
}
|
||||
(false, Climb) if vel.0.magnitude_squared() < HUMANOID_SPEED.powf(2.0) => {
|
||||
HUMANOID_CLIMB_ACCEL
|
||||
}
|
||||
(false, Glide) if vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) => {
|
||||
GLIDE_ACCEL
|
||||
}
|
||||
@ -102,6 +131,11 @@ impl<'a> System<'a> for Sys {
|
||||
{
|
||||
HUMANOID_AIR_ACCEL
|
||||
}
|
||||
(false, Swim)
|
||||
if vel.0.magnitude_squared() < HUMANOID_WATER_SPEED.powf(2.0) =>
|
||||
{
|
||||
HUMANOID_WATER_ACCEL
|
||||
}
|
||||
_ => 0.0,
|
||||
};
|
||||
}
|
||||
@ -112,6 +146,12 @@ impl<'a> System<'a> for Sys {
|
||||
|| character.action.is_block()
|
||||
{
|
||||
Vec2::from(controller.look_dir).normalized()
|
||||
} else if let (Climb, Some(wall_dir)) = (character.movement, physics.on_wall) {
|
||||
if Vec2::<f32>::from(wall_dir).magnitude_squared() > 0.001 {
|
||||
Vec2::from(wall_dir).normalized()
|
||||
} else {
|
||||
Vec2::from(vel.0)
|
||||
}
|
||||
} else {
|
||||
Vec2::from(vel.0)
|
||||
};
|
||||
@ -129,12 +169,16 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// Glide
|
||||
if character.movement == Glide
|
||||
&& vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0)
|
||||
&& Vec2::<f32>::from(vel.0).magnitude_squared() < GLIDE_SPEED.powf(2.0)
|
||||
&& vel.0.z < 0.0
|
||||
{
|
||||
character.action = Idle;
|
||||
let lift = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2;
|
||||
vel.0.z += dt.0 * lift * Vec2::<f32>::from(vel.0 * 0.15).magnitude().min(1.0);
|
||||
let lift = GLIDE_ANTIGRAV + vel.0.z.abs().powf(2.0) * 0.15;
|
||||
vel.0.z += dt.0
|
||||
* lift
|
||||
* (Vec2::<f32>::from(vel.0).magnitude() * 0.075)
|
||||
.min(1.0)
|
||||
.max(0.2);
|
||||
}
|
||||
|
||||
// Roll
|
||||
@ -149,7 +193,36 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
|
||||
if physics.on_ground && (character.movement == Jump || character.movement == Glide) {
|
||||
// Climb
|
||||
if let (true, Some(_wall_dir)) = (
|
||||
(controller.climb | controller.climb_down) && vel.0.z <= CLIMB_SPEED,
|
||||
physics.on_wall,
|
||||
) {
|
||||
if controller.climb_down && !controller.climb {
|
||||
vel.0 -= dt.0 * vel.0.map(|e| e.abs().powf(1.5) * e.signum() * 6.0);
|
||||
} else if controller.climb && !controller.climb_down {
|
||||
vel.0.z = (vel.0.z + dt.0 * GRAVITY * 1.25).min(CLIMB_SPEED);
|
||||
} else {
|
||||
vel.0.z = vel.0.z + dt.0 * GRAVITY * 1.5;
|
||||
vel.0 = Lerp::lerp(
|
||||
vel.0,
|
||||
Vec3::zero(),
|
||||
30.0 * dt.0 / (1.0 - vel.0.z.min(0.0) * 5.0),
|
||||
);
|
||||
}
|
||||
|
||||
character.movement = Climb;
|
||||
character.action = Idle;
|
||||
} else if let Climb = character.movement {
|
||||
character.movement = Jump;
|
||||
}
|
||||
|
||||
if physics.on_ground
|
||||
&& (character.movement == Jump
|
||||
|| character.movement == Climb
|
||||
|| character.movement == Glide
|
||||
|| character.movement == Swim)
|
||||
{
|
||||
character.movement = Stand;
|
||||
}
|
||||
|
||||
@ -160,6 +233,12 @@ impl<'a> System<'a> for Sys {
|
||||
{
|
||||
character.movement = Jump;
|
||||
}
|
||||
|
||||
if !physics.on_ground && physics.in_fluid {
|
||||
character.movement = Swim;
|
||||
} else if let Swim = character.movement {
|
||||
character.movement = Stand;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
use {
|
||||
crate::{
|
||||
comp::{Body, Ori, PhysicsState, Pos, Scale, Vel},
|
||||
comp::{Body, Mounting, Ori, PhysicsState, Pos, Scale, Vel},
|
||||
event::{EventBus, LocalEvent},
|
||||
state::DeltaTime,
|
||||
terrain::TerrainGrid,
|
||||
terrain::{Block, TerrainGrid},
|
||||
vol::ReadVol,
|
||||
},
|
||||
specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage},
|
||||
vek::*,
|
||||
};
|
||||
|
||||
const GRAVITY: f32 = 9.81 * 4.0;
|
||||
|
||||
pub const GRAVITY: f32 = 9.81 * 4.0;
|
||||
const BOUYANCY: f32 = 0.0;
|
||||
// Friction values used for linear damping. They are unitless quantities. The
|
||||
// value of these quantities must be between zero and one. They represent the
|
||||
// amount an object will slow down within 1/60th of a second. Eg. if the frction
|
||||
@ -19,6 +19,7 @@ const GRAVITY: f32 = 9.81 * 4.0;
|
||||
// be 0.99. after 1 second the speed will be 0.54, which is 0.99 ^ 60.
|
||||
const FRIC_GROUND: f32 = 0.125;
|
||||
const FRIC_AIR: f32 = 0.0125;
|
||||
const FRIC_FLUID: f32 = 0.2;
|
||||
|
||||
// Integrates forces, calculates the new velocity based off of the old velocity
|
||||
// dt = delta time
|
||||
@ -29,11 +30,7 @@ fn integrate_forces(dt: f32, mut lv: Vec3<f32>, grav: f32, damp: f32) -> Vec3<f3
|
||||
// this is not linear damping, because it is proportional to the original
|
||||
// velocity this "linear" damping in in fact, quite exponential. and thus
|
||||
// must be interpolated accordingly
|
||||
let linear_damp = if damp < 1.0 {
|
||||
(1.0 - damp).powf(dt * 60.0)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let linear_damp = (1.0 - damp.min(1.0)).powf(dt * 60.0);
|
||||
|
||||
lv.z = (lv.z - grav * dt).max(-50.0);
|
||||
lv * linear_damp
|
||||
@ -53,6 +50,7 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Pos>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, Ori>,
|
||||
ReadStorage<'a, Mounting>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
@ -68,18 +66,20 @@ impl<'a> System<'a> for Sys {
|
||||
mut positions,
|
||||
mut velocities,
|
||||
mut orientations,
|
||||
mountings,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let mut event_emitter = event_bus.emitter();
|
||||
|
||||
// Apply movement inputs
|
||||
for (entity, scale, _, mut pos, mut vel, mut _ori) in (
|
||||
for (entity, scale, _b, mut pos, mut vel, _ori, _) in (
|
||||
&entities,
|
||||
scales.maybe(),
|
||||
&bodies,
|
||||
&mut positions,
|
||||
&mut velocities,
|
||||
&mut orientations,
|
||||
!&mountings,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -102,12 +102,23 @@ impl<'a> System<'a> for Sys {
|
||||
let old_vel = *vel;
|
||||
// Integrate forces
|
||||
// Friction is assumed to be a constant dependent on location
|
||||
let friction = if physics_state.on_ground {
|
||||
FRIC_GROUND
|
||||
let friction = FRIC_AIR
|
||||
.max(if physics_state.on_ground {
|
||||
FRIC_GROUND
|
||||
} else {
|
||||
0.0
|
||||
})
|
||||
.max(if physics_state.in_fluid {
|
||||
FRIC_FLUID
|
||||
} else {
|
||||
0.0
|
||||
});
|
||||
let downward_force = if physics_state.in_fluid {
|
||||
(1.0 - BOUYANCY) * GRAVITY
|
||||
} else {
|
||||
FRIC_AIR
|
||||
GRAVITY
|
||||
};
|
||||
vel.0 = integrate_forces(dt.0, vel.0, GRAVITY, friction);
|
||||
vel.0 = integrate_forces(dt.0, vel.0, downward_force, friction);
|
||||
|
||||
// Don't move if we're not in a loaded chunk
|
||||
let pos_delta = if terrain
|
||||
@ -122,15 +133,11 @@ impl<'a> System<'a> for Sys {
|
||||
};
|
||||
|
||||
// Function for determining whether the player at a specific position collides with the ground
|
||||
let collision_with = |pos: Vec3<f32>, near_iter| {
|
||||
let collision_with = |pos: Vec3<f32>, hit: fn(&Block) -> bool, near_iter| {
|
||||
for (i, j, k) in near_iter {
|
||||
let block_pos = pos.map(|e| e.floor() as i32) + Vec3::new(i, j, k);
|
||||
|
||||
if terrain
|
||||
.get(block_pos)
|
||||
.map(|vox| vox.is_solid())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
if terrain.get(block_pos).map(hit).unwrap_or(false) {
|
||||
let player_aabb = Aabb {
|
||||
min: pos + Vec3::new(-player_rad, -player_rad, 0.0),
|
||||
max: pos + Vec3::new(player_rad, player_rad, player_height),
|
||||
@ -165,7 +172,9 @@ impl<'a> System<'a> for Sys {
|
||||
const MAX_ATTEMPTS: usize = 16;
|
||||
|
||||
// While the player is colliding with the terrain...
|
||||
while collision_with(pos.0, near_iter.clone()) && attempts < MAX_ATTEMPTS {
|
||||
while collision_with(pos.0, |vox| vox.is_solid(), near_iter.clone())
|
||||
&& attempts < MAX_ATTEMPTS
|
||||
{
|
||||
// Calculate the player's AABB
|
||||
let player_aabb = Aabb {
|
||||
min: pos.0 + Vec3::new(-player_rad, -player_rad, 0.0),
|
||||
@ -187,8 +196,6 @@ impl<'a> System<'a> for Sys {
|
||||
},
|
||||
)
|
||||
})
|
||||
// Determine whether the block's AABB collides with the player's AABB
|
||||
.filter(|(_, block_aabb)| block_aabb.collides_with_aabb(player_aabb))
|
||||
// Make sure the block is actually solid
|
||||
.filter(|(block_pos, _)| {
|
||||
terrain
|
||||
@ -196,13 +203,13 @@ impl<'a> System<'a> for Sys {
|
||||
.map(|vox| vox.is_solid())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
// Determine whether the block's AABB collides with the player's AABB
|
||||
.filter(|(_, block_aabb)| block_aabb.collides_with_aabb(player_aabb))
|
||||
// Find the maximum of the minimum collision axes (this bit is weird, trust me that it works)
|
||||
.max_by_key(|(_, block_aabb)| {
|
||||
((player_aabb
|
||||
.collision_vector_with_aabb(*block_aabb)
|
||||
.min_by_key(|(_, block_aabb)| {
|
||||
((block_aabb.center() - player_aabb.center() - Vec3::unit_z() * 0.5)
|
||||
.map(|e| e.abs())
|
||||
.product()
|
||||
+ block_aabb.min.z)
|
||||
.sum()
|
||||
* 1_000_000.0) as i32
|
||||
})
|
||||
.expect("Collision detected, but no colliding blocks found!");
|
||||
@ -231,7 +238,7 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// When the resolution direction is non-vertical, we must be colliding with a wall
|
||||
// If the space above is free...
|
||||
if !collision_with(Vec3::new(pos.0.x, pos.0.y, (pos.0.z + 0.1).ceil()), near_iter.clone())
|
||||
if !collision_with(Vec3::new(pos.0.x, pos.0.y, (pos.0.z + 0.1).ceil()), |vox| vox.is_solid(), near_iter.clone())
|
||||
// ...and we're being pushed out horizontally...
|
||||
&& resolve_dir.z == 0.0
|
||||
// ...and the vertical resolution direction is sufficiently great...
|
||||
@ -244,6 +251,7 @@ impl<'a> System<'a> for Sys {
|
||||
// ...and there is a collision with a block beneath our current hitbox...
|
||||
&& collision_with(
|
||||
old_pos + resolve_dir - Vec3::unit_z() * 1.05,
|
||||
|vox| vox.is_solid(),
|
||||
near_iter.clone(),
|
||||
)
|
||||
{
|
||||
@ -274,8 +282,11 @@ impl<'a> System<'a> for Sys {
|
||||
if on_ground {
|
||||
physics_state.on_ground = true;
|
||||
// If the space below us is free, then "snap" to the ground
|
||||
} else if collision_with(pos.0 - Vec3::unit_z() * 1.05, near_iter.clone())
|
||||
&& vel.0.z < 0.0
|
||||
} else if collision_with(
|
||||
pos.0 - Vec3::unit_z() * 1.05,
|
||||
|vox| vox.is_solid(),
|
||||
near_iter.clone(),
|
||||
) && vel.0.z < 0.0
|
||||
&& vel.0.z > -1.5
|
||||
&& was_on_ground
|
||||
{
|
||||
@ -283,13 +294,45 @@ impl<'a> System<'a> for Sys {
|
||||
physics_state.on_ground = true;
|
||||
}
|
||||
|
||||
let dirs = [
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
-Vec3::unit_x(),
|
||||
-Vec3::unit_y(),
|
||||
];
|
||||
|
||||
if let (wall_dir, true) = dirs.iter().fold((Vec3::zero(), false), |(a, hit), dir| {
|
||||
if collision_with(pos.0 + *dir * 0.01, |vox| vox.is_solid(), near_iter.clone()) {
|
||||
(a + dir, true)
|
||||
} else {
|
||||
(a, hit)
|
||||
}
|
||||
}) {
|
||||
physics_state.on_wall = Some(wall_dir);
|
||||
} else {
|
||||
physics_state.on_wall = None;
|
||||
}
|
||||
|
||||
// Figure out if we're in water
|
||||
physics_state.in_fluid = collision_with(pos.0, |vox| vox.is_fluid(), near_iter.clone());
|
||||
|
||||
let _ = physics_states.insert(entity, physics_state);
|
||||
}
|
||||
|
||||
// Apply pushback
|
||||
for (pos, scale, vel, _) in (&positions, scales.maybe(), &mut velocities, &bodies).join() {
|
||||
for (pos, scale, vel, _, _) in (
|
||||
&positions,
|
||||
scales.maybe(),
|
||||
&mut velocities,
|
||||
&bodies,
|
||||
!&mountings,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let scale = scale.map(|s| s.0).unwrap_or(1.0);
|
||||
for (pos_other, scale_other, _) in (&positions, scales.maybe(), &bodies).join() {
|
||||
for (pos_other, scale_other, _, _) in
|
||||
(&positions, scales.maybe(), &bodies, !&mountings).join()
|
||||
{
|
||||
let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0);
|
||||
let diff = Vec2::<f32>::from(pos.0 - pos_other.0);
|
||||
|
||||
|
@ -414,6 +414,7 @@ fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &C
|
||||
server
|
||||
.create_npc(pos, comp::Stats::new(get_npc_name(id), None), body)
|
||||
.with(comp::Vel(vel))
|
||||
.with(comp::MountState::Unmounted)
|
||||
.with(agent)
|
||||
.build();
|
||||
}
|
||||
|
@ -363,6 +363,53 @@ impl Server {
|
||||
.insert(entity, comp::ForceUpdate);
|
||||
}
|
||||
}
|
||||
ServerEvent::Mount(mounter, mountee) => {
|
||||
if state
|
||||
.ecs()
|
||||
.read_storage::<comp::Mounting>()
|
||||
.get(mounter)
|
||||
.is_none()
|
||||
{
|
||||
let not_mounting_yet = if let Some(comp::MountState::Unmounted) = state
|
||||
.ecs()
|
||||
.write_storage::<comp::MountState>()
|
||||
.get_mut(mountee)
|
||||
.cloned()
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if not_mounting_yet {
|
||||
if let (Some(mounter_uid), Some(mountee_uid)) = (
|
||||
state.ecs().uid_from_entity(mounter),
|
||||
state.ecs().uid_from_entity(mountee),
|
||||
) {
|
||||
state.write_component(
|
||||
mountee,
|
||||
comp::MountState::MountedBy(mounter_uid.into()),
|
||||
);
|
||||
state.write_component(mounter, comp::Mounting(mountee_uid.into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ServerEvent::Unmount(mounter) => {
|
||||
let mountee_entity = state
|
||||
.ecs()
|
||||
.write_storage::<comp::Mounting>()
|
||||
.get(mounter)
|
||||
.and_then(|mountee| state.ecs().entity_from_uid(mountee.0.into()));
|
||||
if let Some(mountee_entity) = mountee_entity {
|
||||
state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::MountState>()
|
||||
.get_mut(mountee_entity)
|
||||
.map(|ms| *ms = comp::MountState::Unmounted);
|
||||
}
|
||||
state.delete_component::<comp::Mounting>(mounter);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(entity) = todo_remove {
|
||||
|
@ -18,6 +18,7 @@ impl Animation for AttackAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
_global_time: f64,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -19,6 +19,7 @@ impl Animation for BlockAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: f64,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -19,6 +19,7 @@ impl Animation for BlockIdleAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: f64,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -19,6 +19,7 @@ impl Animation for CidleAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: f64,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
108
voxygen/src/anim/character/climb.rs
Normal file
108
voxygen/src/anim/character/climb.rs
Normal file
@ -0,0 +1,108 @@
|
||||
use super::{
|
||||
super::{Animation, SkeletonAttr},
|
||||
CharacterSkeleton,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
pub struct ClimbAnimation;
|
||||
|
||||
impl Animation for ClimbAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = (Vec3<f32>, Vec3<f32>, f64);
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
(velocity, _orientation, _global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let speed = velocity.magnitude();
|
||||
*rate = speed;
|
||||
|
||||
let constant = 1.0;
|
||||
let wave = (anim_time as f32 * constant as f32 * 1.5).sin();
|
||||
let wave_cos = (anim_time as f32 * constant as f32 * 1.5).cos();
|
||||
|
||||
let wave_test = (((5.0)
|
||||
/ (0.6 + 4.0 * ((anim_time as f32 * constant as f32 * 1.5).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * constant as f32 * 1.5).sin());
|
||||
let wave_testc = (((5.0)
|
||||
/ (0.6 + 4.0 * ((anim_time as f32 * constant as f32 * 1.5).cos()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * constant as f32 * 1.5).cos());
|
||||
|
||||
next.head.offset = Vec3::new(
|
||||
0.0,
|
||||
1.0 + skeleton_attr.neck_forward,
|
||||
skeleton_attr.neck_height + 13.5 + wave_cos * 1.3,
|
||||
);
|
||||
next.head.ori = Quaternion::rotation_z(wave * 0.1)
|
||||
* Quaternion::rotation_x(0.6)
|
||||
* Quaternion::rotation_y(wave_test * 0.1);
|
||||
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
|
||||
|
||||
next.chest.offset = Vec3::new(0.0, 1.0, 5.0 + wave_cos * 1.1);
|
||||
next.chest.ori = Quaternion::rotation_z(wave_test * 0.25)
|
||||
* Quaternion::rotation_x(-0.15)
|
||||
* Quaternion::rotation_y(wave_test * -0.12);
|
||||
next.chest.scale = Vec3::one();
|
||||
|
||||
next.belt.offset = Vec3::new(0.0, 1.0, 3.5 + wave_cos * 1.1);
|
||||
next.belt.ori = Quaternion::rotation_z(wave_test * 0.25) * Quaternion::rotation_x(0.0);
|
||||
next.belt.scale = Vec3::one();
|
||||
|
||||
next.shorts.offset = Vec3::new(0.0, 1.0, 1.0 + wave_cos * 1.1);
|
||||
next.shorts.ori = Quaternion::rotation_z(wave_test * 0.25)
|
||||
* Quaternion::rotation_x(0.1)
|
||||
* Quaternion::rotation_y(wave_test * 0.10);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
next.l_hand.offset = Vec3::new(-8.5, 3.0 + wave_testc * 1.5, 6.0 - wave_test * 4.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(0.2 + wave_testc * 0.5);
|
||||
next.l_hand.scale = Vec3::one();
|
||||
|
||||
next.r_hand.offset = Vec3::new(8.5, 3.0 - wave_test * 1.5, 6.0 + wave_test * 4.0);
|
||||
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.2 - wave_testc * 0.5);
|
||||
next.r_hand.scale = Vec3::one();
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, 1.0, 6.0 + wave_test * 2.5);
|
||||
next.l_foot.ori = Quaternion::rotation_x(0.2 - wave_testc * 0.50);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, 1.0, 6.0 - wave_test * 2.5);
|
||||
next.r_foot.ori = Quaternion::rotation_x(0.2 + wave_testc * 0.50);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.weapon.offset = Vec3::new(
|
||||
-7.0 + skeleton_attr.weapon_x,
|
||||
-5.0 + skeleton_attr.weapon_y,
|
||||
15.0,
|
||||
);
|
||||
next.weapon.ori =
|
||||
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + wave_cos * 0.25);
|
||||
next.weapon.scale = Vec3::one();
|
||||
|
||||
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
|
||||
next.l_shoulder.ori = Quaternion::rotation_x(wave_cos * 0.15);
|
||||
next.l_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.r_shoulder.offset = Vec3::new(5.0, 0.0, 4.7);
|
||||
next.r_shoulder.ori = Quaternion::rotation_x(wave * 0.15);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.draw.offset = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.draw.ori = Quaternion::rotation_y(0.0);
|
||||
next.draw.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, -0.2 + wave * -0.08, 0.4) * skeleton_attr.scaler;
|
||||
next.torso.ori = Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
|
||||
next
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ impl Animation for WieldAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
(velocity, global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -9,15 +9,19 @@ pub struct GlidingAnimation;
|
||||
|
||||
impl Animation for GlidingAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = (f32, f64);
|
||||
type Dependency = (Vec3<f32>, Vec3<f32>, Vec3<f32>, f64);
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
(velocity, global_time): Self::Dependency,
|
||||
(velocity, orientation, last_ori, global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let speed = Vec2::<f32>::from(velocity).magnitude();
|
||||
|
||||
let wave_slow = (anim_time as f32 * 7.0).sin();
|
||||
let wave_slow_cos = (anim_time as f32 * 7.0).cos();
|
||||
let wave_stop = (anim_time as f32 * 1.5).min(PI / 2.0).sin();
|
||||
@ -37,6 +41,22 @@ impl Animation for GlidingAnimation {
|
||||
.sin()
|
||||
* 0.25,
|
||||
);
|
||||
|
||||
let ori = Vec2::from(orientation);
|
||||
let last_ori = Vec2::from(last_ori);
|
||||
|
||||
let tilt = if Vec2::new(ori, last_ori)
|
||||
.map(|o| Vec2::<f32>::from(o).magnitude_squared())
|
||||
.map(|m| m > 0.001 && m.is_finite())
|
||||
.reduce_and()
|
||||
&& ori.angle_between(last_ori).is_finite()
|
||||
{
|
||||
ori.angle_between(last_ori).min(0.15)
|
||||
* last_ori.determine_side(Vec2::zero(), ori).signum()
|
||||
} else {
|
||||
0.0
|
||||
} * 0.8;
|
||||
|
||||
next.head.offset = Vec3::new(
|
||||
0.0 + skeleton_attr.neck_right,
|
||||
0.0 + skeleton_attr.neck_forward,
|
||||
@ -76,14 +96,14 @@ impl Animation for GlidingAnimation {
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, 1.0, -2.0);
|
||||
next.l_foot.ori = Quaternion::rotation_x(
|
||||
(wave_stop * -0.7 - wave_slow_cos * -0.21 + wave_very_slow * 0.19) * velocity * 0.04,
|
||||
(wave_stop * -0.7 - wave_slow_cos * -0.21 + wave_very_slow * 0.19) * speed * 0.04,
|
||||
);
|
||||
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, 1.0, -2.0);
|
||||
next.r_foot.ori = Quaternion::rotation_x(
|
||||
(wave_stop * -0.8 + wave_slow * -0.25 + wave_very_slow_alt * 0.13) * velocity * 0.04,
|
||||
(wave_stop * -0.8 + wave_slow * -0.25 + wave_very_slow_alt * 0.13) * speed * 0.04,
|
||||
);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
@ -104,12 +124,13 @@ impl Animation for GlidingAnimation {
|
||||
next.r_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.draw.offset = Vec3::new(0.0, -13.0 + wave_very_slow * 0.10, 6.0);
|
||||
next.draw.ori = Quaternion::rotation_x(1.0)//0.95 - wave_very_slow * 0.08)
|
||||
* Quaternion::rotation_y(wave_very_slow_cos * 0.04);
|
||||
next.draw.ori =
|
||||
Quaternion::rotation_x(1.0) * Quaternion::rotation_y(wave_very_slow_cos * 0.04);
|
||||
next.draw.scale = Vec3::one();
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, 6.0, 15.0) / 11.0 * skeleton_attr.scaler;
|
||||
next.torso.ori = Quaternion::rotation_x(-0.05 * velocity + wave_very_slow * 0.10);
|
||||
next.torso.ori = Quaternion::rotation_x(-0.05 * speed.max(12.0) + wave_very_slow * 0.10)
|
||||
* Quaternion::rotation_y(tilt * 16.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
|
||||
next
|
||||
|
@ -18,6 +18,7 @@ impl Animation for IdleAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: f64,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -15,6 +15,7 @@ impl Animation for JumpAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
_global_time: f64,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -2,12 +2,15 @@ pub mod attack;
|
||||
pub mod block;
|
||||
pub mod blockidle;
|
||||
pub mod cidle;
|
||||
pub mod climb;
|
||||
pub mod gliding;
|
||||
pub mod idle;
|
||||
pub mod jump;
|
||||
pub mod roll;
|
||||
pub mod run;
|
||||
pub mod sit;
|
||||
pub mod stand;
|
||||
pub mod swim;
|
||||
pub mod wield;
|
||||
|
||||
// Reexports
|
||||
@ -15,12 +18,15 @@ pub use self::attack::AttackAnimation;
|
||||
pub use self::block::BlockAnimation;
|
||||
pub use self::blockidle::BlockIdleAnimation;
|
||||
pub use self::cidle::CidleAnimation;
|
||||
pub use self::climb::ClimbAnimation;
|
||||
pub use self::gliding::GlidingAnimation;
|
||||
pub use self::idle::IdleAnimation;
|
||||
pub use self::jump::JumpAnimation;
|
||||
pub use self::roll::RollAnimation;
|
||||
pub use self::run::RunAnimation;
|
||||
pub use self::sit::SitAnimation;
|
||||
pub use self::stand::StandAnimation;
|
||||
pub use self::swim::SwimAnimation;
|
||||
pub use self::wield::WieldAnimation;
|
||||
|
||||
use super::{Bone, Skeleton};
|
||||
|
@ -15,6 +15,7 @@ impl Animation for RollAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
_global_time: f64,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -10,21 +10,35 @@ pub struct RunAnimation;
|
||||
|
||||
impl Animation for RunAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = (f32, f32, f64);
|
||||
type Dependency = (Vec3<f32>, Vec3<f32>, Vec3<f32>, f64);
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
(velocity, orientation, global_time): Self::Dependency,
|
||||
(velocity, orientation, last_ori, global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave = (anim_time as f32 * velocity * 1.2).sin();
|
||||
let wave_cos = (anim_time as f32 * velocity * 1.2).cos();
|
||||
let speed = Vec2::<f32>::from(velocity).magnitude();
|
||||
*rate = speed;
|
||||
|
||||
let wave_diff = (anim_time as f32 * velocity * 0.6).sin();
|
||||
let wave_cos_dub = (anim_time as f32 * velocity * 2.4).cos();
|
||||
let constant = 1.0;
|
||||
let wave = (((5.0)
|
||||
/ (1.1 + 3.9 * ((anim_time as f32 * constant as f32 * 1.2).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * constant as f32 * 1.2).sin());
|
||||
let wave_cos = (((5.0)
|
||||
/ (1.1 + 3.9 * ((anim_time as f32 * constant as f32 * 2.4).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * constant as f32 * 1.5).sin());
|
||||
let wave_cos_dub = (((5.0)
|
||||
/ (1.1 + 3.9 * ((anim_time as f32 * constant as f32 * 1.5).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * constant as f32 * 1.5).sin());
|
||||
|
||||
let wave_diff = (anim_time as f32 * 0.6).sin();
|
||||
let wave_stop = (anim_time as f32 * 2.6).min(PI / 2.0).sin();
|
||||
let head_look = Vec2::new(
|
||||
((global_time + anim_time) as f32 / 2.0)
|
||||
@ -39,18 +53,20 @@ impl Animation for RunAnimation {
|
||||
* 0.1,
|
||||
);
|
||||
|
||||
let vel = Vec2::from(velocity);
|
||||
let ori = (Vec2::from(orientation)).normalized();
|
||||
let ori = Vec2::from(orientation);
|
||||
let last_ori = Vec2::from(last_ori);
|
||||
|
||||
let _tilt = if Vec2::new(ori, vel)
|
||||
.map(|v| Vec2::<f32>::from(v).magnitude_squared())
|
||||
.reduce_partial_min()
|
||||
> 0.001
|
||||
let tilt = if Vec2::new(ori, last_ori)
|
||||
.map(|o| Vec2::<f32>::from(o).magnitude_squared())
|
||||
.map(|m| m > 0.001 && m.is_finite())
|
||||
.reduce_and()
|
||||
&& ori.angle_between(last_ori).is_finite()
|
||||
{
|
||||
vel.normalized().dot(ori.normalized()).min(1.0).acos()
|
||||
ori.angle_between(last_ori).min(0.5)
|
||||
* last_ori.determine_side(Vec2::zero(), ori).signum()
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
} * 1.3;
|
||||
|
||||
next.head.offset = Vec3::new(
|
||||
0.0,
|
||||
@ -90,11 +106,11 @@ impl Animation for RunAnimation {
|
||||
next.r_hand.scale = Vec3::one();
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave_cos * 1.0, 6.0 - wave_cos_dub * 0.7);
|
||||
next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave_cos * 1.5);
|
||||
next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave_cos * 1.2);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, 0.0 - wave_cos * 1.0, 6.0 - wave_cos_dub * 0.7);
|
||||
next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.5);
|
||||
next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.2);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.weapon.offset = Vec3::new(
|
||||
@ -120,8 +136,8 @@ impl Animation for RunAnimation {
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, -0.2 + wave * -0.08, 0.4) * skeleton_attr.scaler;
|
||||
next.torso.ori =
|
||||
Quaternion::rotation_x(wave_stop * velocity * -0.06 + wave_diff * velocity * -0.005)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
Quaternion::rotation_x(wave_stop * speed * -0.06 + wave_diff * speed * -0.005)
|
||||
* Quaternion::rotation_y(tilt);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
|
||||
next
|
||||
|
125
voxygen/src/anim/character/sit.rs
Normal file
125
voxygen/src/anim/character/sit.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use super::{
|
||||
super::{Animation, SkeletonAttr},
|
||||
CharacterSkeleton,
|
||||
};
|
||||
use std::{f32::consts::PI, ops::Mul};
|
||||
use vek::*;
|
||||
|
||||
pub struct SitAnimation;
|
||||
|
||||
impl Animation for SitAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = f64;
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: f64,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave_slow = (anim_time as f32 * 1.0 + PI).sin();
|
||||
let wave_slow_cos = (anim_time as f32 * 1.0 + PI).cos();
|
||||
let wave_stop = (anim_time as f32 * 3.0).min(PI / 2.0).sin();
|
||||
let wave_slow_abs = ((anim_time as f32 * 0.5 + PI).sin()) + 1.0;
|
||||
let wave_ultra_slow = (anim_time as f32 * 0.3 + PI).sin();
|
||||
let wave_ultra_slow_cos = (anim_time as f32 * 0.3 + PI).cos();
|
||||
|
||||
let head_look = Vec2::new(
|
||||
((global_time + anim_time) as f32 / 18.0)
|
||||
.floor()
|
||||
.mul(7331.0)
|
||||
.sin()
|
||||
* 0.25,
|
||||
((global_time + anim_time) as f32 / 18.0)
|
||||
.floor()
|
||||
.mul(1337.0)
|
||||
.sin()
|
||||
* 0.125,
|
||||
);
|
||||
next.head.offset = Vec3::new(
|
||||
0.0 + skeleton_attr.neck_right,
|
||||
wave_stop * -1.6 + skeleton_attr.neck_forward,
|
||||
skeleton_attr.neck_height + 15.0 + wave_slow * 0.1 + wave_stop * -0.8,
|
||||
);
|
||||
next.head.ori =
|
||||
Quaternion::rotation_z(head_look.x + wave_ultra_slow * 0.2 - wave_slow * 0.1)
|
||||
* Quaternion::rotation_x(
|
||||
(wave_ultra_slow_cos * -0.2 + wave_slow * 0.1 + head_look.y).abs(),
|
||||
);
|
||||
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
|
||||
|
||||
next.chest.offset = Vec3::new(
|
||||
0.0,
|
||||
wave_stop * -0.4,
|
||||
7.0 + wave_slow * 0.1 + wave_stop * -0.8,
|
||||
);
|
||||
next.chest.ori = Quaternion::rotation_x(wave_stop * 0.15);
|
||||
next.chest.scale = Vec3::one() + wave_slow_abs * 0.05;
|
||||
|
||||
next.belt.offset = Vec3::new(0.0, wave_stop * 1.2, 5.0);
|
||||
next.belt.ori = Quaternion::rotation_x(wave_stop * 0.3);
|
||||
next.belt.scale = (Vec3::one() + wave_slow_abs * 0.05) * 1.02;
|
||||
|
||||
next.shorts.offset = Vec3::new(0.0, wave_stop * 2.5, 2.0 + wave_stop * 0.6);
|
||||
next.shorts.ori = Quaternion::rotation_x(wave_stop * 0.6);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-7.5,
|
||||
0.0 + wave_ultra_slow_cos * 0.15,
|
||||
wave_ultra_slow * 0.7 + wave_stop * -2.0,
|
||||
);
|
||||
|
||||
next.l_hand.ori =
|
||||
Quaternion::rotation_x(0.0 + wave_slow_cos * -0.1 + wave_ultra_slow * 0.1);
|
||||
next.l_hand.scale = Vec3::one() + wave_slow_abs * -0.05;
|
||||
|
||||
next.r_hand.offset = Vec3::new(
|
||||
7.5,
|
||||
0.0 + wave_ultra_slow_cos * 0.15,
|
||||
wave_ultra_slow * 0.7 + wave_stop * -2.0,
|
||||
);
|
||||
next.r_hand.ori =
|
||||
Quaternion::rotation_x(0.0 + wave_slow * -0.1 + wave_ultra_slow_cos * 0.1);
|
||||
next.r_hand.scale = Vec3::one() + wave_slow_abs * -0.05;
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, -0.1, 8.0);
|
||||
next.l_foot.ori =
|
||||
Quaternion::rotation_x(wave_slow * 0.1 + wave_stop * 1.2 + wave_ultra_slow * 0.1);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, -0.1, 8.0);
|
||||
next.r_foot.ori = Quaternion::rotation_x(
|
||||
wave_slow_cos * 0.1 + wave_stop * 1.2 + wave_ultra_slow_cos * 0.1,
|
||||
);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.weapon.offset = Vec3::new(
|
||||
-7.0 + skeleton_attr.weapon_x,
|
||||
-5.0 + skeleton_attr.weapon_y,
|
||||
15.0,
|
||||
);
|
||||
next.weapon.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
||||
next.weapon.scale = Vec3::one() + wave_slow_abs * -0.05;
|
||||
|
||||
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
|
||||
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.l_shoulder.scale = (Vec3::one() + wave_slow_abs * -0.05) * 1.15;
|
||||
|
||||
next.r_shoulder.offset = Vec3::new(5.0, 0.0, 4.7);
|
||||
next.r_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.r_shoulder.scale = (Vec3::one() + wave_slow_abs * -0.05) * 1.15;
|
||||
|
||||
next.draw.offset = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.draw.ori = Quaternion::rotation_y(0.0);
|
||||
next.draw.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, -0.2, wave_stop * -0.16) * skeleton_attr.scaler;
|
||||
next.torso.ori = Quaternion::rotation_x(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
next
|
||||
}
|
||||
}
|
@ -5,9 +5,6 @@ use super::{
|
||||
use std::{f32::consts::PI, ops::Mul};
|
||||
use vek::*;
|
||||
|
||||
pub struct Input {
|
||||
pub attack: bool,
|
||||
}
|
||||
pub struct StandAnimation;
|
||||
|
||||
impl Animation for StandAnimation {
|
||||
@ -18,12 +15,14 @@ impl Animation for StandAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: f64,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin();
|
||||
let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos();
|
||||
let wave_ultra_slow_abs = ((anim_time as f32 * 0.5 + PI).sin()) + 1.0;
|
||||
|
||||
let head_look = Vec2::new(
|
||||
((global_time + anim_time) as f32 / 12.0)
|
||||
@ -48,11 +47,11 @@ impl Animation for StandAnimation {
|
||||
|
||||
next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_ultra_slow * 0.3);
|
||||
next.chest.ori = Quaternion::rotation_x(0.0);
|
||||
next.chest.scale = Vec3::one();
|
||||
next.chest.scale = Vec3::one() + wave_ultra_slow_abs * 0.05;
|
||||
|
||||
next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + wave_ultra_slow * 0.3);
|
||||
next.belt.ori = Quaternion::rotation_x(0.0);
|
||||
next.belt.scale = Vec3::one();
|
||||
next.belt.scale = Vec3::one() + wave_ultra_slow_abs * 0.05;
|
||||
|
||||
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + wave_ultra_slow * 0.3);
|
||||
next.shorts.ori = Quaternion::rotation_x(0.0);
|
||||
@ -70,10 +69,10 @@ impl Animation for StandAnimation {
|
||||
next.r_hand.offset = Vec3::new(
|
||||
7.5,
|
||||
0.0 + wave_ultra_slow_cos * 0.15,
|
||||
0.0 + wave_ultra_slow * 0.5,
|
||||
0.0 + wave_ultra_slow * 0.5 + wave_ultra_slow_abs * -0.05,
|
||||
);
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * -0.06);
|
||||
next.r_hand.scale = Vec3::one();
|
||||
next.r_hand.scale = Vec3::one() + wave_ultra_slow_abs * -0.05;
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, -0.1, 8.0);
|
||||
next.l_foot.ori = Quaternion::identity();
|
||||
@ -89,15 +88,15 @@ impl Animation for StandAnimation {
|
||||
15.0,
|
||||
);
|
||||
next.weapon.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
||||
next.weapon.scale = Vec3::one();
|
||||
next.weapon.scale = Vec3::one() + wave_ultra_slow_abs * -0.05;
|
||||
|
||||
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
|
||||
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.l_shoulder.scale = Vec3::one() * 1.1;
|
||||
next.l_shoulder.scale = (Vec3::one() + wave_ultra_slow_abs * -0.05) * 1.15;
|
||||
|
||||
next.r_shoulder.offset = Vec3::new(5.0, 0.0, 4.7);
|
||||
next.r_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.1;
|
||||
next.r_shoulder.scale = (Vec3::one() + wave_ultra_slow_abs * -0.05) * 1.15;
|
||||
|
||||
next.draw.offset = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.draw.ori = Quaternion::rotation_y(0.0);
|
||||
|
130
voxygen/src/anim/character/swim.rs
Normal file
130
voxygen/src/anim/character/swim.rs
Normal file
@ -0,0 +1,130 @@
|
||||
use super::{
|
||||
super::{Animation, SkeletonAttr},
|
||||
CharacterSkeleton,
|
||||
};
|
||||
use std::f32::consts::PI;
|
||||
use std::ops::Mul;
|
||||
use vek::*;
|
||||
|
||||
pub struct SwimAnimation;
|
||||
|
||||
impl Animation for SwimAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = (f32, f32, f64);
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
(velocity, orientation, global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave = (anim_time as f32 * velocity * 1.2).sin();
|
||||
let wave_cos = (anim_time as f32 * velocity * 1.2).cos();
|
||||
|
||||
let wave_diff = (anim_time as f32 * velocity * 0.6).sin();
|
||||
let wave_cos_dub = (anim_time as f32 * velocity * 2.4).cos();
|
||||
let wave_stop = (anim_time as f32 * 2.6).min(PI / 2.0).sin();
|
||||
let head_look = Vec2::new(
|
||||
((global_time + anim_time) as f32 / 2.0)
|
||||
.floor()
|
||||
.mul(7331.0)
|
||||
.sin()
|
||||
* 0.2,
|
||||
((global_time + anim_time) as f32 / 2.0)
|
||||
.floor()
|
||||
.mul(1337.0)
|
||||
.sin()
|
||||
* 0.1,
|
||||
);
|
||||
|
||||
let vel = Vec2::from(velocity);
|
||||
let ori = (Vec2::from(orientation)).normalized();
|
||||
|
||||
let _tilt = if Vec2::new(ori, vel)
|
||||
.map(|v| Vec2::<f32>::from(v).magnitude_squared())
|
||||
.reduce_partial_min()
|
||||
> 0.001
|
||||
{
|
||||
vel.normalized().dot(ori.normalized()).min(1.0).acos()
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
next.head.offset = Vec3::new(
|
||||
0.0,
|
||||
-1.0 + skeleton_attr.neck_forward,
|
||||
skeleton_attr.neck_height + 15.0 + wave_cos * 1.3,
|
||||
);
|
||||
next.head.ori = Quaternion::rotation_z(head_look.x + wave * 0.1)
|
||||
* Quaternion::rotation_x(head_look.y + 0.35);
|
||||
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
|
||||
|
||||
next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_cos * 1.1);
|
||||
next.chest.ori = Quaternion::rotation_z(wave * 0.2);
|
||||
next.chest.scale = Vec3::one();
|
||||
|
||||
next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + wave_cos * 1.1);
|
||||
next.belt.ori = Quaternion::rotation_z(wave * 0.35);
|
||||
next.belt.scale = Vec3::one();
|
||||
|
||||
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + wave_cos * 1.1);
|
||||
next.shorts.ori = Quaternion::rotation_z(wave * 0.6);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-7.5 + wave_cos_dub * 1.0,
|
||||
2.0 + wave_cos * 5.0,
|
||||
0.0 - wave * 1.5,
|
||||
);
|
||||
next.l_hand.ori = Quaternion::rotation_x(wave_cos * 0.8);
|
||||
next.l_hand.scale = Vec3::one();
|
||||
|
||||
next.r_hand.offset = Vec3::new(
|
||||
7.5 - wave_cos_dub * 1.0,
|
||||
2.0 - wave_cos * 5.0,
|
||||
0.0 + wave * 1.5,
|
||||
);
|
||||
next.r_hand.ori = Quaternion::rotation_x(wave_cos * -0.8);
|
||||
next.r_hand.scale = Vec3::one();
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave_cos * 1.0, 6.0 - wave_cos_dub * 0.7);
|
||||
next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave_cos * 1.5);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, 0.0 - wave_cos * 1.0, 6.0 - wave_cos_dub * 0.7);
|
||||
next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.5);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.weapon.offset = Vec3::new(
|
||||
-7.0 + skeleton_attr.weapon_x,
|
||||
-5.0 + skeleton_attr.weapon_y,
|
||||
15.0,
|
||||
);
|
||||
next.weapon.ori =
|
||||
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + wave_cos * 0.25);
|
||||
next.weapon.scale = Vec3::one();
|
||||
|
||||
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
|
||||
next.l_shoulder.ori = Quaternion::rotation_x(wave_cos * 0.15);
|
||||
next.l_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.r_shoulder.offset = Vec3::new(5.0, 0.0, 4.7);
|
||||
next.r_shoulder.ori = Quaternion::rotation_x(wave * 0.15);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.draw.offset = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.draw.ori = Quaternion::rotation_y(0.0);
|
||||
next.draw.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, -0.2 + wave * -0.08, 0.4) * skeleton_attr.scaler;
|
||||
next.torso.ori =
|
||||
Quaternion::rotation_x(wave_stop * velocity * -0.06 + wave_diff * velocity * -0.005)
|
||||
* Quaternion::rotation_y(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
|
||||
next
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ impl Animation for WieldAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
(_velocity, _global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -178,6 +178,7 @@ pub trait Animation {
|
||||
skeleton: &Self::Skeleton,
|
||||
dependency: Self::Dependency,
|
||||
anim_time: f64,
|
||||
rate: &mut f32,
|
||||
skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ impl Animation for IdleAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: Self::Dependency,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
_skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -15,6 +15,7 @@ impl Animation for JumpAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
(_velocity, _global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
_skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -14,6 +14,7 @@ impl Animation for RunAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
(_velocity, _global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
_skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -15,6 +15,7 @@ impl Animation for IdleAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: Self::Dependency,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
_skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -15,6 +15,7 @@ impl Animation for JumpAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
_global_time: Self::Dependency,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
_skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -15,6 +15,7 @@ impl Animation for RunAnimation {
|
||||
skeleton: &Self::Skeleton,
|
||||
(_velocity, global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
_rate: &mut f32,
|
||||
_skeleton_attr: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
@ -28,6 +28,15 @@ image_ids! {
|
||||
bar_content: "voxygen.element.skillbar.bar_content",
|
||||
level_up: "voxygen.element.misc_bg.level_up",
|
||||
level_down:"voxygen.element.misc_bg.level_down",
|
||||
stamina_0:"voxygen.element.skillbar.stamina_wheel-empty",
|
||||
stamina_1:"voxygen.element.skillbar.stamina_wheel-0",
|
||||
stamina_2:"voxygen.element.skillbar.stamina_wheel-1",
|
||||
stamina_3:"voxygen.element.skillbar.stamina_wheel-2",
|
||||
stamina_4:"voxygen.element.skillbar.stamina_wheel-3",
|
||||
stamina_5:"voxygen.element.skillbar.stamina_wheel-4",
|
||||
stamina_6:"voxygen.element.skillbar.stamina_wheel-5",
|
||||
stamina_7:"voxygen.element.skillbar.stamina_wheel-6",
|
||||
stamina_8:"voxygen.element.skillbar.stamina_wheel-7",
|
||||
|
||||
// Window Parts
|
||||
window_3: "voxygen.element.frames.window_3",
|
||||
|
@ -77,7 +77,7 @@ widget_ids! {
|
||||
level_down,
|
||||
level_align,
|
||||
level_message,
|
||||
|
||||
stamina_wheel,
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,6 +163,37 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
let shortcuts = self.global_state.settings.gameplay.shortcut_numbers;
|
||||
|
||||
const BG_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 0.8);
|
||||
|
||||
// Stamina Wheel
|
||||
/*
|
||||
let stamina_percentage =
|
||||
self.stats.health.current() as f64 / self.stats.health.maximum() as f64 * 100.0;
|
||||
if stamina_percentage < 100.0 {
|
||||
Image::new(if stamina_percentage <= 0.1 {
|
||||
self.imgs.stamina_0
|
||||
} else if stamina_percentage < 12.5 {
|
||||
self.imgs.stamina_1
|
||||
} else if stamina_percentage < 25.0 {
|
||||
self.imgs.stamina_2
|
||||
} else if stamina_percentage < 37.5 {
|
||||
self.imgs.stamina_3
|
||||
} else if stamina_percentage < 50.0 {
|
||||
self.imgs.stamina_4
|
||||
} else if stamina_percentage < 62.5 {
|
||||
self.imgs.stamina_5
|
||||
} else if stamina_percentage < 75.0 {
|
||||
self.imgs.stamina_6
|
||||
} else if stamina_percentage < 87.5 {
|
||||
self.imgs.stamina_7
|
||||
} else {
|
||||
self.imgs.stamina_8
|
||||
})
|
||||
.w_h(37.0 * 3.0, 37.0 * 3.0)
|
||||
.mid_bottom_with_margin_on(ui.window, 150.0)
|
||||
.set(state.ids.stamina_wheel, ui);
|
||||
}
|
||||
*/
|
||||
|
||||
// Level Up Message
|
||||
|
||||
let current_level = self.stats.level.level();
|
||||
|
@ -131,6 +131,7 @@ impl Scene {
|
||||
self.figure_state.skeleton_mut(),
|
||||
client.state().get_time(),
|
||||
client.state().get_time(),
|
||||
&mut 0.0,
|
||||
&SkeletonAttr::from(&body),
|
||||
);
|
||||
self.figure_state.skeleton_mut().interpolate(
|
||||
@ -145,6 +146,8 @@ impl Scene {
|
||||
1.0,
|
||||
Rgba::broadcast(1.0),
|
||||
1.0 / 60.0, // TODO: Use actual deltatime here?
|
||||
1.0,
|
||||
1.0,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ use common::{
|
||||
use hashbrown::HashMap;
|
||||
use log::debug;
|
||||
use specs::{Entity as EcsEntity, Join};
|
||||
use std::time::Instant;
|
||||
use vek::*;
|
||||
|
||||
const DAMAGE_FADE_COEFFICIENT: f64 = 5.0;
|
||||
@ -128,6 +127,9 @@ impl FigureMgr {
|
||||
)
|
||||
.1;
|
||||
|
||||
let mut movement_animation_rate = 1.0;
|
||||
let mut action_animation_rate = 1.0;
|
||||
|
||||
match body {
|
||||
Body::Humanoid(_) => {
|
||||
let state = self
|
||||
@ -140,45 +142,67 @@ impl FigureMgr {
|
||||
};
|
||||
|
||||
if !character.is_same_movement(&last_character.0) {
|
||||
state.last_movement_change = Instant::now();
|
||||
state.movement_time = 0.0;
|
||||
}
|
||||
if !character.is_same_action(&last_character.0) {
|
||||
state.last_action_change = Instant::now();
|
||||
state.action_time = 0.0;
|
||||
}
|
||||
|
||||
let time_since_movement_change =
|
||||
state.last_movement_change.elapsed().as_secs_f64();
|
||||
let time_since_action_change = state.last_action_change.elapsed().as_secs_f64();
|
||||
|
||||
let target_base = match &character.movement {
|
||||
Stand => anim::character::StandAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
time,
|
||||
time_since_movement_change,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Run => anim::character::RunAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(vel.0.magnitude(), ori.0.magnitude(), time),
|
||||
time_since_movement_change,
|
||||
(vel.0, ori.0, state.last_ori, time),
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Jump => anim::character::JumpAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
time,
|
||||
time_since_movement_change,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Roll { .. } => anim::character::RollAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
time,
|
||||
time_since_movement_change,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Glide => anim::character::GlidingAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(vel.0.magnitude(), time),
|
||||
time_since_movement_change,
|
||||
(vel.0, ori.0, state.last_ori, time),
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Swim => anim::character::SwimAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(vel.0.magnitude(), ori.0.magnitude(), time),
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Climb => anim::character::ClimbAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
(vel.0, ori.0, time),
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Sit => anim::character::SitAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(),
|
||||
time,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
};
|
||||
@ -187,40 +211,54 @@ impl FigureMgr {
|
||||
(Stand, Wield { .. }) => anim::character::CidleAnimation::update_skeleton(
|
||||
&target_base,
|
||||
time,
|
||||
time_since_action_change,
|
||||
state.action_time,
|
||||
&mut action_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
(Stand, Block { .. }) => {
|
||||
anim::character::BlockIdleAnimation::update_skeleton(
|
||||
&target_base,
|
||||
time,
|
||||
time_since_action_change,
|
||||
state.action_time,
|
||||
&mut action_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
}
|
||||
(_, Attack { .. }) => anim::character::AttackAnimation::update_skeleton(
|
||||
&target_base,
|
||||
time,
|
||||
time_since_action_change,
|
||||
state.action_time,
|
||||
&mut action_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
(_, Wield { .. }) => anim::character::WieldAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(vel.0.magnitude(), time),
|
||||
time_since_action_change,
|
||||
state.action_time,
|
||||
&mut action_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
(_, Block { .. }) => anim::character::BlockAnimation::update_skeleton(
|
||||
&target_base,
|
||||
time,
|
||||
time_since_action_change,
|
||||
state.action_time,
|
||||
&mut action_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
_ => target_base,
|
||||
};
|
||||
state.skeleton.interpolate(&target_bones, dt);
|
||||
|
||||
state.update(renderer, pos.0, ori.0, scale, col, dt);
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
);
|
||||
}
|
||||
Body::Quadruped(_) => {
|
||||
let state = self
|
||||
@ -234,29 +272,29 @@ impl FigureMgr {
|
||||
};
|
||||
|
||||
if !character.is_same_movement(&last_character.0) {
|
||||
state.last_movement_change = Instant::now();
|
||||
state.movement_time = 0.0;
|
||||
}
|
||||
|
||||
let time_since_movement_change =
|
||||
state.last_movement_change.elapsed().as_secs_f64();
|
||||
|
||||
let target_base = match character.movement {
|
||||
Stand => anim::quadruped::IdleAnimation::update_skeleton(
|
||||
&QuadrupedSkeleton::new(),
|
||||
time,
|
||||
time_since_movement_change,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Run => anim::quadruped::RunAnimation::update_skeleton(
|
||||
&QuadrupedSkeleton::new(),
|
||||
(vel.0.magnitude(), time),
|
||||
time_since_movement_change,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Jump => anim::quadruped::JumpAnimation::update_skeleton(
|
||||
&QuadrupedSkeleton::new(),
|
||||
(vel.0.magnitude(), time),
|
||||
time_since_movement_change,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
|
||||
@ -265,7 +303,16 @@ impl FigureMgr {
|
||||
};
|
||||
|
||||
state.skeleton.interpolate(&target_base, dt);
|
||||
state.update(renderer, pos.0, ori.0, scale, col, dt);
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
);
|
||||
}
|
||||
Body::QuadrupedMedium(_) => {
|
||||
let state = self
|
||||
@ -281,29 +328,29 @@ impl FigureMgr {
|
||||
};
|
||||
|
||||
if !character.is_same_movement(&last_character.0) {
|
||||
state.last_movement_change = Instant::now();
|
||||
state.movement_time = 0.0;
|
||||
}
|
||||
|
||||
let time_since_movement_change =
|
||||
state.last_movement_change.elapsed().as_secs_f64();
|
||||
|
||||
let target_base = match character.movement {
|
||||
Stand => anim::quadrupedmedium::IdleAnimation::update_skeleton(
|
||||
&QuadrupedMediumSkeleton::new(),
|
||||
time,
|
||||
time_since_movement_change,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Run => anim::quadrupedmedium::RunAnimation::update_skeleton(
|
||||
&QuadrupedMediumSkeleton::new(),
|
||||
(vel.0.magnitude(), time),
|
||||
time_since_movement_change,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
Jump => anim::quadrupedmedium::JumpAnimation::update_skeleton(
|
||||
&QuadrupedMediumSkeleton::new(),
|
||||
(vel.0.magnitude(), time),
|
||||
time_since_movement_change,
|
||||
state.movement_time,
|
||||
&mut movement_animation_rate,
|
||||
skeleton_attr,
|
||||
),
|
||||
|
||||
@ -312,7 +359,16 @@ impl FigureMgr {
|
||||
};
|
||||
|
||||
state.skeleton.interpolate(&target_base, dt);
|
||||
state.update(renderer, pos.0, ori.0, scale, col, dt);
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
);
|
||||
}
|
||||
Body::Object(_) => {
|
||||
let state = self
|
||||
@ -321,7 +377,16 @@ impl FigureMgr {
|
||||
.or_insert_with(|| FigureState::new(renderer, ObjectSkeleton::new()));
|
||||
|
||||
state.skeleton = state.skeleton_mut().clone();
|
||||
state.update(renderer, pos.0, ori.0, scale, col, dt);
|
||||
state.update(
|
||||
renderer,
|
||||
pos.0,
|
||||
ori.0,
|
||||
scale,
|
||||
col,
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -426,11 +491,12 @@ impl FigureMgr {
|
||||
pub struct FigureState<S: Skeleton> {
|
||||
bone_consts: Consts<FigureBoneData>,
|
||||
locals: Consts<FigureLocals>,
|
||||
last_movement_change: Instant,
|
||||
last_action_change: Instant,
|
||||
movement_time: f64,
|
||||
action_time: f64,
|
||||
skeleton: S,
|
||||
pos: Vec3<f32>,
|
||||
ori: Vec3<f32>,
|
||||
last_ori: Vec3<f32>,
|
||||
}
|
||||
|
||||
impl<S: Skeleton> FigureState<S> {
|
||||
@ -440,11 +506,12 @@ impl<S: Skeleton> FigureState<S> {
|
||||
.create_consts(&skeleton.compute_matrices())
|
||||
.unwrap(),
|
||||
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
|
||||
last_movement_change: Instant::now(),
|
||||
last_action_change: Instant::now(),
|
||||
movement_time: 0.0,
|
||||
action_time: 0.0,
|
||||
skeleton,
|
||||
pos: Vec3::zero(),
|
||||
ori: Vec3::zero(),
|
||||
last_ori: Vec3::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,7 +523,11 @@ impl<S: Skeleton> FigureState<S> {
|
||||
scale: f32,
|
||||
col: Rgba<f32>,
|
||||
dt: f32,
|
||||
movement_rate: f32,
|
||||
action_rate: f32,
|
||||
) {
|
||||
self.last_ori = Lerp::lerp(self.last_ori, ori, 15.0 * dt);
|
||||
|
||||
// Update interpolation values
|
||||
if self.pos.distance_squared(pos) < 64.0 * 64.0 {
|
||||
self.pos = Lerp::lerp(self.pos, pos, 15.0 * dt);
|
||||
@ -466,6 +537,9 @@ impl<S: Skeleton> FigureState<S> {
|
||||
self.ori = ori;
|
||||
}
|
||||
|
||||
self.movement_time += (dt * movement_rate) as f64;
|
||||
self.action_time += (dt * action_rate) as f64;
|
||||
|
||||
let mat = Mat4::<f32>::identity()
|
||||
* Mat4::translation_3d(self.pos)
|
||||
* Mat4::rotation_z(-ori.x.atan2(ori.y))
|
||||
|
@ -10,8 +10,7 @@ use client::{self, Client};
|
||||
use common::{
|
||||
clock::Clock,
|
||||
comp,
|
||||
comp::Pos,
|
||||
comp::Vel,
|
||||
comp::{Pos, Vel},
|
||||
msg::ClientState,
|
||||
terrain::{Block, BlockKind},
|
||||
vol::ReadVol,
|
||||
@ -118,6 +117,9 @@ impl PlayState for SessionState {
|
||||
.compute_dependents(&self.client.borrow());
|
||||
let cam_dir: Vec3<f32> = Vec3::from(view_mat.inverted() * -Vec4::unit_z());
|
||||
|
||||
// Reset controller events
|
||||
self.controller.clear_events();
|
||||
|
||||
// Handle window events.
|
||||
for event in global_state.window.fetch_events() {
|
||||
// Pass all events to the ui first.
|
||||
@ -208,6 +210,9 @@ impl PlayState for SessionState {
|
||||
Event::InputUpdate(GameInput::Jump, state) => {
|
||||
self.controller.jump = state;
|
||||
}
|
||||
Event::InputUpdate(GameInput::Sit, state) => {
|
||||
self.controller.sit = state;
|
||||
}
|
||||
Event::InputUpdate(GameInput::MoveForward, state) => self.key_state.up = state,
|
||||
Event::InputUpdate(GameInput::MoveBack, state) => self.key_state.down = state,
|
||||
Event::InputUpdate(GameInput::MoveLeft, state) => self.key_state.left = state,
|
||||
@ -215,6 +220,54 @@ impl PlayState for SessionState {
|
||||
Event::InputUpdate(GameInput::Glide, state) => {
|
||||
self.controller.glide = state;
|
||||
}
|
||||
Event::InputUpdate(GameInput::Climb, state) => self.controller.climb = state,
|
||||
Event::InputUpdate(GameInput::ClimbDown, state) => {
|
||||
self.controller.climb_down = state
|
||||
}
|
||||
Event::InputUpdate(GameInput::WallLeap, state) => {
|
||||
self.controller.wall_leap = state
|
||||
}
|
||||
Event::InputUpdate(GameInput::Mount, true) => {
|
||||
let client = self.client.borrow();
|
||||
if client.is_mounted() {
|
||||
self.controller.push_event(comp::ControlEvent::Unmount);
|
||||
} else {
|
||||
let player_pos = client
|
||||
.state()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(client.entity())
|
||||
.copied();
|
||||
if let Some(player_pos) = player_pos {
|
||||
// Find closest mountable entity
|
||||
let closest_mountable = (
|
||||
&client.state().ecs().entities(),
|
||||
&client.state().ecs().read_storage::<comp::Pos>(),
|
||||
&client.state().ecs().read_storage::<comp::MountState>(),
|
||||
)
|
||||
.join()
|
||||
.filter(|(_, _, ms)| {
|
||||
if let comp::MountState::Unmounted = ms {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.min_by_key(|(_, pos, _)| {
|
||||
(player_pos.0.distance_squared(pos.0) * 1000.0) as i32
|
||||
})
|
||||
.map(|(entity, _, _)| entity);
|
||||
|
||||
if let Some(mountee_uid) =
|
||||
closest_mountable.and_then(|mountee_entity| {
|
||||
client.state().ecs().uid_from_entity(mountee_entity)
|
||||
})
|
||||
{
|
||||
self.controller
|
||||
.push_event(comp::ControlEvent::Mount(mountee_uid.into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::Interact, state) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
|
||||
|
@ -24,7 +24,12 @@ pub struct ControlSettings {
|
||||
pub move_back: KeyMouse,
|
||||
pub move_right: KeyMouse,
|
||||
pub jump: KeyMouse,
|
||||
pub sit: KeyMouse,
|
||||
pub glide: KeyMouse,
|
||||
pub climb: KeyMouse,
|
||||
pub climb_down: KeyMouse,
|
||||
pub wall_leap: KeyMouse,
|
||||
pub mount: KeyMouse,
|
||||
pub map: KeyMouse,
|
||||
pub bag: KeyMouse,
|
||||
pub quest_log: KeyMouse,
|
||||
@ -57,7 +62,12 @@ impl Default for ControlSettings {
|
||||
move_back: KeyMouse::Key(VirtualKeyCode::S),
|
||||
move_right: KeyMouse::Key(VirtualKeyCode::D),
|
||||
jump: KeyMouse::Key(VirtualKeyCode::Space),
|
||||
sit: KeyMouse::Key(VirtualKeyCode::K),
|
||||
glide: KeyMouse::Key(VirtualKeyCode::LShift),
|
||||
climb: KeyMouse::Key(VirtualKeyCode::Space),
|
||||
climb_down: KeyMouse::Key(VirtualKeyCode::LShift),
|
||||
wall_leap: KeyMouse::Mouse(MouseButton::Middle),
|
||||
mount: KeyMouse::Key(VirtualKeyCode::F),
|
||||
map: KeyMouse::Key(VirtualKeyCode::M),
|
||||
bag: KeyMouse::Key(VirtualKeyCode::B),
|
||||
quest_log: KeyMouse::Key(VirtualKeyCode::L),
|
||||
|
@ -19,7 +19,12 @@ pub enum GameInput {
|
||||
MoveLeft,
|
||||
MoveRight,
|
||||
Jump,
|
||||
Sit,
|
||||
Glide,
|
||||
Climb,
|
||||
ClimbDown,
|
||||
WallLeap,
|
||||
Mount,
|
||||
Enter,
|
||||
Command,
|
||||
Escape,
|
||||
@ -142,9 +147,24 @@ impl Window {
|
||||
map.entry(settings.controls.jump)
|
||||
.or_default()
|
||||
.push(GameInput::Jump);
|
||||
map.entry(settings.controls.sit)
|
||||
.or_default()
|
||||
.push(GameInput::Sit);
|
||||
map.entry(settings.controls.glide)
|
||||
.or_default()
|
||||
.push(GameInput::Glide);
|
||||
map.entry(settings.controls.climb)
|
||||
.or_default()
|
||||
.push(GameInput::Climb);
|
||||
map.entry(settings.controls.climb_down)
|
||||
.or_default()
|
||||
.push(GameInput::ClimbDown);
|
||||
map.entry(settings.controls.wall_leap)
|
||||
.or_default()
|
||||
.push(GameInput::WallLeap);
|
||||
map.entry(settings.controls.mount)
|
||||
.or_default()
|
||||
.push(GameInput::Mount);
|
||||
map.entry(settings.controls.map)
|
||||
.or_default()
|
||||
.push(GameInput::Map);
|
||||
|
Loading…
Reference in New Issue
Block a user