use avian3d::math::{Scalar, Vector, Vector2};
use bevy::prelude::*;
use crate::{
actions::{
KccActions,
gravity_action::GravityAction,
jump_action::JumpAction,
move_action::MoveAction,
rotate_action::{RotateAction, RotationType},
},
kcc::Kcc,
system_sets::IchunSystemSet,
};
#[derive(Component)]
#[require(Kcc)]
pub struct KccMovementEventsConfig {
pub movement_acceleration: Scalar,
pub running_acceleration: Scalar,
pub air_control_factor: Scalar,
pub air_acceleration_factor: Scalar,
pub air_max_speed_multiplier: Scalar,
pub camera_sensitivity: Vector2,
pub jump_impulse: Scalar,
pub is_running: bool,
pub is_floating: bool,
pub floating_gravity: Vector,
}
impl Default for KccMovementEventsConfig {
fn default() -> Self {
Self {
movement_acceleration: 50.0,
running_acceleration: 90.0,
air_control_factor: 0.5,
air_acceleration_factor: 1.5,
air_max_speed_multiplier: 1.1,
camera_sensitivity: Vector2::new(0.003, 0.002),
jump_impulse: 7.0,
is_running: false,
is_floating: false,
floating_gravity: Vector::NEG_Y * 4.0,
}
}
}
pub struct IchunMovementEventsPlugin;
impl Plugin for IchunMovementEventsPlugin {
fn build(&self, app: &mut bevy::app::App) {
app.add_message::<IchunRotateEvent>()
.add_message::<IchunMoveEvent>()
.add_message::<IchunRunEvent>()
.add_message::<IchunJumpEvent>()
.add_message::<IchunFloatEvent>()
.add_systems(
Update,
(
handle_rotate_events_sys,
handle_move_events_sys,
handle_run_events_sys,
handle_jump_events_sys,
handle_float_events_sys,
cap_gravity_sys,
)
.chain()
.in_set(IchunSystemSet::MovementEventsSet),
);
}
}
#[derive(Message)]
pub struct IchunMoveEvent {
pub entity: Entity,
pub direction: Vector2,
}
#[derive(Message)]
pub struct IchunRunEvent {
pub entity: Entity,
pub is_running: Option<bool>,
}
#[derive(Message)]
pub struct IchunRotateEvent {
pub entity: Entity,
pub rotation: Vector2,
}
#[derive(Message)]
pub struct IchunJumpEvent {
pub entity: Entity,
}
#[derive(Message)]
pub struct IchunFloatEvent {
pub entity: Entity,
pub is_floating: Option<bool>,
}
fn handle_move_events_sys(
mut movement_event_reader: MessageReader<IchunMoveEvent>,
mut controllers_qry: Query<(Entity, &KccMovementEventsConfig, &mut KccActions)>,
) {
for event in movement_event_reader.read() {
let Some((_, config, mut actions)) =
controllers_qry.iter_mut().find(|c| c.0 == event.entity)
else {
continue;
};
let desired_velocity = Vec3::new(event.direction.x, 0.0, event.direction.y);
let acceleration = if config.is_running {
config.running_acceleration
} else {
config.movement_acceleration
};
actions.move_action = Some(
MoveAction::new(desired_velocity)
.with_movement_acceleration(acceleration)
.with_air_control(config.air_control_factor)
.with_air_acceleration_factor(config.air_acceleration_factor)
.with_air_max_speed_multiplier(config.air_max_speed_multiplier)
.with_account_rotation(true),
);
}
}
fn handle_rotate_events_sys(
mut movement_event_reader: MessageReader<IchunRotateEvent>,
mut controllers_qry: Query<(Entity, &KccMovementEventsConfig, &mut KccActions)>,
) {
for event in movement_event_reader.read() {
let Some((_, config, mut actions)) =
controllers_qry.iter_mut().find(|c| c.0 == event.entity)
else {
continue;
};
let rotation = Vec3::new(event.rotation.x * config.camera_sensitivity.x, 0.0, 0.0);
actions.rotation_action = Some(RotateAction::new(RotationType::RotationVec(rotation)));
}
}
fn handle_jump_events_sys(
mut movement_event_reader: MessageReader<IchunJumpEvent>,
mut controllers_qry: Query<(Entity, &KccMovementEventsConfig, &mut KccActions)>,
) {
for event in movement_event_reader.read() {
let Some((_, config, mut actions)) =
controllers_qry.iter_mut().find(|c| c.0 == event.entity)
else {
continue;
};
actions.jump_action = Some(JumpAction::new(config.jump_impulse).with_allow_in_air(true)); }
}
fn handle_run_events_sys(
mut movement_event_reader: MessageReader<IchunRunEvent>,
mut controllers_qry: Query<(Entity, &mut KccMovementEventsConfig)>,
) {
for event in movement_event_reader.read() {
let Some((_, mut config)) = controllers_qry.iter_mut().find(|c| c.0 == event.entity) else {
continue;
};
config.is_running = match event.is_running {
Some(running) => running,
None => !config.is_running,
};
}
}
fn handle_float_events_sys(
mut movement_event_reader: MessageReader<IchunFloatEvent>,
mut controllers_qry: Query<(Entity, &mut KccMovementEventsConfig)>,
) {
for event in movement_event_reader.read() {
let Some((_, mut config)) = controllers_qry.iter_mut().find(|c| c.0 == event.entity) else {
continue;
};
config.is_floating = match event.is_floating {
Some(floating) => floating,
None => !config.is_floating,
};
}
}
fn cap_gravity_sys(mut controllers_qry: Query<(&KccMovementEventsConfig, &mut KccActions)>) {
for (movement, mut actions) in controllers_qry.iter_mut() {
if movement.is_floating {
if movement.is_floating {
actions.gravity_action = Some(GravityAction::new(movement.floating_gravity));
} else {
actions.gravity_action = None;
}
}
}
}