use bevy::prelude::*;
use bevy::scene::prelude::{bsn, CommandsSceneExt};
use bevy_gearbox::prelude::*;
use bevy_gearbox::GearboxPlugin;
#[derive(Message, Clone, Reflect, GearboxMessage)]
#[gearbox(validator = Digit)]
struct Press {
#[gearbox(target)]
machine: Entity,
digit: u8,
}
#[derive(Default, Clone)]
enum Digit {
#[default]
Any,
Only(u8),
}
impl MessageValidator<Press> for Digit {
fn matches(&self, press: &Press) -> bool {
match self {
Digit::Any => true,
Digit::Only(d) => press.digit == *d,
}
}
}
#[derive(Component)]
struct Door;
#[derive(Component)]
struct Progress;
const LOCKED: Color = Color::srgb(0.6, 0.25, 0.25);
const PARTIAL: Color = Color::srgb(0.7, 0.6, 0.2);
const OPEN: Color = Color::srgb(0.3, 0.8, 0.4);
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(GearboxPlugin::default())
.add_plugins(editor_server)
.add_systems(Startup, setup)
.add_systems(Update, digits.before(GearboxSet))
.add_systems(Update, show_progress.after(GearboxSet))
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands.spawn((
Text2d::new("The code is 1 2 3. Type digits; a wrong one locks the vault."),
TextColor(Color::WHITE),
Transform::from_xyz(0.0, 200.0, 0.0),
));
commands.spawn((
Door,
Sprite::from_color(LOCKED, Vec2::new(160.0, 200.0)),
Transform::default(),
));
commands.spawn((
Progress,
Text2d::new("_ _ _"),
TextColor(Color::WHITE),
Transform::from_xyz(0.0, -150.0, 0.0),
));
commands.spawn_scene(bsn! {
#Vault
StateMachineId("vault")
StateMachine InitialState(#Locked)
Substates [
#Locked Transitions [
(Target(#One) MessageEdge::<Press>::new(Some(Digit::Only(1)))),
],
#One Transitions [
(Target(#Two) MessageEdge::<Press>::new(Some(Digit::Only(2)))),
(Target(#Locked) MessageEdge::<Press>),
],
#Two Transitions [
(Target(#Open) MessageEdge::<Press>::new(Some(Digit::Only(3)))),
(Target(#Locked) MessageEdge::<Press>),
],
#Open Transitions [
(Target(#Locked) MessageEdge::<Press>),
],
]
});
}
fn digits(
keys: Res<ButtonInput<KeyCode>>,
machine: Single<Entity, With<StateMachine>>,
mut writer: MessageWriter<Press>,
) {
const DIGITS: [(KeyCode, u8); 10] = [
(KeyCode::Digit0, 0), (KeyCode::Digit1, 1), (KeyCode::Digit2, 2), (KeyCode::Digit3, 3),
(KeyCode::Digit4, 4), (KeyCode::Digit5, 5), (KeyCode::Digit6, 6), (KeyCode::Digit7, 7),
(KeyCode::Digit8, 8), (KeyCode::Digit9, 9),
];
for (key, digit) in DIGITS {
if keys.just_pressed(key) {
writer.write(Press { machine: *machine, digit });
}
}
}
fn show_progress(
q_entered: Query<&Name, Added<Active>>,
mut door: Single<&mut Sprite, With<Door>>,
mut progress: Single<&mut Text2d, With<Progress>>,
) {
for name in &q_entered {
let (text, color) = match name.as_str() {
"Locked" => ("_ _ _", LOCKED),
"One" => ("1 _ _", PARTIAL),
"Two" => ("1 2 _", PARTIAL),
"Open" => ("1 2 3 OPEN", OPEN),
_ => continue,
};
progress.0 = text.into();
door.color = color;
}
}
fn editor_server(app: &mut App) {
#[cfg(feature = "server")]
app.add_plugins(bevy_gearbox::server::ServerPlugin::default());
#[cfg(not(feature = "server"))]
let _ = app;
}