feat: Added proper event handling for different beatmaps

This commit is contained in:
Alexey 2026-02-03 09:55:50 +03:00
commit 21fd428108

View file

@ -52,15 +52,11 @@ impl Beat {
struct BeatMap(Vec<Beat>);
impl BeatMap {
pub fn beat_length(&self) -> f32 {
let Some(last_beat) = self.0.last() else {
return 0f32;
};
last_beat.position
}
pub fn accuracy(&self, compared: &BeatMap) -> f32 {
if self.0.len() != compared.0.len() {
return 0f32;
}
let mut total_accuracy = 1f32;
for i in 0..self.0.len() {
total_accuracy *= self.0[i].accuracy(&compared.0[i]);
@ -69,9 +65,34 @@ impl BeatMap {
}
}
#[derive(Event)]
struct DemoEvent;
#[derive(Event)]
struct AnotherDemoEvent;
#[derive(PartialEq, PartialOrd, Eq, Ord, Debug)]
enum BeatMapType {
Demo,
AnotherDemo,
}
impl BeatMapType {
fn fire_event(&self, commands: &mut Commands) {
match self {
Self::Demo => {
commands.trigger(DemoEvent);
},
Self::AnotherDemo => {
commands.trigger(AnotherDemoEvent);
},
}
}
}
#[derive(Resource, Debug)]
struct BeatMapManager {
pub beatmaps: BTreeMap<String, BeatMap>,
pub beatmaps: BTreeMap<BeatMapType, BeatMap>,
pub input: BeatMap,
}
@ -96,11 +117,15 @@ pub struct RhythmPlugin;
impl Plugin for RhythmPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, setup_metronome)
.add_systems(Update, (tick_metronome, handle_input).chain());
.add_systems(Update, (tick_metronome, handle_input).chain())
.add_observer(demo_event)
.add_observer(another_demo_event);
}
}
fn setup_metronome(mut commands: Commands, asset_server: Res<AssetServer>) {
use BeatMapType as BMT;
commands.insert_resource( MetronomeData {
sound: asset_server.load("sfx/metronome.wav"),
timer: Timer::new(duration_from_bpm(120f32), TimerMode::Repeating),
@ -108,7 +133,7 @@ fn setup_metronome(mut commands: Commands, asset_server: Res<AssetServer>) {
});
commands.spawn(Metronome);
let beatmap = vec![
let demo_beatmap = vec![
Beat::new(0.0, BeatDirection::Down),
Beat::new(1.0, BeatDirection::Down),
Beat::new(2.0, BeatDirection::Left),
@ -122,8 +147,27 @@ fn setup_metronome(mut commands: Commands, asset_server: Res<AssetServer>) {
Beat::new(7.0, BeatDirection::Up),
];
let another_beatmap = vec![
Beat::new(0.0, BeatDirection::Up),
Beat::new(1.0, BeatDirection::Right),
Beat::new(1.5, BeatDirection::Right),
Beat::new(2.0, BeatDirection::Right),
Beat::new(3.0, BeatDirection::Left),
Beat::new(3.5, BeatDirection::Left),
Beat::new(4.5, BeatDirection::Down),
Beat::new(5.0, BeatDirection::Down),
Beat::new(6.0, BeatDirection::Up),
Beat::new(6.5, BeatDirection::Right),
Beat::new(7.0, BeatDirection::Up),
Beat::new(8.0, BeatDirection::Left),
Beat::new(8.5, BeatDirection::Down),
Beat::new(9.5, BeatDirection::Down),
Beat::new(10.0, BeatDirection::Right),
];
let mut beatmaps = BTreeMap::new();
beatmaps.insert("test".into(), BeatMap(beatmap));
beatmaps.insert(BMT::Demo, BeatMap(demo_beatmap));
beatmaps.insert(BMT::AnotherDemo, BeatMap(another_beatmap));
commands.insert_resource(BeatMapManager {
beatmaps,
@ -156,10 +200,20 @@ fn handle_input(
mut metronome: ResMut<MetronomeData>,
mut bm: ResMut<BeatMapManager>,
) {
if metronome.current_beat() > bm.beatmaps["test"].beat_length() + 1f32
&& !bm.input.0.is_empty() {
if keyboard_input.just_pressed(KeyCode::Space) {
println!("checking input...");
for (bm_type, beatmap) in bm.beatmaps.iter() {
let total_accuracy = beatmap.accuracy(&bm.input);
println!("accuracy for {:?}: {}%", bm_type, total_accuracy * 100f32);
if total_accuracy >= 0.85 {
bm_type.fire_event(&mut commands);
break;
}
}
println!("cleared input");
bm.input.0.clear();
println!("track ended, cleared input");
}
let input_directions = vec![
@ -190,26 +244,19 @@ fn handle_input(
bm.input.0.push(Beat::new(metronome.current_beat(), direction));
println!("pushed {:?}", bm.input.0.last().unwrap());
let last_index = bm.input.0.len() - 1;
if bm.beatmaps["test"].0.len() > last_index {
let accuracy = bm.beatmaps["test"].0[last_index].accuracy(bm.input.0.last().unwrap());
println!("accuracy: {}%", accuracy * 100f32);
}
if bm.beatmaps["test"].0.len() == bm.input.0.len() {
let total_accuracy = bm.beatmaps["test"].accuracy(&bm.input);
println!("sequence completed, total accuracy: {}%", total_accuracy * 100f32);
if total_accuracy >= 0.85 {
println!("accuracy > 85%; imagine like something happened");
}
bm.input.0.clear();
}
break;
}
}
}
fn demo_event(_: On<DemoEvent>) {
println!("demo event fired!");
}
fn another_demo_event(_: On<AnotherDemoEvent>) {
println!("another demo event fired!");
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)