mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Make knockbacks cancels fly mode; parameterise winged bodies parasite drag over wing state
Assign more reasonable masses to QuadrupedSmall species
This commit is contained in:
parent
e66a2079ce
commit
aa06972a95
@ -240,13 +240,33 @@ impl Body {
|
||||
_ => 200.0,
|
||||
},
|
||||
Body::QuadrupedSmall(body) => match body.species {
|
||||
quadruped_small::Species::Batfox => 50.0,
|
||||
quadruped_small::Species::Axolotl => 1.0,
|
||||
quadruped_small::Species::Batfox => 10.0,
|
||||
quadruped_small::Species::Beaver => 10.0,
|
||||
quadruped_small::Species::Boar => 80.0, // ~✅ (60-100 kg)
|
||||
quadruped_small::Species::Dodarock => 150.0,
|
||||
quadruped_small::Species::Holladon => 150.0,
|
||||
quadruped_small::Species::Cat => 4.0, // ~✅ (4-5 kg)
|
||||
quadruped_small::Species::Dodarock => 70.0,
|
||||
quadruped_small::Species::Dog => 30.0, // ~✅ (German Shepherd: 30-40 kg)
|
||||
quadruped_small::Species::Fox => 10.0,
|
||||
quadruped_small::Species::Frog => 1.0,
|
||||
quadruped_small::Species::Fungome => 10.0,
|
||||
quadruped_small::Species::Gecko => 1.0,
|
||||
quadruped_small::Species::Goat => 50.0,
|
||||
quadruped_small::Species::Hare => 10.0,
|
||||
quadruped_small::Species::Holladon => 60.0,
|
||||
quadruped_small::Species::Hyena => 70.0, // ~✅ (vaguely)
|
||||
quadruped_small::Species::Truffler => 150.0,
|
||||
_ => 80.0,
|
||||
quadruped_small::Species::Jackalope => 10.0,
|
||||
quadruped_small::Species::Pig => 20.0,
|
||||
quadruped_small::Species::Porcupine => 5.0,
|
||||
quadruped_small::Species::Quokka => 10.0,
|
||||
quadruped_small::Species::Rabbit => 2.0,
|
||||
quadruped_small::Species::Raccoon => 30.0,
|
||||
quadruped_small::Species::Rat => 1.0,
|
||||
quadruped_small::Species::Sheep => 50.0,
|
||||
quadruped_small::Species::Skunk => 5.0,
|
||||
quadruped_small::Species::Squirrel => 1.0,
|
||||
quadruped_small::Species::Truffler => 70.0,
|
||||
quadruped_small::Species::Turtle => 40.0,
|
||||
},
|
||||
Body::Theropod(body) => match body.species {
|
||||
// for reference, elephants are in the range of 2.6-6.9 tons
|
||||
|
@ -349,7 +349,7 @@ impl Body {
|
||||
Body::BoltFire => Vec3::new(0.1, 0.1, 0.1),
|
||||
Body::Crossbow => Vec3::new(3.0, 3.0, 1.5),
|
||||
Body::HaniwaSentry => Vec3::new(0.8, 0.8, 1.4),
|
||||
_ => Vec3::broadcast(0.2),
|
||||
_ => Vec3::broadcast(0.5),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
body::{object, Body},
|
||||
CharacterState, Density, Ori, Vel,
|
||||
Density, Ori, Vel,
|
||||
};
|
||||
use crate::{
|
||||
consts::{AIR_DENSITY, WATER_DENSITY},
|
||||
@ -87,12 +87,22 @@ impl Default for Fluid {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Wings {
|
||||
Flying,
|
||||
Gliding {
|
||||
aspect_ratio: f32,
|
||||
planform_area: f32,
|
||||
ori: Ori,
|
||||
},
|
||||
Folded,
|
||||
}
|
||||
|
||||
impl Body {
|
||||
pub fn aerodynamic_forces(
|
||||
&self,
|
||||
rel_flow: &Vel,
|
||||
fluid_density: f32,
|
||||
character_state: Option<&CharacterState>,
|
||||
wings: Option<&Wings>,
|
||||
) -> Vec3<f32> {
|
||||
let v_sq = rel_flow.0.magnitude_squared();
|
||||
if v_sq < 0.25 {
|
||||
@ -103,22 +113,23 @@ impl Body {
|
||||
// All the coefficients come pre-multiplied by their reference area
|
||||
0.5 * fluid_density
|
||||
* v_sq
|
||||
* character_state
|
||||
.and_then(|cs| match cs {
|
||||
CharacterState::Glide(data) => {
|
||||
Some((data.aspect_ratio, data.planform_area, data.ori))
|
||||
},
|
||||
_ => None,
|
||||
})
|
||||
.map(|(ar, area, ori)| {
|
||||
if ar > 25.0 {
|
||||
* wings
|
||||
.and_then(|wings| match *wings {
|
||||
Wings::Gliding {
|
||||
aspect_ratio,
|
||||
planform_area,
|
||||
ori,
|
||||
} => {
|
||||
if aspect_ratio > 25.0 {
|
||||
tracing::warn!(
|
||||
"Calculating lift for wings with an aspect ratio of {}. The \
|
||||
formulas are only valid for aspect ratios below 25.",
|
||||
ar
|
||||
aspect_ratio
|
||||
)
|
||||
};
|
||||
(ar.min(24.0), area, ori)
|
||||
Some((aspect_ratio.min(24.0), planform_area, ori))
|
||||
},
|
||||
_ => None,
|
||||
})
|
||||
.map(|(ar, area, ori)| {
|
||||
// We have an elliptical wing; proceed to calculate its lift and drag
|
||||
@ -158,7 +169,7 @@ impl Body {
|
||||
let e = 1.78 * (1.0 - 0.045 * ar.powf(0.68)) - 0.64;
|
||||
|
||||
zero_lift_drag_coefficient(area)
|
||||
+ self.parasite_drag_coefficient()
|
||||
+ self.parasite_drag_coefficient(wings)
|
||||
+ c_l.powi(2) / (PI * e * ar)
|
||||
};
|
||||
debug_assert!(c_d.is_sign_positive());
|
||||
@ -166,7 +177,7 @@ impl Body {
|
||||
|
||||
c_l * *lift_dir + c_d * *rel_flow_dir
|
||||
})
|
||||
.unwrap_or_else(|| self.parasite_drag_coefficient() * *rel_flow_dir)
|
||||
.unwrap_or_else(|| self.parasite_drag_coefficient(wings) * *rel_flow_dir)
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +185,7 @@ impl Body {
|
||||
/// Skin friction is the drag arising from the shear forces between a fluid
|
||||
/// and a surface, while pressure drag is due to flow separation. Both are
|
||||
/// viscous effects.
|
||||
fn parasite_drag_coefficient(&self) -> f32 {
|
||||
fn parasite_drag_coefficient(&self, wings: Option<&Wings>) -> f32 {
|
||||
// Reference area and drag coefficient assumes best-case scenario of the
|
||||
// orientation producing least amount of drag
|
||||
match self {
|
||||
@ -201,12 +212,16 @@ impl Body {
|
||||
// Cross-section, zero-lift angle; exclude the wings (width * 0.2)
|
||||
Body::BirdMedium(_) | Body::BirdLarge(_) | Body::Dragon(_) => {
|
||||
let dim = self.dimensions().map(|a| a * 0.5);
|
||||
let cd = if matches!(wings, Some(Wings::Folded) | None) {
|
||||
0.7
|
||||
} else {
|
||||
// "Field Estimates of Body Drag Coefficient on the Basis of Dives in Passerine
|
||||
// Birds", Anders Hedenström and Felix Liechti, 2001
|
||||
let cd = match self {
|
||||
match self {
|
||||
Body::BirdLarge(_) | Body::BirdMedium(_) => 0.2,
|
||||
// arbitrary
|
||||
_ => 0.7,
|
||||
}
|
||||
};
|
||||
cd * PI * dim.x * 0.2 * dim.z
|
||||
},
|
||||
|
@ -1,14 +1,16 @@
|
||||
use common::{
|
||||
comp::{
|
||||
body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST},
|
||||
BeamSegment, Body, CharacterState, Collider, Density, Fluid, Mass, Mounting, Ori,
|
||||
PhysicsState, Pos, PosVelDefer, PreviousPhysCache, Projectile, Scale, Shockwave, Sticky,
|
||||
Vel,
|
||||
fluid_dynamics::{Fluid, Wings},
|
||||
BeamSegment, Body, CharacterState, Collider, Controller, Density, InputKind, Mass,
|
||||
Mounting, Ori, PhysicsState, Pos, PosVelDefer, PreviousPhysCache, Projectile, Scale,
|
||||
Shockwave, Sticky, Vel,
|
||||
},
|
||||
consts::{AIR_DENSITY, FRIC_GROUND, GRAVITY},
|
||||
event::{EventBus, ServerEvent},
|
||||
outcome::Outcome,
|
||||
resources::DeltaTime,
|
||||
states,
|
||||
terrain::{Block, TerrainGrid},
|
||||
uid::Uid,
|
||||
util::{Projection, SpatialGrid},
|
||||
@ -38,14 +40,44 @@ fn fluid_density(height: f32, fluid: &Fluid) -> Density {
|
||||
Density(fluid.density().0 * immersion + AIR_DENSITY * (1.0 - immersion))
|
||||
}
|
||||
|
||||
fn get_wings(
|
||||
character_state: Option<&CharacterState>,
|
||||
controller: Option<&Controller>,
|
||||
body: &Body,
|
||||
) -> Option<Wings> {
|
||||
match *character_state? {
|
||||
CharacterState::Glide(states::glide::Data {
|
||||
aspect_ratio,
|
||||
planform_area,
|
||||
ori,
|
||||
..
|
||||
}) => Some(Wings::Gliding {
|
||||
aspect_ratio,
|
||||
planform_area,
|
||||
ori,
|
||||
}),
|
||||
|
||||
_ => {
|
||||
if body.fly_thrust().is_some() {
|
||||
if controller?.queued_inputs.contains_key(&InputKind::Fly) {
|
||||
Some(Wings::Flying)
|
||||
} else {
|
||||
Some(Wings::Folded)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn integrate_forces(
|
||||
dt: &DeltaTime,
|
||||
mut vel: Vel,
|
||||
body: &Body,
|
||||
(body, wings): (&Body, Option<&Wings>),
|
||||
density: &Density,
|
||||
mass: &Mass,
|
||||
character_state: Option<&CharacterState>,
|
||||
fluid: &Fluid,
|
||||
gravity: f32,
|
||||
) -> Vel {
|
||||
@ -59,7 +91,7 @@ fn integrate_forces(
|
||||
// Aerodynamic/hydrodynamic forces
|
||||
if !rel_flow.0.is_approx_zero() {
|
||||
debug_assert!(!rel_flow.0.map(|a| a.is_nan()).reduce_or());
|
||||
let impulse = dt.0 * body.aerodynamic_forces(&rel_flow, fluid_density.0, character_state);
|
||||
let impulse = dt.0 * body.aerodynamic_forces(&rel_flow, fluid_density.0, wings);
|
||||
debug_assert!(!impulse.map(|a| a.is_nan()).reduce_or());
|
||||
if !impulse.is_approx_zero() {
|
||||
let new_v = vel.0 + impulse / mass.0;
|
||||
@ -116,6 +148,7 @@ pub struct PhysicsRead<'a> {
|
||||
stickies: ReadStorage<'a, Sticky>,
|
||||
masses: ReadStorage<'a, Mass>,
|
||||
colliders: ReadStorage<'a, Collider>,
|
||||
controllers: ReadStorage<'a, Controller>,
|
||||
mountings: ReadStorage<'a, Mounting>,
|
||||
projectiles: ReadStorage<'a, Projectile>,
|
||||
beams: ReadStorage<'a, BeamSegment>,
|
||||
@ -574,6 +607,7 @@ impl<'a> PhysicsData<'a> {
|
||||
&read.bodies,
|
||||
read.character_states.maybe(),
|
||||
&write.physics_states,
|
||||
read.controllers.maybe(),
|
||||
&read.masses,
|
||||
&read.densities,
|
||||
!&read.mountings,
|
||||
@ -592,6 +626,7 @@ impl<'a> PhysicsData<'a> {
|
||||
body,
|
||||
character_state,
|
||||
physics_state,
|
||||
controller,
|
||||
mass,
|
||||
density,
|
||||
_,
|
||||
@ -616,13 +651,13 @@ impl<'a> PhysicsData<'a> {
|
||||
vel.0.z -= dt.0 * GRAVITY;
|
||||
},
|
||||
Some(fluid) => {
|
||||
let wings = get_wings(character_state, controller, body);
|
||||
vel.0 = integrate_forces(
|
||||
&dt,
|
||||
*vel,
|
||||
body,
|
||||
(body, wings.as_ref()),
|
||||
density,
|
||||
mass,
|
||||
character_state,
|
||||
&fluid,
|
||||
GRAVITY,
|
||||
)
|
||||
|
@ -79,6 +79,11 @@ pub fn handle_knockback(server: &Server, entity: EcsEntity, impulse: Vec3<f32>)
|
||||
if let Some(vel) = velocities.get_mut(entity) {
|
||||
vel.0 += impulse;
|
||||
}
|
||||
if let Some(controller) = ecs.write_storage::<comp::Controller>().get_mut(entity) {
|
||||
controller
|
||||
.actions
|
||||
.push(comp::ControlAction::CancelInput(comp::InputKind::Fly));
|
||||
}
|
||||
if let Some(client) = clients.get(entity) {
|
||||
client.send_fallible(ServerGeneral::Knockback(impulse));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user