fix the slider ball not moving correctly
This commit is contained in:
parent
69fd5a452a
commit
aef8e2e6c6
6 changed files with 105 additions and 32 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1038,7 +1038,7 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libosu"
|
name = "libosu"
|
||||||
version = "0.0.12"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
|
|
@ -20,4 +20,4 @@ ordered-float = "2.0.1"
|
||||||
|
|
||||||
[dependencies.libosu]
|
[dependencies.libosu]
|
||||||
git = "https://github.com/iptq/libosu"
|
git = "https://github.com/iptq/libosu"
|
||||||
rev = "fa82d6b167c648ad3f68efa3005aa8f7af12d943"
|
rev = "d75fe384e95156b3b40dd9e5ca7af539e48af8fa"
|
||||||
|
|
54
src/game.rs
54
src/game.rs
|
@ -10,11 +10,13 @@ use ggez::{
|
||||||
self, Color, DrawMode, DrawParam, FillOptions, FilterMode, Mesh, Rect, StrokeOptions, Text,
|
self, Color, DrawMode, DrawParam, FillOptions, FilterMode, Mesh, Rect, StrokeOptions, Text,
|
||||||
WHITE,
|
WHITE,
|
||||||
},
|
},
|
||||||
|
nalgebra::Point2,
|
||||||
Context, GameError, GameResult,
|
Context, GameError, GameResult,
|
||||||
};
|
};
|
||||||
use libosu::{Beatmap, HitObject, HitObjectKind, Point, SpinnerInfo};
|
use libosu::{Beatmap, HitObject, HitObjectKind, Point, SpinnerInfo};
|
||||||
|
|
||||||
use crate::audio::{AudioEngine, Sound};
|
use crate::audio::{AudioEngine, Sound};
|
||||||
|
use crate::skin::Skin;
|
||||||
use crate::slider_render::{render_slider, Spline};
|
use crate::slider_render::{render_slider, Spline};
|
||||||
|
|
||||||
pub type SliderCache = HashMap<Vec<Point<i32>>, Spline>;
|
pub type SliderCache = HashMap<Vec<Point<i32>>, Spline>;
|
||||||
|
@ -25,6 +27,7 @@ pub struct Game {
|
||||||
song: Option<Sound>,
|
song: Option<Sound>,
|
||||||
beatmap: Beatmap,
|
beatmap: Beatmap,
|
||||||
hit_objects: Vec<HitObject>,
|
hit_objects: Vec<HitObject>,
|
||||||
|
skin: Skin,
|
||||||
|
|
||||||
slider_cache: SliderCache,
|
slider_cache: SliderCache,
|
||||||
}
|
}
|
||||||
|
@ -34,6 +37,7 @@ impl Game {
|
||||||
let audio_engine = AudioEngine::new()?;
|
let audio_engine = AudioEngine::new()?;
|
||||||
let beatmap = Beatmap::default();
|
let beatmap = Beatmap::default();
|
||||||
let hit_objects = Vec::new();
|
let hit_objects = Vec::new();
|
||||||
|
let skin = Skin::new();
|
||||||
|
|
||||||
Ok(Game {
|
Ok(Game {
|
||||||
is_playing: false,
|
is_playing: false,
|
||||||
|
@ -41,6 +45,7 @@ impl Game {
|
||||||
beatmap,
|
beatmap,
|
||||||
hit_objects,
|
hit_objects,
|
||||||
song: None,
|
song: None,
|
||||||
|
skin,
|
||||||
slider_cache: SliderCache::default(),
|
slider_cache: SliderCache::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -56,7 +61,7 @@ impl Game {
|
||||||
let dir = path.parent().unwrap();
|
let dir = path.parent().unwrap();
|
||||||
|
|
||||||
let song = Sound::create(dir.join(&self.beatmap.audio_filename))?;
|
let song = Sound::create(dir.join(&self.beatmap.audio_filename))?;
|
||||||
song.set_position(113.0)?;
|
song.set_position(36.5)?;
|
||||||
self.song = Some(song);
|
self.song = Some(song);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -74,14 +79,14 @@ impl Game {
|
||||||
|
|
||||||
fn priv_draw(&mut self, ctx: &mut Context) -> Result<()> {
|
fn priv_draw(&mut self, ctx: &mut Context) -> Result<()> {
|
||||||
// TODO: lol
|
// 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());
|
graphics::clear(ctx, [0.0, 0.0, 0.0, 1.0].into());
|
||||||
|
|
||||||
let playfield = Mesh::new_rectangle(
|
let playfield = Mesh::new_rectangle(
|
||||||
ctx,
|
ctx,
|
||||||
DrawMode::Stroke(StrokeOptions::default()),
|
DrawMode::Stroke(StrokeOptions::default()),
|
||||||
EDITOR_SCREEN,
|
PLAYFIELD_BOUNDS,
|
||||||
Color::new(1.0, 1.0, 1.0, 0.5),
|
Color::new(1.0, 1.0, 1.0, 0.5),
|
||||||
)?;
|
)?;
|
||||||
graphics::draw(ctx, &playfield, DrawParam::default())?;
|
graphics::draw(ctx, &playfield, DrawParam::default())?;
|
||||||
|
@ -128,9 +133,9 @@ impl Game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cs_scale = EDITOR_SCREEN.w / 640.0;
|
let cs_scale = PLAYFIELD_BOUNDS.w / 640.0;
|
||||||
let osupx_scale_x = EDITOR_SCREEN.w / 512.0;
|
let osupx_scale_x = PLAYFIELD_BOUNDS.w / 512.0;
|
||||||
let osupx_scale_y = EDITOR_SCREEN.h / 384.0;
|
let osupx_scale_y = PLAYFIELD_BOUNDS.h / 384.0;
|
||||||
let cs_osupx = self.beatmap.difficulty.circle_size_osupx();
|
let cs_osupx = self.beatmap.difficulty.circle_size_osupx();
|
||||||
let cs_real = cs_osupx * cs_scale;
|
let cs_real = cs_osupx * cs_scale;
|
||||||
|
|
||||||
|
@ -138,8 +143,8 @@ impl Game {
|
||||||
let ho = draw_info.hit_object;
|
let ho = draw_info.hit_object;
|
||||||
let ho_time = (ho.start_time.0 as f64) / 1000.0;
|
let ho_time = (ho.start_time.0 as f64) / 1000.0;
|
||||||
let pos = [
|
let pos = [
|
||||||
EDITOR_SCREEN.x + osupx_scale_x * ho.pos.0 as f32,
|
PLAYFIELD_BOUNDS.x + osupx_scale_x * ho.pos.0 as f32,
|
||||||
EDITOR_SCREEN.y + osupx_scale_y * ho.pos.1 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);
|
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(
|
let spline = render_slider(
|
||||||
&mut self.slider_cache,
|
&mut self.slider_cache,
|
||||||
ctx,
|
ctx,
|
||||||
EDITOR_SCREEN,
|
PLAYFIELD_BOUNDS,
|
||||||
&self.beatmap,
|
&self.beatmap,
|
||||||
ho,
|
ho,
|
||||||
color,
|
color,
|
||||||
|
@ -166,10 +171,11 @@ impl Game {
|
||||||
travel_percent = 1.0 - travel_percent;
|
travel_percent = 1.0 - travel_percent;
|
||||||
}
|
}
|
||||||
let travel_length = travel_percent * info.pixel_length;
|
let travel_length = travel_percent * info.pixel_length;
|
||||||
|
print!("ho={:.3} ", ho_time);
|
||||||
let pos = spline.point_at_length(travel_length);
|
let pos = spline.point_at_length(travel_length);
|
||||||
let ball_pos = [
|
let ball_pos = [
|
||||||
EDITOR_SCREEN.x + osupx_scale_x * pos.0 as f32,
|
PLAYFIELD_BOUNDS.x + osupx_scale_x * pos.0 as f32,
|
||||||
EDITOR_SCREEN.y + osupx_scale_y * pos.1 as f32,
|
PLAYFIELD_BOUNDS.y + osupx_scale_y * pos.1 as f32,
|
||||||
];
|
];
|
||||||
let ball = Mesh::new_circle(
|
let ball = Mesh::new_circle(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -183,28 +189,26 @@ impl Game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let circ = Mesh::new_circle(
|
self.skin.hitcircle.draw(
|
||||||
ctx,
|
ctx,
|
||||||
DrawMode::Fill(FillOptions::default()),
|
(cs_real * 2.0, cs_real * 2.0),
|
||||||
pos,
|
DrawParam::default().dest(pos).color(color),
|
||||||
cs_real,
|
)?;
|
||||||
1.0,
|
|
||||||
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 {
|
if time < ho_time {
|
||||||
let time_diff = ho_time - time;
|
let time_diff = ho_time - time;
|
||||||
let approach_r = cs_real * (1.0 + 2.0 * time_diff as f32 / 0.75);
|
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,
|
ctx,
|
||||||
DrawMode::Stroke(StrokeOptions::default().with_line_width(2.0)),
|
(approach_r * 2.0, approach_r * 2.0),
|
||||||
pos,
|
DrawParam::default().dest(pos).color(color),
|
||||||
approach_r,
|
|
||||||
1.0,
|
|
||||||
WHITE,
|
|
||||||
)?;
|
)?;
|
||||||
graphics::draw(ctx, &approach, DrawParam::default())?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,8 @@ fn main() -> Result<()> {
|
||||||
.init()
|
.init()
|
||||||
.unwrap();
|
.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_setup(WindowSetup::default().title("OSU editor"))
|
||||||
.window_mode(WindowMode::default().dimensions(1024.0, 768.0));
|
.window_mode(WindowMode::default().dimensions(1024.0, 768.0));
|
||||||
|
|
||||||
|
|
68
src/skin.rs
68
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<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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -230,8 +230,6 @@ impl Spline {
|
||||||
let n = self.spline_points.len() - 1;
|
let n = self.spline_points.len() - 1;
|
||||||
if idx == 0 && self.spline_points.len() > 2 {
|
if idx == 0 && self.spline_points.len() > 2 {
|
||||||
return self.spline_points[0];
|
return self.spline_points[0];
|
||||||
} else if idx >= n {
|
|
||||||
return self.spline_points[n];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (len1, len2) = (
|
let (len1, len2) = (
|
||||||
|
@ -240,7 +238,11 @@ impl Spline {
|
||||||
);
|
);
|
||||||
let proportion = (length - len1) / (len2 - len1);
|
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);
|
assert!(p1 != p2);
|
||||||
(p2 - p1) * proportion + p1
|
(p2 - p1) * proportion + p1
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue