use bevy::prelude::*;
use inlet::{
InputBindings, InputManagementPlugin,
axis::AxisBinding,
button::{BevyAxisButton, ButtonChord, ButtonCombo, ButtonEventBinding},
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(InputManagementPlugin::<InputTypes, Cheats>::default())
.add_systems(Startup, setup)
.add_systems(Update, (gravity, control_player, accept_events))
.run();
}
#[derive(Hash, PartialEq, Eq, Clone)]
enum InputTypes {
Move,
Zoom,
Jump,
SecretAbility1,
SecretAbility2,
}
#[derive(Message)]
enum Cheats {
Grow,
Shrink,
}
impl Cheats {
pub fn grow() -> Self {
Self::Grow
}
pub fn shrink() -> Self {
Self::Shrink
}
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
Mesh3d(meshes.add(Circle::new(20.0))),
MeshMaterial3d(materials.add(Color::WHITE)),
Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
));
commands.spawn((
InputBindings::<InputTypes, Cheats>::new()
.with_action_binding(
InputTypes::Jump,
vec![KeyCode::Space.into(), GamepadButton::South.into()].into(),
)
.with_value_binding(
InputTypes::Zoom,
AxisBinding::mouse_y_scroll().invert().into(),
)
.with_dual_value_binding(
InputTypes::Move,
(
vec![
AxisBinding::keyboard_da(),
AxisBinding::gamepad_left_stick_x(),
AxisBinding::gamepad_dpad_right_left(),
],
vec![
AxisBinding::keyboard_ws(),
AxisBinding::gamepad_left_stick_y(),
AxisBinding::gamepad_dpad_up_down(),
],
)
.into(),
)
.with_action_binding(
InputTypes::SecretAbility1,
(
vec![
ButtonCombo::new_default_rules(vec![
KeyCode::KeyW.into(),
KeyCode::KeyS.into(),
KeyCode::KeyD.into(),
KeyCode::KeyA.into(),
])
.into(),
ButtonCombo::new_default_rules(vec![
GamepadButton::DPadUp.into(),
GamepadButton::DPadDown.into(),
GamepadButton::DPadRight.into(),
GamepadButton::DPadLeft.into(),
])
.into(),
ButtonChord::new(vec![
BevyAxisButton::new_positive_only(GamepadAxis::LeftStickY.into())
.into(),
BevyAxisButton::new_negative_only(GamepadAxis::LeftStickY.into())
.into(),
BevyAxisButton::new_positive_only(GamepadAxis::LeftStickX.into())
.into(),
BevyAxisButton::new_negative_only(GamepadAxis::LeftStickX.into())
.into(),
])
.into(),
],
ButtonEventBinding::WhenPressed(Cheats::grow),
)
.into(),
)
.with_action_binding(
InputTypes::SecretAbility2,
(
vec![
ButtonChord::new(vec![
KeyCode::KeyW.into(),
KeyCode::KeyS.into(),
KeyCode::KeyA.into(),
KeyCode::KeyD.into(),
])
.into(),
ButtonChord::new(vec![
GamepadButton::DPadUp.into(),
GamepadButton::DPadDown.into(),
GamepadButton::DPadLeft.into(),
GamepadButton::DPadRight.into(),
])
.into(),
],
ButtonEventBinding::WhenPressed(Cheats::shrink),
)
.into(),
),
Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
Transform::from_xyz(0.0, 0.5, 0.0),
));
commands.spawn((
PointLight {
shadow_maps_enabled: true,
..default()
},
Transform::from_xyz(4.0, 8.0, 4.0),
));
commands.spawn((
Camera3d::default(),
Transform::from_xyz(-10., 18., -36.0).looking_at(Vec3::ZERO, Vec3::Y),
));
}
fn control_player(
time: Res<Time>,
mut player: Single<(&mut Transform, &InputBindings<InputTypes, Cheats>)>,
mut camera: Single<
&mut Transform,
(With<Camera3d>, Without<InputBindings<InputTypes, Cheats>>),
>,
) {
let delta_time = time.delta_secs();
let mover = player.1.get_dual_value(&InputTypes::Move);
let y_scale = player.0.scale.y * 0.5;
let mover = Vec3::new(
-mover.x,
if player.1.get_action_state(&InputTypes::Jump).just_pressed() {
10.0 * y_scale
} else {
0.0
},
mover.y,
);
player.0.translation += mover * delta_time;
let zoom = 1.0 + (player.1.get_value(&InputTypes::Zoom) * delta_time);
camera.translation *= zoom;
}
fn accept_events(
mut cheats: MessageReader<Cheats>,
mut player: Single<&mut Transform, With<InputBindings<InputTypes, Cheats>>>,
) {
for cheat in cheats.read() {
match cheat {
Cheats::Grow => player.scale += 1.,
Cheats::Shrink => player.scale -= 1.,
}
}
}
fn gravity(
time: Res<Time>,
mut player: Single<&mut Transform, With<InputBindings<InputTypes, Cheats>>>,
) {
let delta_time = time.delta_secs();
let ground_y = player.scale.y * 0.5;
let new = player.translation.y - (18. * delta_time * delta_time);
if new <= ground_y {
player.translation.y = ground_y;
} else {
player.translation.y = new;
}
}