From aef8e2e6c6368acd15c75a88298ad5e4a73f64d2 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Fri, 8 Jan 2021 07:34:30 -0600 Subject: [PATCH] fix the slider ball not moving correctly --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/game.rs | 54 +++++++++++++++++++---------------- src/main.rs | 3 +- src/skin.rs | 68 +++++++++++++++++++++++++++++++++++++++++++- src/slider_render.rs | 8 ++++-- 6 files changed, 105 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e3d48c..28a981d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1038,7 +1038,7 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libosu" version = "0.0.12" -source = "git+https://github.com/iptq/libosu?rev=fa82d6b167c648ad3f68efa3005aa8f7af12d943#fa82d6b167c648ad3f68efa3005aa8f7af12d943" +source = "git+https://github.com/iptq/libosu?rev=d75fe384e95156b3b40dd9e5ca7af539e48af8fa#d75fe384e95156b3b40dd9e5ca7af539e48af8fa" dependencies = [ "anyhow", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index fe48933..5f02129 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,4 @@ ordered-float = "2.0.1" [dependencies.libosu] git = "https://github.com/iptq/libosu" -rev = "fa82d6b167c648ad3f68efa3005aa8f7af12d943" +rev = "d75fe384e95156b3b40dd9e5ca7af539e48af8fa" diff --git a/src/game.rs b/src/game.rs index be10882..9876374 100644 --- a/src/game.rs +++ b/src/game.rs @@ -10,11 +10,13 @@ use ggez::{ self, Color, DrawMode, DrawParam, FillOptions, FilterMode, Mesh, Rect, StrokeOptions, Text, WHITE, }, + nalgebra::Point2, Context, GameError, GameResult, }; use libosu::{Beatmap, HitObject, HitObjectKind, Point, SpinnerInfo}; use crate::audio::{AudioEngine, Sound}; +use crate::skin::Skin; use crate::slider_render::{render_slider, Spline}; pub type SliderCache = HashMap>, Spline>; @@ -25,6 +27,7 @@ pub struct Game { song: Option, beatmap: Beatmap, hit_objects: Vec, + skin: Skin, slider_cache: SliderCache, } @@ -34,6 +37,7 @@ impl Game { let audio_engine = AudioEngine::new()?; let beatmap = Beatmap::default(); let hit_objects = Vec::new(); + let skin = Skin::new(); Ok(Game { is_playing: false, @@ -41,6 +45,7 @@ impl Game { beatmap, hit_objects, song: None, + skin, slider_cache: SliderCache::default(), }) } @@ -56,7 +61,7 @@ impl Game { let dir = path.parent().unwrap(); let song = Sound::create(dir.join(&self.beatmap.audio_filename))?; - song.set_position(113.0)?; + song.set_position(36.5)?; self.song = Some(song); Ok(()) @@ -74,14 +79,14 @@ impl Game { fn priv_draw(&mut self, ctx: &mut Context) -> Result<()> { // TODO: lol - const EDITOR_SCREEN: Rect = Rect::new(112.0, 84.0, 800.0, 600.0); + const PLAYFIELD_BOUNDS: Rect = Rect::new(112.0, 112.0, 800.0, 600.0); graphics::clear(ctx, [0.0, 0.0, 0.0, 1.0].into()); let playfield = Mesh::new_rectangle( ctx, DrawMode::Stroke(StrokeOptions::default()), - EDITOR_SCREEN, + PLAYFIELD_BOUNDS, Color::new(1.0, 1.0, 1.0, 0.5), )?; graphics::draw(ctx, &playfield, DrawParam::default())?; @@ -128,9 +133,9 @@ impl Game { } } - let cs_scale = EDITOR_SCREEN.w / 640.0; - let osupx_scale_x = EDITOR_SCREEN.w / 512.0; - let osupx_scale_y = EDITOR_SCREEN.h / 384.0; + let cs_scale = PLAYFIELD_BOUNDS.w / 640.0; + let osupx_scale_x = PLAYFIELD_BOUNDS.w / 512.0; + let osupx_scale_y = PLAYFIELD_BOUNDS.h / 384.0; let cs_osupx = self.beatmap.difficulty.circle_size_osupx(); let cs_real = cs_osupx * cs_scale; @@ -138,8 +143,8 @@ impl Game { let ho = draw_info.hit_object; let ho_time = (ho.start_time.0 as f64) / 1000.0; let pos = [ - EDITOR_SCREEN.x + osupx_scale_x * ho.pos.0 as f32, - EDITOR_SCREEN.y + osupx_scale_y * ho.pos.1 as f32, + PLAYFIELD_BOUNDS.x + osupx_scale_x * ho.pos.0 as f32, + PLAYFIELD_BOUNDS.y + osupx_scale_y * ho.pos.1 as f32, ]; let color = graphics::Color::new(1.0, 1.0, 1.0, draw_info.opacity as f32); @@ -148,7 +153,7 @@ impl Game { let spline = render_slider( &mut self.slider_cache, ctx, - EDITOR_SCREEN, + PLAYFIELD_BOUNDS, &self.beatmap, ho, color, @@ -166,10 +171,11 @@ 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 = [ - EDITOR_SCREEN.x + osupx_scale_x * pos.0 as f32, - EDITOR_SCREEN.y + osupx_scale_y * pos.1 as f32, + PLAYFIELD_BOUNDS.x + osupx_scale_x * pos.0 as f32, + PLAYFIELD_BOUNDS.y + osupx_scale_y * pos.1 as f32, ]; let ball = Mesh::new_circle( ctx, @@ -183,28 +189,26 @@ impl Game { } } - let circ = Mesh::new_circle( + self.skin.hitcircle.draw( ctx, - DrawMode::Fill(FillOptions::default()), - pos, - cs_real, - 1.0, - color, + (cs_real * 2.0, cs_real * 2.0), + DrawParam::default().dest(pos).color(color), + )?; + + self.skin.hitcircleoverlay.draw( + ctx, + (cs_real * 2.0, cs_real * 2.0), + DrawParam::default().dest(pos).color(color), )?; - graphics::draw(ctx, &circ, DrawParam::default())?; if time < ho_time { let time_diff = ho_time - time; let approach_r = cs_real * (1.0 + 2.0 * time_diff as f32 / 0.75); - let approach = Mesh::new_circle( + self.skin.approachcircle.draw( ctx, - DrawMode::Stroke(StrokeOptions::default().with_line_width(2.0)), - pos, - approach_r, - 1.0, - WHITE, + (approach_r * 2.0, approach_r * 2.0), + DrawParam::default().dest(pos).color(color), )?; - graphics::draw(ctx, &approach, DrawParam::default())?; } } diff --git a/src/main.rs b/src/main.rs index 0fc91e7..24d3950 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,7 +30,8 @@ fn main() -> Result<()> { .init() .unwrap(); - let cb = ContextBuilder::new("super_simple", "ggez") + let cb = ContextBuilder::new("osu_editor", "ggez") + .add_resource_path("skin") .window_setup(WindowSetup::default().title("OSU editor")) .window_mode(WindowMode::default().dimensions(1024.0, 768.0)); diff --git a/src/skin.rs b/src/skin.rs index 21a6e5b..4ed9315 100644 --- a/src/skin.rs +++ b/src/skin.rs @@ -1 +1,67 @@ -pub struct Skin {} +use std::path::{Path, PathBuf}; + +use anyhow::Result; +use ggez::{ + graphics::{self, DrawParam, Image}, + nalgebra::Point2, + Context, +}; + +macro_rules! create_skin { + ($([$name:ident]),* $(,)?) => { + pub struct Skin { + $( + pub $name: Texture, + )* + } + + impl Skin { + pub fn new() -> Self { + Skin { + $($name: Texture::with_path(concat!("/", stringify!($name), ".png")),)* + } + } + } + } +} + +create_skin! { + [approachcircle], + [hitcircle], + [hitcircleoverlay], +} + +pub struct Texture { + path: PathBuf, + image: Option, +} + +impl Texture { + pub fn with_path(path: impl AsRef) -> Self { + Texture { + path: path.as_ref().to_path_buf(), + image: None, + } + } + + pub fn draw(&mut self, ctx: &mut Context, size: (f32, f32), param: DrawParam) -> Result<()> { + let image = if self.image.is_some() { + self.image.as_ref().unwrap() + } else { + self.image = Some(Image::new(ctx, &self.path)?); + self.image.as_ref().unwrap() + }; + + let random_constant = 1.35; + let x_scale = random_constant * size.0 / image.width() as f32; + let y_scale = random_constant * size.1 / image.height() as f32; + graphics::draw( + ctx, + image, + param + .scale([x_scale, y_scale]) + .offset(Point2::new(0.5, 0.5)), + )?; + Ok(()) + } +} diff --git a/src/slider_render.rs b/src/slider_render.rs index e5248da..962e324 100644 --- a/src/slider_render.rs +++ b/src/slider_render.rs @@ -230,8 +230,6 @@ impl Spline { let n = self.spline_points.len() - 1; if idx == 0 && self.spline_points.len() > 2 { return self.spline_points[0]; - } else if idx >= n { - return self.spline_points[n]; } let (len1, len2) = ( @@ -240,7 +238,11 @@ impl Spline { ); let proportion = (length - len1) / (len2 - len1); - let (p1, p2) = (self.spline_points[idx], self.spline_points[idx + 1]); + let (p1, p2) = (self.spline_points[idx - 1], self.spline_points[idx]); + // println!( + // "len={:.3} idx={} len1={:.3} len2={:.3} prop={:.3} p1={:.3} p2={:.3}", + // length, idx, len1, len2, proportion, p1, p2 + // ); assert!(p1 != p2); (p2 - p1) * proportion + p1 }