I guess it makes more sense with all-quadratic drag
parent
ae19b8bb93
commit
754fd681c0
|
@ -60,15 +60,25 @@ impl EulerAngles {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Use iota macro
|
||||
const KEY_LEFT: usize = 0;
|
||||
const KEY_RIGHT: usize = KEY_LEFT + 1;
|
||||
const KEY_UP: usize = KEY_RIGHT + 1;
|
||||
const KEY_DOWN: usize = KEY_UP + 1;
|
||||
mod keys {
|
||||
use iota::iota;
|
||||
iota! {
|
||||
pub const
|
||||
KEY_LEFT: usize = iota;
|
||||
, KEY_RIGHT
|
||||
, KEY_UP
|
||||
, KEY_DOWN
|
||||
, YAW_LEFT
|
||||
, YAW_RIGHT
|
||||
}
|
||||
}
|
||||
|
||||
struct ControllerState {
|
||||
keys: Vec <bool>,
|
||||
|
||||
analog_left_x: i16,
|
||||
analog_left_y: i16,
|
||||
|
||||
trigger_left: i16,
|
||||
trigger_right: i16,
|
||||
}
|
||||
|
@ -87,6 +97,7 @@ impl ControllerState {
|
|||
};
|
||||
|
||||
let key_or_gamepad = |key, button| f (key) || b (button);
|
||||
let axis_or_zero = |a| c.as_ref ().map_or (0, |c| c.axis (a));
|
||||
|
||||
Self {
|
||||
keys: vec! [
|
||||
|
@ -95,14 +106,10 @@ impl ControllerState {
|
|||
key_or_gamepad (Scancode::Up, Button::DPadUp),
|
||||
key_or_gamepad (Scancode::Down, Button::DPadDown),
|
||||
],
|
||||
trigger_left: match c {
|
||||
None => 0,
|
||||
Some (c) => c.axis (Axis::TriggerLeft),
|
||||
},
|
||||
trigger_right: match c {
|
||||
None => 0,
|
||||
Some (c) => c.axis (Axis::TriggerRight),
|
||||
},
|
||||
analog_left_x: axis_or_zero (Axis::LeftX),
|
||||
analog_left_y: axis_or_zero (Axis::LeftY),
|
||||
trigger_left: axis_or_zero (Axis::TriggerLeft),
|
||||
trigger_right: axis_or_zero (Axis::TriggerRight),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,6 +123,7 @@ impl ControllerState {
|
|||
spin_speed: i32
|
||||
) -> i32
|
||||
{
|
||||
use keys::*;
|
||||
const SPIN_RAMP_TIME: i32 = 30;
|
||||
let spin_f = 4.0 * spin_speed as f32 / SPIN_RAMP_TIME as f32;
|
||||
|
||||
|
@ -144,6 +152,7 @@ impl ControllerState {
|
|||
spin_speed: i32
|
||||
) -> i32
|
||||
{
|
||||
use keys::*;
|
||||
const SPIN_RAMP_TIME: i32 = 30;
|
||||
let spin_f = 2.0 * (spin_speed + 1) as f32 / SPIN_RAMP_TIME as f32;
|
||||
let spin_f = spin_f.to_radians ();
|
||||
|
@ -166,6 +175,12 @@ impl ControllerState {
|
|||
//println! ("spin_f {}, Quat {:?}", spin_f, delta);
|
||||
|
||||
if delta == Quat::default () {
|
||||
let analog_scale = 1.0f32.to_radians () / 32768.0;
|
||||
|
||||
delta = delta.mul_quat (Quat::from_rotation_y (self.analog_left_x as f32 * analog_scale));
|
||||
delta = delta.mul_quat (Quat::from_rotation_x (self.analog_left_y as f32 * analog_scale));
|
||||
|
||||
*controlled_quat = (controlled_quat.mul_quat (delta)).normalize ();
|
||||
0
|
||||
}
|
||||
else {
|
||||
|
@ -207,17 +222,19 @@ struct Airplane {
|
|||
struct FlightState {
|
||||
airplane: Airplane,
|
||||
spin_speed: i32,
|
||||
arrows: Vec <Arrow>,
|
||||
}
|
||||
|
||||
impl Default for FlightState {
|
||||
fn default () -> Self {
|
||||
Self {
|
||||
airplane: Airplane {
|
||||
pos: (0.0, -10.0, 20.0).into (),
|
||||
pos: (0.0, -20.0, 20.0).into (),
|
||||
vel: (0.0, 0.0, 0.0).into (),
|
||||
ori: Default::default (),
|
||||
},
|
||||
spin_speed: 0,
|
||||
arrows: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -230,54 +247,86 @@ impl FlightState {
|
|||
pub fn step (&mut self, controller: &ControllerState) {
|
||||
self.spin_speed = controller.control_quat (&mut self.airplane.ori, self.spin_speed);
|
||||
|
||||
let airplane = &mut self.airplane;
|
||||
// Info
|
||||
let nose = airplane.ori.mul_vec3 ((0.0, 1.0, 0.0).into ());
|
||||
let speed = airplane.vel.length ();
|
||||
// Different from nose since planes are always drifting
|
||||
let direction = if speed == 0.0 {
|
||||
Vec3::from ((0.0, 0.0, 0.0))
|
||||
}
|
||||
else {
|
||||
airplane.vel * (1.0 / speed)
|
||||
};
|
||||
|
||||
let object_space_dir = airplane.ori.conjugate ().mul_vec3 (direction);
|
||||
|
||||
let throttle = 1.0 + (controller.trigger_right as f32 - controller.trigger_left as f32) / 32767.0;
|
||||
|
||||
// Forces
|
||||
let gravity = Vec3::from ((0.0, 0.0, -0.25));
|
||||
let thrust = nose * throttle;
|
||||
let laminar_drag = 0.25 * speed * -object_space_dir.y () * nose;
|
||||
let airplane = &mut self.airplane;
|
||||
|
||||
let turbulent_dir = Vec3::from ((0.5 * object_space_dir.x (), 0.0, object_space_dir.z ()));
|
||||
let turbulent_drag = -speed * speed * airplane.ori.mul_vec3 (turbulent_dir);
|
||||
let microsteps = 4;
|
||||
|
||||
let air_drag = laminar_drag + turbulent_drag;
|
||||
for microstep in 0..microsteps {
|
||||
// Info
|
||||
let nose = airplane.ori.mul_vec3 ((0.0, 1.0, 0.0).into ());
|
||||
let speed = airplane.vel.length ();
|
||||
// Different from nose since planes are always drifting
|
||||
let direction = if speed == 0.0 {
|
||||
Vec3::from ((0.0, 0.0, 0.0))
|
||||
}
|
||||
else {
|
||||
airplane.vel * (1.0 / speed)
|
||||
};
|
||||
|
||||
// Accumulate forces and run an Euler integration step
|
||||
let dt = 1.0 / 60.0;
|
||||
airplane.vel += dt * (thrust + gravity + air_drag);
|
||||
airplane.pos += dt * airplane.vel;
|
||||
let inverse_ori = airplane.ori.conjugate ();
|
||||
let object_space_dir = inverse_ori.mul_vec3 (direction);
|
||||
|
||||
if airplane.pos.z () < 0.0 {
|
||||
airplane.vel.set_z (0.0);
|
||||
airplane.pos.set_z (0.0);
|
||||
// Forces
|
||||
let gravity = Vec3::from ((0.0, 0.0, -0.25));
|
||||
let thrust = 0.125 * nose * throttle;
|
||||
let linear_drag = 0.0 * 0.25 * speed * -object_space_dir.y () * nose;
|
||||
|
||||
let turbulent_dir = Vec3::from ((-1.0 * object_space_dir.x (), -0.03125 * object_space_dir.y (), -16.0 * object_space_dir.z ()));
|
||||
let quadratic_drag = speed * speed * airplane.ori.mul_vec3 (turbulent_dir);
|
||||
|
||||
let air_drag = linear_drag + quadratic_drag;
|
||||
|
||||
// Accumulate forces and run an Euler integration step
|
||||
let dt = 1.0 / 60.0 / microsteps as f32;
|
||||
airplane.vel += dt * (thrust + gravity + air_drag);
|
||||
airplane.pos += dt * airplane.vel;
|
||||
|
||||
if airplane.pos.z () < 0.0 {
|
||||
airplane.vel.set_z (0.0);
|
||||
airplane.pos.set_z (0.0);
|
||||
}
|
||||
|
||||
if microstep == microsteps - 1 {
|
||||
let make_arrow = |direction, color| Arrow {
|
||||
origin: airplane.pos.clone (),
|
||||
direction: direction * 0.125,
|
||||
color,
|
||||
};
|
||||
|
||||
self.arrows = vec! [
|
||||
make_arrow (gravity, color_from_255 ((128.0, 128.0, 128.0))),
|
||||
make_arrow (thrust, color_from_255 ((255.0, 128.0, 0.0))),
|
||||
make_arrow (linear_drag, color_from_255 ((128.0, 128.0, 128.0))),
|
||||
make_arrow (quadratic_drag, color_from_255 ((0.0, 255.0, 255.0))),
|
||||
];
|
||||
|
||||
// Gauges
|
||||
let alti = airplane.pos.z () * 100.0;
|
||||
let sink_rate = -airplane.vel.z () * 100.0;
|
||||
let air_speed = speed * 100.0;
|
||||
let ground_vel = Vec3::from ((airplane.vel.x (), airplane.vel.y (), 0.0));
|
||||
let ground_speed = ground_vel.length () * 100.0;
|
||||
let glide_ratio = if sink_rate > 1.0 && throttle == 0.0 {
|
||||
Some (ground_speed / sink_rate)
|
||||
}
|
||||
else {
|
||||
None
|
||||
};
|
||||
|
||||
println! ("Alti: {}, Airspeed: {}, Groundspeed: {}, Throttle: {}, Sink Rate: {}, Glide Ratio: {:?}\nLaminar: {}, Turbulent: {}",
|
||||
alti as i32,
|
||||
air_speed as i32,
|
||||
ground_speed as i32,
|
||||
(throttle * 100.0) as i32,
|
||||
sink_rate as i32,
|
||||
glide_ratio,
|
||||
(linear_drag.length () * 100.0) as i32,
|
||||
(quadratic_drag.length () * 100.0) as i32
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Gauges
|
||||
let alti = airplane.pos.z () * 100.0;
|
||||
let air_speed = speed * 100.0;
|
||||
let ground_vel = Vec3::from ((airplane.vel.x (), airplane.vel.y (), 0.0));
|
||||
let ground_speed = ground_vel.length () * 100.0;
|
||||
|
||||
println! ("Alti: {}, Airspeed: {}, Groundspeed: {}, Throttle: {}",
|
||||
alti as i32,
|
||||
air_speed as i32,
|
||||
ground_speed as i32,
|
||||
(throttle * 100.0) as i32
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,6 +437,7 @@ fn make_object_space_vec (inverse_model_mat: &Mat4, world_space_vec: &Vec3)
|
|||
Vec3::from ((v4.x (), v4.y (), v4.z ()))
|
||||
}
|
||||
|
||||
#[derive (Clone)]
|
||||
struct Arrow {
|
||||
origin: Vec3,
|
||||
direction: Vec3,
|
||||
|
@ -667,7 +717,7 @@ impl GameGraphics {
|
|||
flags: hashmap! {
|
||||
gl::CULL_FACE => true,
|
||||
gl::DEPTH_TEST => true,
|
||||
gl::TEXTURE_2D => true,
|
||||
gl::TEXTURE_2D => false,
|
||||
gl::STENCIL_TEST => false,
|
||||
},
|
||||
front_face: Some (FrontFace::Cw),
|
||||
|
@ -911,7 +961,7 @@ impl GameGraphics {
|
|||
let unis = &shader_vars.unis;
|
||||
|
||||
glezz::uniform_3fv (unis [&MIN_BRIGHT], &black);
|
||||
glezz::uniform_3fv (unis [&MIN_ALBEDO], &black);
|
||||
glezz::uniform_3fv (unis [&MIN_ALBEDO], &white);
|
||||
|
||||
for arrow in arrows.iter () {
|
||||
let mvp = view_mat * arrow.model_mat;
|
||||
|
@ -1036,7 +1086,7 @@ fn main () {
|
|||
}
|
||||
]
|
||||
},
|
||||
_ => vec![],
|
||||
PlayMode::FreeFlight => state.flight.arrows.clone (),
|
||||
};
|
||||
|
||||
let renderable_arrows: Vec <_> = arrows.iter ().map (|arrow| {
|
||||
|
|
Loading…
Reference in New Issue