|
| 1 | +use std::collections::HashSet; |
| 2 | + |
| 3 | +use bevy::{input::common_conditions::input_just_pressed, prelude::*}; |
| 4 | + |
| 5 | +use crate::gameplay::FactorySystems; |
| 6 | + |
| 7 | +pub const DEMOLISH_BUTTON: KeyCode = KeyCode::KeyF; |
| 8 | +pub const DEMOLISH_CANCEL_BUTTON: KeyCode = KeyCode::Escape; |
| 9 | +pub const DEMOLISH_DURATION_SECS: f32 = 1.0; |
| 10 | + |
| 11 | +pub(super) fn plugin(app: &mut App) { |
| 12 | + app.register_type::<Demolishable>(); |
| 13 | + |
| 14 | + app.register_type::<DemolishSelection>(); |
| 15 | + app.init_resource::<DemolishSelection>(); |
| 16 | + |
| 17 | + app.register_type::<DemolishTimer>(); |
| 18 | + app.init_resource::<DemolishTimer>(); |
| 19 | + |
| 20 | + app.add_systems( |
| 21 | + Update, |
| 22 | + ( |
| 23 | + add_to_selection.run_if(on_event::<Pointer<Over>>), |
| 24 | + remove_from_selection.run_if(on_event::<Pointer<Out>>), |
| 25 | + clear_selection.run_if(input_just_pressed(DEMOLISH_CANCEL_BUTTON)), |
| 26 | + ) |
| 27 | + .in_set(FactorySystems::Demolish), |
| 28 | + ); |
| 29 | + |
| 30 | + app.add_systems( |
| 31 | + Update, |
| 32 | + ( |
| 33 | + tick_demolish_timer, |
| 34 | + highlight_demolition, |
| 35 | + demolish_selection.run_if(demolish_timer_finished), |
| 36 | + ) |
| 37 | + .chain() |
| 38 | + .in_set(FactorySystems::Demolish), |
| 39 | + ); |
| 40 | +} |
| 41 | + |
| 42 | +#[derive(Component, Reflect, Debug, Default)] |
| 43 | +#[reflect(Component)] |
| 44 | +pub struct Demolishable; |
| 45 | + |
| 46 | +#[derive(Resource, Reflect, Debug, Default, Deref, DerefMut)] |
| 47 | +#[reflect(Resource)] |
| 48 | +pub struct DemolishSelection(HashSet<Entity>); |
| 49 | + |
| 50 | +#[derive(Resource, Reflect, Debug, Deref, DerefMut)] |
| 51 | +#[reflect(Resource)] |
| 52 | +pub struct DemolishTimer(Timer); |
| 53 | + |
| 54 | +impl Default for DemolishTimer { |
| 55 | + fn default() -> Self { |
| 56 | + Self(Timer::from_seconds(DEMOLISH_DURATION_SECS, TimerMode::Once)) |
| 57 | + } |
| 58 | +} |
| 59 | + |
| 60 | +fn tick_demolish_timer( |
| 61 | + mut timer: ResMut<DemolishTimer>, |
| 62 | + keys: Res<ButtonInput<KeyCode>>, |
| 63 | + time: Res<Time>, |
| 64 | +) { |
| 65 | + if keys.just_released(DEMOLISH_BUTTON) { |
| 66 | + timer.reset(); |
| 67 | + } |
| 68 | + |
| 69 | + if keys.pressed(DEMOLISH_BUTTON) { |
| 70 | + timer.tick(time.delta()); |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +fn demolish_timer_finished(timer: Res<DemolishTimer>) -> bool { |
| 75 | + timer.just_finished() |
| 76 | +} |
| 77 | + |
| 78 | +fn add_to_selection( |
| 79 | + mut events: EventReader<Pointer<Over>>, |
| 80 | + mut selection: ResMut<DemolishSelection>, |
| 81 | + demolishables: Query<Entity, With<Demolishable>>, |
| 82 | +) { |
| 83 | + for event in events.read() { |
| 84 | + if !demolishables.contains(event.target) { |
| 85 | + continue; |
| 86 | + } |
| 87 | + |
| 88 | + selection.insert(event.target); |
| 89 | + } |
| 90 | +} |
| 91 | + |
| 92 | +fn remove_from_selection( |
| 93 | + mut events: EventReader<Pointer<Out>>, |
| 94 | + mut selection: ResMut<DemolishSelection>, |
| 95 | + keys: Res<ButtonInput<KeyCode>>, |
| 96 | +) { |
| 97 | + for event in events.read() { |
| 98 | + if keys.pressed(KeyCode::ShiftLeft) { |
| 99 | + continue; |
| 100 | + } |
| 101 | + |
| 102 | + selection.remove(&event.target); |
| 103 | + } |
| 104 | +} |
| 105 | + |
| 106 | +fn clear_selection(mut selection: ResMut<DemolishSelection>) { |
| 107 | + selection.clear(); |
| 108 | +} |
| 109 | + |
| 110 | +fn highlight_demolition( |
| 111 | + timer: Res<DemolishTimer>, |
| 112 | + selection: Res<DemolishSelection>, |
| 113 | + mut sprites: Query<&mut Sprite, With<Demolishable>>, |
| 114 | +) { |
| 115 | + let inverse_fraction = 1.0 - timer.fraction(); |
| 116 | + |
| 117 | + let hue = 60.0 * inverse_fraction; |
| 118 | + |
| 119 | + for entity in selection.iter() { |
| 120 | + if let Ok(mut sprite) = sprites.get_mut(*entity) { |
| 121 | + sprite.color = Color::hsl(hue, 1.0, 0.5); |
| 122 | + } |
| 123 | + } |
| 124 | +} |
| 125 | + |
| 126 | +fn demolish_selection(mut selection: ResMut<DemolishSelection>, mut commands: Commands) { |
| 127 | + for demolishable in selection.drain() { |
| 128 | + commands.entity(demolishable).despawn(); |
| 129 | + } |
| 130 | +} |
0 commit comments