diff --git a/src/game.rs b/src/game.rs index e449733..7171987 100644 --- a/src/game.rs +++ b/src/game.rs @@ -6,6 +6,7 @@ use std::path::Path; use anyhow::Result; use ggez::{ event::{EventHandler, KeyCode, KeyMods}, + nalgebra::Point2, graphics::{ self, Color, DrawMode, DrawParam, FillOptions, FilterMode, Mesh, Rect, StrokeOptions, Text, WHITE, @@ -81,6 +82,7 @@ impl Game { // TODO: lol const PLAYFIELD_BOUNDS: Rect = Rect::new(112.0, 112.0, 800.0, 600.0); const SEEKER_BOUNDS: Rect = Rect::new(46.0, 722.0, 932.0, 36.0); + const TIMELINE_BOUNDS: Rect = Rect::new(0.0, 0.0, 1024.0, 108.0); graphics::clear(ctx, [0.0, 0.0, 0.0, 1.0].into()); @@ -103,11 +105,64 @@ impl Game { end_time: f64, } - let mut visible_hitobjects = Vec::new(); + let timeline_span = 6.0 / self.beatmap.timeline_zoom; + let timeline_left = time - timeline_span / 2.0; + let timeline_right = time + timeline_span / 2.0; + println!("left {:.3} right {:.3}", timeline_left, timeline_right); + let timeline_current_line_x = TIMELINE_BOUNDS.x + TIMELINE_BOUNDS.w * 0.5; + let current_line = Mesh::new_line( + ctx, + &[ + Point2::new(timeline_current_line_x, TIMELINE_BOUNDS.y), + Point2::new( + timeline_current_line_x, + TIMELINE_BOUNDS.y + TIMELINE_BOUNDS.h, + ), + ], + 2.0, + graphics::WHITE, + )?; + graphics::draw(ctx, ¤t_line, DrawParam::default())?; + + let mut playfield_hitobjects = Vec::new(); let preempt = (self.beatmap.difficulty.approach_preempt() as f64) / 1000.0; let fade_in = (self.beatmap.difficulty.approach_fade_time() as f64) / 1000.0; - for ho in self.beatmap.hit_objects.iter() { + + // TODO: tighten this loop even more by binary searching for the start of the timeline and + // playfield hitobjects rather than looping through the entire beatmap, better yet, just + // keeping track of the old index will probably be much faster + for ho in self.beatmap.hit_objects.iter().rev() { let ho_time = (ho.start_time.0 as f64) / 1000.0; + + // draw in timeline + if ho_time >= timeline_left && ho_time <= timeline_right { + let timeline_percent = (ho_time - timeline_left) / (timeline_right - timeline_left); + let timeline_x = timeline_percent as f32 * TIMELINE_BOUNDS.w + TIMELINE_BOUNDS.x; + let timeline_y = TIMELINE_BOUNDS.y; + println!( + " - [{}] {:.3}-{:.3} : {:.3}%", + self.beatmap.timeline_zoom, + timeline_left, + timeline_right, + timeline_percent * 100.0 + ); + self.skin.hitcircle.draw( + ctx, + (TIMELINE_BOUNDS.h, TIMELINE_BOUNDS.h), + DrawParam::default() + .dest([timeline_x, timeline_y + TIMELINE_BOUNDS.h / 2.0]) + .offset([0.5, 0.0]), + )?; + self.skin.hitcircleoverlay.draw( + ctx, + (TIMELINE_BOUNDS.h, TIMELINE_BOUNDS.h), + DrawParam::default() + .dest([timeline_x, timeline_y + TIMELINE_BOUNDS.h / 2.0]) + .offset([0.5, 0.0]), + )?; + } + + // draw hitobject in playfield let end_time; let opacity = if time > ho_time - fade_in { 1.0 @@ -126,7 +181,7 @@ impl Game { }) => end_time = (spinner_end.0 as f64) / 1000.0, }; if ho_time - preempt < time && time < end_time { - visible_hitobjects.push(DrawInfo { + playfield_hitobjects.push(DrawInfo { hit_object: ho, opacity, end_time, @@ -140,7 +195,7 @@ impl Game { let cs_osupx = self.beatmap.difficulty.circle_size_osupx(); let cs_real = cs_osupx * cs_scale; - for draw_info in visible_hitobjects.iter().rev() { + for draw_info in playfield_hitobjects.iter() { let ho = draw_info.hit_object; let ho_time = (ho.start_time.0 as f64) / 1000.0; let pos = [ @@ -184,15 +239,6 @@ impl Game { DrawParam::default().dest(ball_pos), (travel_percent / 0.25) as usize, )?; - // let ball = Mesh::new_circle( - // ctx, - // DrawMode::Fill(FillOptions::default()), - // ball_pos, - // cs_real, - // 1.0, - // graphics::WHITE, - // )?; - // graphics::draw(ctx, &ball, DrawParam::default())?; } }