use avian3d::math::{AdjustPrecision, Scalar};
use bevy::{
math::{Vec2, Vec3},
time::Time,
transform::components::Transform,
};
use crate::kcc::{Kcc, KccVelocity};
#[derive(Default, Debug)]
pub struct MoveAction {
pub desired_velocity: Vec3,
pub movement_acceleration: Scalar,
pub air_control_factor: Scalar,
pub air_acceleration_factor: Scalar,
pub air_max_speed_multiplier: Scalar,
pub account_rotation: bool,
}
impl MoveAction {
pub fn new(desired_velocity: Vec3) -> Self {
Self {
desired_velocity,
movement_acceleration: 100.0,
air_control_factor: 0.3,
air_acceleration_factor: 50.0,
air_max_speed_multiplier: 1.0,
account_rotation: true,
}
}
pub fn with_movement_acceleration(mut self, acceleration: Scalar) -> Self {
self.movement_acceleration = acceleration;
self
}
pub fn with_air_control(mut self, factor: Scalar) -> Self {
self.air_control_factor = factor;
self
}
pub fn with_air_acceleration_factor(mut self, factor: Scalar) -> Self {
self.air_acceleration_factor = factor;
self
}
pub fn with_air_max_speed_multiplier(mut self, multiplier: Scalar) -> Self {
self.air_max_speed_multiplier = multiplier;
self
}
pub fn with_account_rotation(mut self, account: bool) -> Self {
self.account_rotation = account;
self
}
pub fn apply(
&mut self,
time: &Time,
kcc_vel: &mut KccVelocity,
transform: &Transform,
kcc: &Kcc,
) {
let delta_time = time.delta_secs_f64().adjust_precision();
let adjusted_acceleration = if kcc.is_grounded {
self.movement_acceleration
} else {
self.movement_acceleration * self.air_control_factor * self.air_acceleration_factor
};
let velocity_direction = if self.account_rotation {
transform.rotation.mul_vec3(Vec3::new(
self.desired_velocity.x * adjusted_acceleration * delta_time,
0.0, self.desired_velocity.z * adjusted_acceleration * delta_time,
))
} else {
Vec3::new(
self.desired_velocity.x * adjusted_acceleration * delta_time,
0.0, self.desired_velocity.z * adjusted_acceleration * delta_time,
)
};
kcc_vel.x += velocity_direction.x;
kcc_vel.z += velocity_direction.z;
if !kcc.is_grounded {
let max_air_speed = self.movement_acceleration * self.air_max_speed_multiplier;
let current_horizontal_speed = Vec2::new(kcc_vel.x, kcc_vel.z).length();
if current_horizontal_speed > max_air_speed {
let normalized = Vec2::new(kcc_vel.x, kcc_vel.z).normalize() * max_air_speed;
kcc_vel.x = normalized.x;
kcc_vel.z = normalized.y;
}
}
}
}