mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Correctly scale glider physics
This commit is contained in:
parent
df63e41a23
commit
587996abb7
@ -730,7 +730,7 @@ impl ServerChatCommand {
|
||||
cmd(vec![], "Lightning strike at current position", Some(Admin))
|
||||
},
|
||||
ServerChatCommand::Scale => {
|
||||
cmd(vec![Float("factor", 1.0, Required)], "Scale your character", Some(Admin))
|
||||
cmd(vec![Float("factor", 1.0, Required), Boolean("reset_mass", true.to_string(), Optional)], "Scale your character", Some(Admin))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -135,6 +135,7 @@ impl Body {
|
||||
rel_flow: &Vel,
|
||||
fluid_density: f32,
|
||||
wings: Option<&Wings>,
|
||||
scale: f32,
|
||||
) -> Vec3<f32> {
|
||||
let v_sq = rel_flow.0.magnitude_squared();
|
||||
if v_sq < 0.25 {
|
||||
@ -201,11 +202,11 @@ impl Body {
|
||||
debug_assert!(c_d.is_sign_positive());
|
||||
debug_assert!(c_l.is_sign_positive() || aoa.is_sign_negative());
|
||||
|
||||
planform_area * (c_l * *lift_dir + c_d * *rel_flow_dir)
|
||||
+ self.parasite_drag() * *rel_flow_dir
|
||||
planform_area * scale.powf(2.0) * (c_l * *lift_dir + c_d * *rel_flow_dir)
|
||||
+ self.parasite_drag(scale) * *rel_flow_dir
|
||||
},
|
||||
|
||||
_ => self.parasite_drag() * *rel_flow_dir,
|
||||
_ => self.parasite_drag(scale) * *rel_flow_dir,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,13 +215,13 @@ 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(&self) -> f32 {
|
||||
fn parasite_drag(&self, scale: f32) -> f32 {
|
||||
// Reference area and drag coefficient assumes best-case scenario of the
|
||||
// orientation producing least amount of drag
|
||||
match self {
|
||||
// Cross-section, head/feet first
|
||||
Body::BipedLarge(_) | Body::BipedSmall(_) | Body::Golem(_) | Body::Humanoid(_) => {
|
||||
let dim = self.dimensions().xy().map(|a| a * 0.5);
|
||||
let dim = self.dimensions().xy().map(|a| a * 0.5 * scale);
|
||||
const CD: f32 = 0.7;
|
||||
CD * PI * dim.x * dim.y
|
||||
},
|
||||
@ -231,7 +232,7 @@ impl Body {
|
||||
| Body::QuadrupedSmall(_)
|
||||
| Body::QuadrupedLow(_)
|
||||
| Body::Arthropod(_) => {
|
||||
let dim = self.dimensions().map(|a| a * 0.5);
|
||||
let dim = self.dimensions().map(|a| a * 0.5 * scale);
|
||||
let cd: f32 = if matches!(self, Body::QuadrupedLow(_)) {
|
||||
0.7
|
||||
} else {
|
||||
@ -242,7 +243,7 @@ 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 dim = self.dimensions().map(|a| a * 0.5 * scale);
|
||||
let cd: f32 = match self {
|
||||
// "Field Estimates of Body Drag Coefficient
|
||||
// on the Basis of Dives in Passerine Birds",
|
||||
@ -256,7 +257,7 @@ impl Body {
|
||||
|
||||
// Cross-section, zero-lift angle; exclude the fins (width * 0.2)
|
||||
Body::FishMedium(_) | Body::FishSmall(_) => {
|
||||
let dim = self.dimensions().map(|a| a * 0.5);
|
||||
let dim = self.dimensions().map(|a| a * 0.5 * scale);
|
||||
// "A Simple Method to Determine Drag Coefficients in Aquatic Animals",
|
||||
// D. Bilo and W. Nachtigall, 1980
|
||||
const CD: f32 = 0.031;
|
||||
@ -276,7 +277,7 @@ impl Body {
|
||||
| object::Body::FireworkYellow
|
||||
| object::Body::MultiArrow
|
||||
| object::Body::Dart => {
|
||||
let dim = self.dimensions().map(|a| a * 0.5);
|
||||
let dim = self.dimensions().map(|a| a * 0.5 * scale);
|
||||
const CD: f32 = 0.02;
|
||||
CD * PI * dim.x * dim.z
|
||||
},
|
||||
@ -295,20 +296,20 @@ impl Body {
|
||||
| object::Body::Pumpkin3
|
||||
| object::Body::Pumpkin4
|
||||
| object::Body::Pumpkin5 => {
|
||||
let dim = self.dimensions().map(|a| a * 0.5);
|
||||
let dim = self.dimensions().map(|a| a * 0.5 * scale);
|
||||
const CD: f32 = 0.5;
|
||||
CD * PI * dim.x * dim.z
|
||||
},
|
||||
|
||||
_ => {
|
||||
let dim = self.dimensions();
|
||||
let dim = self.dimensions().map(|a| a * scale);
|
||||
const CD: f32 = 2.0;
|
||||
CD * (PI / 6.0 * dim.x * dim.y * dim.z).powf(2.0 / 3.0)
|
||||
},
|
||||
},
|
||||
|
||||
Body::ItemDrop(_) => {
|
||||
let dim = self.dimensions();
|
||||
let dim = self.dimensions().map(|a| a * scale);
|
||||
const CD: f32 = 2.0;
|
||||
CD * (PI / 6.0 * dim.x * dim.y * dim.z).powf(2.0 / 3.0)
|
||||
},
|
||||
@ -316,7 +317,7 @@ impl Body {
|
||||
Body::Ship(_) => {
|
||||
// Airships tend to use the square of the cube root of its volume for
|
||||
// reference area
|
||||
let dim = self.dimensions();
|
||||
let dim = self.dimensions().map(|a| a * scale);
|
||||
(PI / 6.0 * dim.x * dim.y * dim.z).powf(2.0 / 3.0)
|
||||
},
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ impl CharacterBehavior for Data {
|
||||
// They've climbed atop something, give them a boost
|
||||
output_events.emit_local(LocalEvent::Jump(
|
||||
data.entity,
|
||||
CLIMB_BOOST_JUMP_FACTOR * impulse / data.mass.0,
|
||||
CLIMB_BOOST_JUMP_FACTOR * impulse / data.mass.0 * data.scale.map_or(1.0, |s| s.0.powf(13.0).powf(0.25)),
|
||||
));
|
||||
};
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
|
@ -1075,7 +1075,7 @@ pub fn handle_jump(
|
||||
output_events.emit_local(LocalEvent::Jump(
|
||||
data.entity,
|
||||
strength * impulse / data.mass.0
|
||||
* data.scale.map_or(1.0, |s| s.0.powf(0.25))
|
||||
* data.scale.map_or(1.0, |s| s.0.powf(13.0).powf(0.25))
|
||||
* data.stats.move_speed_modifier,
|
||||
));
|
||||
})
|
||||
|
@ -50,6 +50,7 @@ fn integrate_forces(
|
||||
mass: &Mass,
|
||||
fluid: &Fluid,
|
||||
gravity: f32,
|
||||
scale: Option<Scale>,
|
||||
) -> Vel {
|
||||
let dim = body.dimensions();
|
||||
let height = dim.z;
|
||||
@ -61,7 +62,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, wings);
|
||||
let impulse = dt.0 * body.aerodynamic_forces(&rel_flow, fluid_density.0, wings, scale.map_or(1.0, |s| s.0));
|
||||
debug_assert!(!impulse.map(|a| a.is_nan()).reduce_or());
|
||||
if !impulse.is_approx_zero() {
|
||||
let new_v = vel.0 + impulse / mass.0;
|
||||
@ -610,6 +611,7 @@ impl<'a> PhysicsData<'a> {
|
||||
&write.physics_states,
|
||||
&read.masses,
|
||||
&read.densities,
|
||||
read.scales.maybe(),
|
||||
!&read.is_ridings,
|
||||
)
|
||||
.par_join()
|
||||
@ -628,6 +630,7 @@ impl<'a> PhysicsData<'a> {
|
||||
physics_state,
|
||||
mass,
|
||||
density,
|
||||
scale,
|
||||
_,
|
||||
)| {
|
||||
let in_loaded_chunk = read
|
||||
@ -672,6 +675,7 @@ impl<'a> PhysicsData<'a> {
|
||||
mass,
|
||||
&fluid,
|
||||
GRAVITY,
|
||||
scale.copied(),
|
||||
)
|
||||
.0
|
||||
},
|
||||
@ -1438,7 +1442,8 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
||||
|
||||
// Don't jump too far at once
|
||||
const MAX_INCREMENTS: usize = 100; // The maximum number of collision tests per tick
|
||||
let increments = ((pos_delta.map(|e| e.abs()).reduce_partial_max() / 0.3).ceil() as usize)
|
||||
let min_step = (radius / 2.0).min(z_max - z_min).clamped(0.01, 0.3);
|
||||
let increments = ((pos_delta.map(|e| e.abs()).reduce_partial_max() / min_step).ceil() as usize)
|
||||
.clamped(1, MAX_INCREMENTS);
|
||||
let old_pos = pos.0;
|
||||
for _ in 0..increments {
|
||||
|
@ -1228,6 +1228,7 @@ fn handle_spawn(
|
||||
)
|
||||
.with(comp::Vel(vel))
|
||||
.with(opt_scale.map(comp::Scale).unwrap_or(body.scale()))
|
||||
.maybe_with(opt_scale.map(|s| comp::Mass(body.mass().0 * s.powi(3))))
|
||||
.with(alignment);
|
||||
|
||||
if ai {
|
||||
@ -3844,13 +3845,27 @@ fn handle_scale(
|
||||
args: Vec<String>,
|
||||
action: &ServerChatCommand,
|
||||
) -> CmdResult<()> {
|
||||
if let Some(scale) = parse_cmd_args!(args, f32) {
|
||||
if let (Some(scale), reset_mass) = parse_cmd_args!(args, f32, bool) {
|
||||
let scale = scale.clamped(0.025, 1000.0);
|
||||
let _ = server
|
||||
.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Scale>()
|
||||
.insert(target, comp::Scale(scale));
|
||||
if reset_mass.unwrap_or(true) {
|
||||
if let Some(body) = server
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<comp::Body>()
|
||||
.get(target)
|
||||
{
|
||||
let _ = server
|
||||
.state
|
||||
.ecs()
|
||||
.write_storage()
|
||||
.insert(target, comp::Mass(body.mass().0 * scale.powi(3)));
|
||||
}
|
||||
}
|
||||
server.notify_client(
|
||||
client,
|
||||
ServerGeneral::server_msg(ChatType::CommandInfo, format!("Set scale to {}", scale)),
|
||||
|
@ -709,7 +709,7 @@ impl Server {
|
||||
if old_block.get_rtsim_resource().is_some() || new_block.get_rtsim_resource().is_some() {
|
||||
ecs.write_resource::<rtsim2::RtSim>().hook_block_update(
|
||||
&ecs.read_resource::<Arc<world::World>>(),
|
||||
ecs.read_resource::<Arc<world::IndexOwned>>().as_index_ref(),
|
||||
ecs.read_resource::<world::IndexOwned>().as_index_ref(),
|
||||
wpos,
|
||||
old_block,
|
||||
new_block,
|
||||
|
Loading…
Reference in New Issue
Block a user