fix the slider ball not moving correctly

This commit is contained in:
Michael Zhang 2021-01-08 07:34:30 -06:00
parent 69fd5a452a
commit aef8e2e6c6
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
6 changed files with 105 additions and 32 deletions

2
Cargo.lock generated
View file

@ -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",

View file

@ -20,4 +20,4 @@ ordered-float = "2.0.1"
[dependencies.libosu]
git = "https://github.com/iptq/libosu"
rev = "fa82d6b167c648ad3f68efa3005aa8f7af12d943"
rev = "d75fe384e95156b3b40dd9e5ca7af539e48af8fa"

View file

@ -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<Vec<Point<i32>>, Spline>;
@ -25,6 +27,7 @@ pub struct Game {
song: Option<Sound>,
beatmap: Beatmap,
hit_objects: Vec<HitObject>,
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())?;
}
}

View file

@ -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));

View file

@ -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<Image>,
}
impl Texture {
pub fn with_path(path: impl AsRef<Path>) -> 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(())
}
}

View file

@ -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
}