mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
No gliding bodies, only gliding glider
This commit is contained in:
parent
906bf798e7
commit
96168b5654
@ -594,21 +594,6 @@ impl Body {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wings(&self) -> Option<RigidWings> {
|
||||
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<Self, IdvStorage<Self>>;
|
||||
}
|
||||
|
||||
/// 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<f32>,
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
|
@ -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<f32>,
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -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,
|
||||
|
@ -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) }
|
||||
|
@ -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::<f32>::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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user