diff --git a/src/beatmap.rs b/src/beatmap.rs index 52524e8..504efd6 100644 --- a/src/beatmap.rs +++ b/src/beatmap.rs @@ -27,7 +27,7 @@ impl BeatmapExt { for ho in self.hit_objects.iter_mut() { if ho.inner.new_combo { number = 1; - color_idx = (color_idx+1) % self.inner.colors.len(); + color_idx = (color_idx + 1) % self.inner.colors.len(); } ho.number = number; diff --git a/src/game.rs b/src/game/mod.rs similarity index 83% rename from src/game.rs rename to src/game/mod.rs index 2dfefe5..8dea7fe 100644 --- a/src/game.rs +++ b/src/game/mod.rs @@ -1,3 +1,5 @@ +mod timeline; + use std::collections::HashMap; use std::fs::File; use std::io::Read; @@ -87,7 +89,6 @@ 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()); @@ -111,23 +112,7 @@ impl Game { color: Color, } - let timeline_span = 6.0 / self.beatmap.inner.timeline_zoom; - let timeline_left = time - timeline_span / 2.0; - let timeline_right = time + timeline_span / 2.0; - 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())?; + self.draw_timeline(ctx, time)?; let mut playfield_hitobjects = Vec::new(); let preempt = (self.beatmap.inner.difficulty.approach_preempt() as f64) / 1000.0; @@ -147,26 +132,7 @@ impl Game { ); // 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; - 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]) - .color(color), - )?; - 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]), - )?; - } + self.draw_hitobject_to_timeline(ctx, time, ho)?; // draw hitobject in playfield let end_time; @@ -251,7 +217,6 @@ impl Game { travel_percent = 1.0 - travel_percent; } let travel_length = travel_percent * info.pixel_length; - // print!("ho={:.3} ", ho_time); let pos = spline.point_at_length(travel_length); let ball_pos = [ PLAYFIELD_BOUNDS.x + osupx_scale_x * pos.0 as f32, diff --git a/src/game/timeline.rs b/src/game/timeline.rs new file mode 100644 index 0000000..e14a222 --- /dev/null +++ b/src/game/timeline.rs @@ -0,0 +1,77 @@ +use anyhow::Result; +use ggez::{ + graphics::{self, DrawParam, Mesh, Rect}, + nalgebra::Point2, + Context, +}; + +use crate::hit_object::HitObjectExt; + +use super::Game; + +pub const TIMELINE_BOUNDS: Rect = Rect::new(0.0, 0.0, 1024.0, 108.0); + +impl Game { + pub(super) fn draw_timeline(&self, ctx: &mut Context, time: f64) -> Result<()> { + let timeline_span = 6.0 / self.beatmap.inner.timeline_zoom; + 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())?; + + Ok(()) + } + + pub(super) fn draw_hitobject_to_timeline( + &self, + ctx: &mut Context, + time: f64, + ho: &HitObjectExt, + ) -> Result<()> { + let timeline_span = 6.0 / self.beatmap.inner.timeline_zoom; + let timeline_left = time - timeline_span / 2.0; + let timeline_right = time + timeline_span / 2.0; + + let ho_time = (ho.inner.start_time.0 as f64) / 1000.0; + let color = self.beatmap.inner.colors[ho.color_idx]; + let color = graphics::Color::new( + color.red as f32 / 256.0, + color.green as f32 / 256.0, + color.blue as f32 / 256.0, + 1.0, + ); + + 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; + 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]) + .color(color), + )?; + 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]), + )?; + } + + Ok(()) + } +} diff --git a/src/skin.rs b/src/skin.rs index 1454d48..0be1436 100644 --- a/src/skin.rs +++ b/src/skin.rs @@ -1,5 +1,3 @@ -use std::path::{Path, PathBuf}; - use anyhow::Result; use ggez::{ graphics::{self, DrawParam, Image}, @@ -105,13 +103,13 @@ impl Texture { Ok(()) } - pub fn draw(&mut self, ctx: &mut Context, size: (f32, f32), param: DrawParam) -> Result<()> { + pub fn draw(&self, ctx: &mut Context, size: (f32, f32), param: DrawParam) -> Result<()> { let image = self.image.as_ref().unwrap(); self.draw_image(ctx, image, size, param) } pub fn draw_frame( - &mut self, + &self, ctx: &mut Context, size: (f32, f32), param: DrawParam,