#[repr(C, align(16))]pub struct Wheel3D {Show 26 fields
pub position: Vec3,
pub radius: f32,
pub mass: f32,
pub suspension_distance: f32,
pub spring: f32,
pub damper: f32,
pub target_position: f32,
pub force_app_point_distance: f32,
pub damping_rate: f32,
pub forward_friction: FrictionCurve,
pub sideways_friction: FrictionCurve,
pub motor_torque: f32,
pub brake_torque: f32,
pub steer_angle: f32,
pub local_rotation: Quat,
pub grounded: bool,
pub contact_point: Vec3,
pub contact_normal: Vec3,
pub compression: f32,
pub suspension_force: f32,
pub sprung_mass: f32,
pub angular_velocity: f32,
pub forward_slip: f32,
pub sideways_slip: f32,
pub spin: f32,
pub local_position: Vec3,
}Expand description
One wheel of a Vehicle3D: where it’s mounted, its suspension and
tyres (set these up once), what drives it this tick (yours to set), and
what happened to it in the last physics step (read after the step).
The suspension hangs straight down from position
along the chassis’s -Y: at full compression the wheel’s center is at
position, fully extended it’s suspension_distance
lower. Under the car’s weight it rests at
target_position of that travel.
use ponko::*;
// Front left wheel of a car whose chassis faces -Z.
let mut wheel = Wheel3D::new(vec3(-0.8, -0.2, -1.3), 0.35);
wheel.spring = 40_000.0;
wheel.sideways_friction.stiffness = 1.2;
// Each tick:
wheel.motor_torque = 300.0;
wheel.steer_angle = 0.3; // right
assert!(!wheel.grounded);Fields§
§position: Vec3Where the wheel’s center is at full compression, in the chassis’s
frame (relative to its Transform3D position).
radius: f32The wheel’s radius in meters. Default 0.5.
mass: f32The wheel’s mass in kg, which sets how fast torque spins it up. Default 20.
suspension_distance: f32How far the suspension travels, meters. Default 0.3.
spring: f32The suspension’s spring rate, N/m. Default 35 000.
damper: f32The suspension’s damper rate, N·s/m. Default 4 500.
target_position: f32Where the suspension rests under the car’s weight: 0 fully compressed, 1 fully extended. Default 0.5.
force_app_point_distance: f32Where the suspension and tyre forces act: this far up the suspension from the bottom of the resting wheel. 0 (the default) at the tyre’s contact; near the center of mass rolls less.
damping_rate: f32Slows the wheel’s spin by this many N·m per rad/s (rolling resistance, bearings). Default 0.25.
forward_friction: FrictionCurveGrip along the wheel’s rolling direction.
sideways_friction: FrictionCurveGrip across it.
motor_torque: f32Drive torque, N·m: positive rolls forward (the chassis’s -Z).
brake_torque: f32Brake torque, N·m (positive): slows the wheel’s spin to a stop.
steer_angle: f32Steering, radians around the chassis’s up axis: positive steers right (clockwise seen from above).
local_rotation: QuatThe wheel’s turn relative to the chassis (steer, then spin): for
drawing it, with local_position or
pose.
grounded: boolTouches the ground.
contact_point: Vec3Where the tyre touches the ground (when grounded).
contact_normal: Vec3The ground’s outward direction there (when grounded).
compression: f32How far the suspension is pushed in from full extension, meters
(0 in the air, suspension_distance bottomed out).
suspension_force: f32The suspension’s push, newtons: the load on the tyre.
sprung_mass: f32The share of the chassis’s mass this wheel carries, kg.
angular_velocity: f32How fast the wheel spins, rad/s: positive rolls forward. See rpm.
forward_slip: f32Forward slip (see FrictionCurve).
sideways_slip: f32Sideways slip, radians: positive slides to the wheel’s right.
spin: f32How far the wheel has turned, radians (0..2π), for drawing.
local_position: Vec3The wheel’s center in the chassis’s frame, suspension travel included: for drawing it.
Implementations§
Source§impl Wheel3D
impl Wheel3D
Sourcepub fn new(position: Vec3, radius: f32) -> Self
pub fn new(position: Vec3, radius: f32) -> Self
A wheel of radius mounted at position (its center at full
compression, in the chassis’s frame), with the usual suspension and
tyres.
Examples found in repository?
41fn spawn_car(ctx: &mut Ctx, at: Vec3) -> Entity {
42 let mut car = Vehicle3D::new();
43 for (x, z) in [(-0.8, -1.3), (0.8, -1.3), (-0.8, 1.3), (0.8, 1.3)] {
44 let mut wheel = Wheel3D::new(vec3(x, -0.3, z), 0.35);
45 wheel.sideways_friction.stiffness = 1.3;
46 car = car.with_wheel(wheel);
47 }
48 ctx.world.spawn((
49 Transform3D::at(at),
50 RigidBody3D::dynamic()
51 .mass(1200.0)
52 .center_of_mass(vec3(0.0, -0.35, 0.0)),
53 Collider3D::cuboid(vec3(1.8, 0.6, 4.2)),
54 Velocity3D::default(),
55 car,
56 ))
57}Sourcepub fn rpm(&self) -> f32
pub fn rpm(&self) -> f32
How fast the wheel spins, in revolutions per minute.
use ponko::*;
let mut wheel = Wheel3D::new(Vec3::ZERO, 0.3);
wheel.angular_velocity = std::f32::consts::TAU; // one turn a second
assert!((wheel.rpm() - 60.0).abs() < 1e-3);Sourcepub fn pose(&self, chassis: &Transform3D) -> Transform3D
pub fn pose(&self, chassis: &Transform3D) -> Transform3D
Where to draw the wheel for a chassis at chassis: its center,
with steer, spin and suspension travel. Pass the chassis’s
Transform3D in a frame system and the wheel moves as smoothly as
the chassis does.
use ponko::*;
let wheel = Wheel3D::new(vec3(1.0, 0.0, 0.0), 0.4);
let pose = wheel.pose(&Transform3D::at(vec3(0.0, 2.0, 0.0)));
// Hanging fully extended: 0.3 m below its mount.
assert!((pose.position - vec3(1.0, 1.7, 0.0)).length() < 1e-5);Examples found in repository?
130fn place_wheels(ctx: &mut Ctx) {
131 let player = ctx.world.resource::<Player>();
132 let car = player.car;
133 let (Some(&vehicle), Some(&chassis)) = (ctx.world.get::<Vehicle3D>(car), ctx.world.get::<Transform3D>(car)) else {
134 return;
135 };
136 for i in 0..player.wheels.len() {
137 let e = ctx.world.resource::<Player>().wheels[i];
138 let pose = vehicle.wheels()[i].pose(&chassis);
139 if let Some(t) = ctx.world.get_mut::<Transform3D>(e) {
140 *t = Transform3D { scale: t.scale, ..pose };
141 }
142 }
143}Trait Implementations§
impl Copy for Wheel3D
Source§impl<'de> Deserialize<'de> for Wheel3D
impl<'de> Deserialize<'de> for Wheel3D
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl StructuralPartialEq for Wheel3D
Auto Trait Implementations§
impl Forget for Wheel3D
impl Freeze for Wheel3D
impl RefUnwindSafe for Wheel3D
impl Send for Wheel3D
impl Sync for Wheel3D
impl Unpin for Wheel3D
impl UnsafeUnpin for Wheel3D
impl UnwindSafe for Wheel3D
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> Component for T
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
impl<T> MaybeSync for T
impl<T> MaybeSync for T
Source§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
Source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian().impl<T> Scalar for T
impl<T> SerializableAny for T
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.