use std::ops::{Deref, DerefMut};
use glam::{Mat3A, Vec3A};
use crate::{CarControls, PhysState, RaycastHitInfo, consts};
#[derive(Clone, Copy, Debug)]
pub struct CarState {
pub phys: PhysState,
pub controls: CarControls,
pub prev_controls: CarControls,
pub is_on_ground: bool,
pub wheels_with_contact: [Option<RaycastHitInfo>; 4],
pub has_jumped: bool,
pub has_double_jumped: bool,
pub has_flipped: bool,
pub flip_rel_torque: Vec3A,
pub jump_ticks: u32,
pub flip_time: f32,
pub is_flipping: bool,
pub is_jumping: bool,
pub air_time: f32,
pub air_time_since_jump: f32,
pub boost: f32,
pub time_since_boosted: f32,
pub is_boosting: bool,
pub boosting_time: f32,
pub is_supersonic: bool,
pub supersonic_grace_timer: f32,
pub handbrake_val: f32,
pub is_auto_flipping: bool,
pub auto_flip_timer: f32,
pub auto_flip_torque_scale: f32,
pub bump_cooldown_timer: f32,
pub last_extra_hit_tick: Option<u64>,
pub world_contact_normal: Option<Vec3A>,
pub is_demoed: bool,
pub demo_respawn_timer: f32,
}
impl Default for CarState {
fn default() -> Self {
Self::DEFAULT
}
}
impl CarState {
pub const DEFAULT: Self = Self {
phys: PhysState {
pos: Vec3A::new(0.0, 0.0, consts::car::spawn::REST_Z),
rot_mat: Mat3A::IDENTITY,
vel: Vec3A::ZERO,
ang_vel: Vec3A::ZERO,
},
controls: CarControls::DEFAULT,
prev_controls: CarControls::DEFAULT,
is_on_ground: true,
wheels_with_contact: [None; 4],
has_jumped: false,
has_double_jumped: false,
has_flipped: false,
flip_rel_torque: Vec3A::ZERO,
jump_ticks: 0,
flip_time: 0.0,
is_flipping: false,
is_jumping: false,
air_time: 0.0,
air_time_since_jump: 0.0,
boost: consts::car::boost::SPAWN_AMOUNT,
time_since_boosted: 0.0,
is_boosting: false,
boosting_time: 0.0,
is_supersonic: false,
supersonic_grace_timer: 0.0,
handbrake_val: 0.0,
is_auto_flipping: false,
auto_flip_timer: 0.0,
auto_flip_torque_scale: 0.0,
bump_cooldown_timer: 0.0,
last_extra_hit_tick: None,
world_contact_normal: None,
is_demoed: false,
demo_respawn_timer: 0.0,
};
#[must_use]
pub const fn has_flip_or_jump(&self) -> bool {
self.is_on_ground
|| (!self.has_flipped
&& !self.has_double_jumped
&& self.air_time_since_jump < consts::car::jump::DOUBLEJUMP_MAX_DELAY)
}
#[must_use]
pub const fn has_flip_reset(&self) -> bool {
!self.is_on_ground && self.has_flip_or_jump() && !self.has_jumped
}
#[must_use]
pub const fn got_flip_reset(&self) -> bool {
!self.is_on_ground && !self.has_jumped
}
#[must_use]
pub fn num_wheels_in_contact(&self) -> usize {
let mut result = 0;
for w in self.wheels_with_contact {
if w.is_some() {
result += 1;
}
}
result
}
#[must_use]
pub const fn jump_time(&self) -> f32 {
self.jump_ticks as f32 * consts::TICK_TIME
}
}
impl Deref for CarState {
type Target = PhysState;
fn deref(&self) -> &Self::Target {
&self.phys
}
}
impl DerefMut for CarState {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.phys
}
}