diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index 8ab78af038..1fe48767b6 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -594,21 +594,6 @@ impl Body { } } - pub fn wings(&self) -> Option { - matches!( - self, - Body::BirdMedium(_) - | Body::BirdSmall(_) - | Body::Dragon(_) - | Body::FishMedium(_) - | Body::FishSmall(_) - ) - .then_some({ - let dim = self.dimensions().xy(); - RigidWings::new(dim.x, dim.y * 0.2) - }) - } - pub fn immune_to(&self, buff: BuffKind) -> bool { match buff { BuffKind::Bleeding => matches!(self, Body::Object(_) | Body::Golem(_) | Body::Ship(_)), @@ -665,37 +650,3 @@ impl Body { impl Component for Body { type Storage = DerefFlaggedStorage>; } - -/// An elliptical fixed rigid wing. Plurally named simply because it's a shape -/// typically composed of two wings forming an elliptical lift distribution. -/// -/// Animal wings are technically flexible, not rigid, (difference being that the -/// former's shape is affected by the flow) and usually has the ability to -/// assume complex shapes with properties like curved camber line, span-wise -/// twist, dihedral angle, sweep angle, and partitioned sections. However, we -/// can make do with this model for fully extended animal wings, enabling them -/// to glide. -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct RigidWings { - aspect_ratio: f32, - planform_area: f32, - // sweep_angle: Option, -} - -impl RigidWings { - /// Wings from total span (wing-tip to wing-tip) and - /// chord length (leading edge to trailing edge) - pub fn new(span_length: f32, chord_length: f32) -> Self { - let planform_area = std::f32::consts::PI * chord_length * span_length * 0.25; - Self { - aspect_ratio: span_length.powi(2) / planform_area, - planform_area, - } - } - - /// The aspect ratio is the ratio of the span squared to actual planform - /// area - pub fn aspect_ratio(&self) -> f32 { self.aspect_ratio } - - pub fn planform_area(&self) -> f32 { self.planform_area } -} diff --git a/common/src/comp/fluid_dynamics.rs b/common/src/comp/fluid_dynamics.rs index 09de84ad66..23589ef285 100644 --- a/common/src/comp/fluid_dynamics.rs +++ b/common/src/comp/fluid_dynamics.rs @@ -1,5 +1,5 @@ use super::{ - body::{object, Body, RigidWings}, + body::{object, Body}, Density, Ori, Vel, }; use crate::{ @@ -105,7 +105,6 @@ impl Body { 0.5 * fluid_density * v_sq * wings - .filter(|_| crate::lift_enabled()) .map(|wings| { // Since we have wings, we proceed to calculate the lift and drag @@ -268,6 +267,40 @@ fn angle_of_attack(ori: &Ori, rel_flow_dir: &Dir) -> f32 { PI / 2.0 - ori.up().angle_between(rel_flow_dir.to_vec()) } +/// An elliptical fixed rigid wing. Plurally named simply because it's a shape +/// typically composed of two wings forming an elliptical lift distribution. +// +// Animal wings are technically flexible, not rigid, (difference being that the +// former's shape is affected by the flow) and usually has the ability to +// assume complex shapes with properties like curved camber line, span-wise +// twist, dihedral angle, sweep angle, and partitioned sections. However, we +// could make do with this model for fully extended animal wings, enabling them +// to glide. +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct RigidWings { + aspect_ratio: f32, + planform_area: f32, + // sweep_angle: Option, +} + +impl RigidWings { + /// Wings from total span (wing-tip to wing-tip) and + /// chord length (leading edge to trailing edge) + pub fn new(span_length: f32, chord_length: f32) -> Self { + let planform_area = std::f32::consts::PI * chord_length * span_length * 0.25; + Self { + aspect_ratio: span_length.powi(2) / planform_area, + planform_area, + } + } + + /// The aspect ratio is the ratio of the span squared to actual planform + /// area + pub fn aspect_ratio(&self) -> f32 { self.aspect_ratio } + + pub fn planform_area(&self) -> f32 { self.planform_area } +} + impl RigidWings { /// Total lift coefficient for a finite wing of symmetric aerofoil shape and /// elliptical pressure distribution. diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 720dab01b5..53e86e65fb 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -52,7 +52,7 @@ pub use self::{ body::{ biped_large, biped_small, bird_large, bird_medium, dragon, fish_medium, fish_small, golem, humanoid, object, quadruped_low, quadruped_medium, quadruped_small, ship, theropod, - AllBodies, Body, BodyData, RigidWings, + AllBodies, Body, BodyData, }, buff::{ Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs, @@ -68,7 +68,7 @@ pub use self::{ InputKind, InventoryAction, InventoryEvent, InventoryManip, MountState, Mounting, }, energy::{Energy, EnergyChange, EnergySource}, - fluid_dynamics::Fluid, + fluid_dynamics::{Fluid, RigidWings}, group::Group, home_chunk::HomeChunk, inputs::CanBuild, diff --git a/common/src/lib.rs b/common/src/lib.rs index a917e2a8c9..d4d8f6a094 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -91,5 +91,3 @@ pub use comp::inventory::loadout_builder::LoadoutBuilder; pub use explosion::{Explosion, RadiusEffect}; #[cfg(not(target_arch = "wasm32"))] pub use skillset_builder::SkillSetBuilder; - -pub fn lift_enabled() -> bool { inline_tweak::tweak!(true) } diff --git a/common/src/states/glide.rs b/common/src/states/glide.rs index 369f32eed6..10f030a623 100644 --- a/common/src/states/glide.rs +++ b/common/src/states/glide.rs @@ -1,18 +1,11 @@ use super::utils::handle_climb; use crate::{ comp::{inventory::slot::EquipSlot, CharacterState, Ori, RigidWings, StateUpdate}, - states::{ - behavior::{CharacterBehavior, JoinData}, - utils::fly_move, - }, + states::behavior::{CharacterBehavior, JoinData}, util::Dir, }; use serde::{Deserialize, Serialize}; -use vek::Vec2; - -const GLIDE_ANTIGRAV: f32 = crate::consts::GRAVITY * 0.90; -const GLIDE_ACCEL: f32 = 5.0; -const GLIDE_MAX_SPEED: f32 = 30.0; +use vek::*; #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Data { @@ -36,50 +29,69 @@ impl CharacterBehavior for Data { // If player is on ground, end glide if data.physics.on_ground && data.vel.0.magnitude_squared() < 25.0 { update.character = CharacterState::GlideWield; - return update; - } - if data + update + } else if data .physics .in_liquid() .map(|depth| depth > 0.5) .unwrap_or(false) + || data.inventory.equipped(EquipSlot::Glider).is_none() { update.character = CharacterState::Idle; - } - if data.inventory.equipped(EquipSlot::Glider).is_none() { - update.character = CharacterState::Idle - }; - - if crate::lift_enabled() { - fly_move(data, &mut update, inline_tweak::tweak!(0.1)); + update + } else if handle_climb(&data, &mut update) { + update } else { - let horiz_vel = Vec2::::from(update.vel.0); - let horiz_speed_sq = horiz_vel.magnitude_squared(); + let tgt_ori = Some(data.inputs.move_dir) + .filter(|mv_dir| !mv_dir.is_approx_zero()) + .map(|mv_dir| { + Vec3::new( + mv_dir.x, + mv_dir.y, + Lerp::lerp_unclamped( + 0.0, + data.inputs.look_dir.z + inline_tweak::tweak!(0.3), + mv_dir.magnitude_squared() * inline_tweak::tweak!(2.0), + ), + ) + }) + .and_then(Dir::from_unnormalized) + .and_then(|tgt_dir| { + Dir::from_unnormalized(data.vel.0) + .and_then(|moving_dir| moving_dir.to_horizontal()) + .map(|moving_dir| { + Ori::from(tgt_dir).rolled_right( + (1.0 - moving_dir.dot(*tgt_dir).max(0.0)) + * self.ori.right().dot(*tgt_dir).signum() + * std::f32::consts::PI + / 3.0, + ) + }) + }) + .or_else(|| self.ori.look_dir().to_horizontal().map(Ori::from)) + .unwrap_or_default(); - // Move player according to movement direction vector - if horiz_speed_sq < GLIDE_MAX_SPEED.powi(2) { - update.vel.0 += Vec2::broadcast(data.dt.0) * data.inputs.move_dir * GLIDE_ACCEL; - } - - // Determine orientation vector from movement direction vector - if let Some(dir) = Dir::from_unnormalized(update.vel.0) { - update.ori = update.ori.slerped_towards(Ori::from(dir), 2.0 * data.dt.0); + let rate = { + let angle = self.ori.look_dir().angle_between(*data.inputs.look_dir); + 0.4 * std::f32::consts::PI / angle }; - // Apply Glide antigrav lift - if update.vel.0.z < 0.0 { - let lift = (GLIDE_ANTIGRAV + update.vel.0.z.powi(2) * 0.15) - * (horiz_speed_sq * f32::powf(0.075, 2.0)).clamp(0.2, 1.0); + let ori = self + .ori + .slerped_towards(tgt_ori, (data.dt.0 * rate).min(0.1)); + update.character = CharacterState::Glide(Self { ori, ..*self }); - update.vel.0.z += lift * data.dt.0; + if let Some(char_ori) = ori.to_horizontal() { + let rate = { + let angle = ori.look_dir().angle_between(*data.inputs.look_dir); + data.body.base_ori_rate() * std::f32::consts::PI / angle + }; + update.ori = update + .ori + .slerped_towards(char_ori, (data.dt.0 * rate).min(0.1)); } + update } - - // If there is a wall in front of character and they are trying to climb go to - // climb - handle_climb(&data, &mut update); - - update } fn unwield(&self, data: &JoinData) -> StateUpdate { diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 99ac3135d7..2b7e55f420 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -6,7 +6,7 @@ use crate::{ quadruped_low, quadruped_medium, quadruped_small, ship, skills::{Skill, SwimSkill}, theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind, - InventoryAction, Ori, StateUpdate, + InventoryAction, StateUpdate, }, consts::{FRIC_GROUND, GRAVITY}, event::{LocalEvent, ServerEvent}, @@ -377,63 +377,14 @@ pub fn fly_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) -> b .or_else(|| glider.is_some().then_some(0.0)) { let thrust = efficiency * force; - let accel = thrust / data.mass.0; - // if lift is enabled we do some more advanced stuff with pitch and roll - if crate::lift_enabled() && !matches!(data.body, Body::Ship(_)) { - let mut ori = glider.map(|g| g.ori).unwrap_or(update.ori); - let fw_dir = ori.look_dir().to_horizontal(); - let tgt_ori = Some(data.inputs.move_dir) - .filter(|mv_dir| !mv_dir.is_approx_zero()) - .map(|mv_dir| { - Vec3::new( - mv_dir.x, - mv_dir.y, - Lerp::lerp_unclamped( - 0.0, - data.inputs.look_dir.z + inline_tweak::tweak!(0.3), - mv_dir.magnitude_squared() * inline_tweak::tweak!(2.0), - ), - ) - }) - .and_then(Dir::from_unnormalized) - .and_then(|tgt_dir| { - Dir::from_unnormalized(data.vel.0) - .and_then(|moving_dir| moving_dir.to_horizontal()) - .map(|moving_dir| { - Ori::from(tgt_dir).rolled_right( - (1.0 - moving_dir.dot(*tgt_dir).max(0.0)) - * ori.right().dot(*tgt_dir).signum() - * std::f32::consts::PI - / 3.0, - ) - }) - }) - .or_else(|| fw_dir.map(Ori::from)) - .unwrap_or_default(); - let rate = { - let angle = ori.look_dir().angle_between(*data.inputs.look_dir); - data.body.base_ori_rate() * efficiency * std::f32::consts::PI / angle - }; - - ori = ori.slerped_towards(tgt_ori, (data.dt.0 * rate).min(0.1)); - if let Some(data) = glider { - update.character = CharacterState::Glide(glide::Data { ori, ..*data }); - if let Some(char_ori) = ori.to_horizontal() { - update.ori = char_ori; - } - } else { - update.ori = ori; - } - } else { - handle_orientation(data, update, efficiency); - } + handle_orientation(data, update, efficiency); // Elevation control match data.body { // flappy flappy - Body::Dragon(_) | Body::BirdMedium(_) | Body::BirdLarge(_) => { + Body::Dragon(_) | Body::BirdLarge(_) | Body::BirdMedium(_) => { let anti_grav = GRAVITY * (1.0 + data.inputs.move_z.min(0.0)); update.vel.0.z += data.dt.0 * (anti_grav + accel * data.inputs.move_z.max(0.0)); }, @@ -530,7 +481,7 @@ pub fn attempt_sneak(data: &JoinData, update: &mut StateUpdate) { } /// Checks that player can `Climb` and updates `CharacterState` if so -pub fn handle_climb(data: &JoinData, update: &mut StateUpdate) { +pub fn handle_climb(data: &JoinData, update: &mut StateUpdate) -> bool { if data.inputs.climb.is_some() && data.physics.on_wall.is_some() && !data.physics.on_ground @@ -544,6 +495,9 @@ pub fn handle_climb(data: &JoinData, update: &mut StateUpdate) { && update.energy.current() > 100 { update.character = CharacterState::Climb(climb::Data::create_adjusted_by_skills(data)); + true + } else { + false } } diff --git a/common/systems/src/phys.rs b/common/systems/src/phys.rs index 41a5de3bf1..cbd3f19c85 100644 --- a/common/systems/src/phys.rs +++ b/common/systems/src/phys.rs @@ -65,19 +65,12 @@ fn integrate_forces( CharacterState::Glide(data) => Some(data), _ => None, }); - // let wings: Option<(RigidWings, Ori)> = - // body.wings().map(|w| (w, ori)).or(character_state.and_then(|cs| { - // match cs { - // CharacterState::Glide(states::glide::Data{wings, ori}) => - // Some((*wings, *ori)), _ => None, - // } - // })); let impulse = dt.0 * body.aerodynamic_forces( glider.map(|g| &g.ori).unwrap_or(ori), &rel_flow, fluid_density.0, - glider.map(|g| g.wings).or_else(|| body.wings()).as_ref(), + glider.map(|g| g.wings).as_ref(), ); debug_assert!(!impulse.map(|a| a.is_nan()).reduce_or()); if !impulse.is_approx_zero() {