You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
6.1 KiB
Rust

use crate::prelude::*;
/// Menu Plugin; empty struct for Plugin impl
pub(crate) struct DicePlugin;
impl Plugin for DicePlugin {
fn build(&self, app: &mut App) {
app.add_event::<DiceAction>();
app.add_systems(Startup, init_dice_ui);
app.add_systems(Startup, init_dice);
app.add_systems(
Update,
button_emit_event::<DiceAction>.run_if(any_component_changed::<Interaction>),
);
app.add_systems(Update, draw_die.run_if(any_component_changed::<Die>));
app.add_systems(Update, roll_die.run_if(on_event::<DiceAction>()));
app.add_systems(Update, move_die.run_if(on_event::<KeyboardInput>()));
}
}
#[derive(Event, Clone)]
enum DiceAction {
Roll,
}
/// Create UI for the Dice game at startup
fn init_dice_ui(mut commands: Commands) {
commands
.spawn((GameChoice::Dice, MenuState::Closed, Pickable::IGNORE))
.add(UiContainer)
.with_children(|parent| {
parent
.spawn_empty()
.add(UiTitle { text: "Dice" })
.add(UiStyle(Style {
position_type: PositionType::Absolute,
top: Val::Px(0.0),
left: Val::Px(0.0),
margin: UiRect::all(Val::Px(5.0)),
border: UiRect::all(Val::Px(1.0)),
..default()
}));
parent
.spawn((SetState(GameChoice::None), SetState(MenuState::Open)))
.add(UiButton { label: "Menu" })
.add(UiStyle(Style {
position_type: PositionType::Absolute,
top: Val::Px(0.0),
right: Val::Px(0.0),
margin: UiRect::all(Val::Px(5.0)),
padding: UiRect::all(Val::Px(5.0)),
border: UiRect::all(Val::Px(1.0)),
..default()
}));
parent
.spawn(EmitEvent(DiceAction::Roll))
.add(UiButton { label: "Roll" })
.add(UiStyle(Style {
position_type: PositionType::Absolute,
margin: UiRect::all(Val::Px(5.0)),
padding: UiRect::all(Val::Px(5.0)),
border: UiRect::all(Val::Px(1.0)),
..default()
}));
});
}
fn init_dice(
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
mut commands: Commands,
) {
[
["a", "b", "c", "d", "e", "f"],
["g", "h", "i", "j", "k", "l"],
["m", "n", "o", "p", "q", "r"],
]
.into_iter()
.enumerate()
.for_each(|(idx, set)| {
commands
.spawn((
GameChoice::Dice,
MenuState::Closed,
Die::new(set),
PickableBundle { ..default() },
On::<Pointer<Drag>>::target_component_mut::<Transform>(|m, transform| {
transform.translation.x += m.delta.x;
transform.translation.y -= m.delta.y;
}),
))
.insert(MaterialMesh2dBundle {
mesh: meshes
.add(Rectangle {
half_size: Vec2::splat(32.0),
})
.into(),
material: materials.add(Color::PINK),
..default()
})
.insert(Text2dBundle {
text: Text::from_section(
"",
TextStyle {
color: Color::BLACK,
font_size: 32.0,
..default()
},
),
..default()
})
.insert(Transform::from_xyz(idx as f32 * 100.0, 100.0, 0.0));
});
}
fn draw_die(mut q: Query<(&Die, &mut Text), Changed<Die>>) {
q.iter_mut().for_each(|(d, mut t)| {
info!("Dice currently reads {:?}", d.get());
t.sections[0].value.replace_range(.., d.get());
});
}
fn roll_die(mut r: EventReader<DiceAction>, mut q: Query<&mut Die>, time: Res<Time>) {
r.read().for_each(|msg| match msg {
DiceAction::Roll => {
q.iter_mut().for_each(|mut d| {
d.roll((time.elapsed_seconds() * 1000.0) as usize);
});
}
});
}
fn move_die(
mut e: EventReader<KeyboardInput>,
mut q: Query<&mut Transform, With<Die>>,
time: Res<Time>,
) {
e.read().for_each(
|KeyboardInput {
key_code, state, ..
}| {
match state {
ButtonState::Pressed => {
q.iter_mut().for_each(|mut t| {
match key_code {
KeyCode::ArrowLeft => {
t.translation -= Vec3::X * time.delta_seconds() * 1000.0
}
KeyCode::ArrowRight => {
t.translation += Vec3::X * time.delta_seconds() * 1000.0
}
KeyCode::ArrowDown => {
t.translation -= Vec3::Y * time.delta_seconds() * 1000.0
}
KeyCode::ArrowUp => {
t.translation += Vec3::Y * time.delta_seconds() * 1000.0
}
_ => (),
}
info!("Moved die {:?}", t.translation);
});
}
_ => (),
}
},
)
}
/// Component for each dice
#[derive(Component, Debug)]
struct Die {
sides: [&'static str; 6],
top: usize,
}
impl Die {
/// Initialize all dice values
fn new(sides: [&'static str; 6]) -> Die {
Die { sides, top: 0 }
}
/// Roll the dice
fn roll(&mut self, seed: usize) -> &'static str {
let idx = seed % 6;
self.top = idx;
self.get()
}
/// Get the current value of the dice
fn get(&self) -> &'static str {
self.sides[self.top]
}
}