rudimentary circle-placing
This commit is contained in:
parent
ac40feeea6
commit
d543ab4565
6 changed files with 92 additions and 11 deletions
BIN
skin/hitcircleselect.png
Normal file
BIN
skin/hitcircleselect.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
skin/hitcircleselect@2x.png
Normal file
BIN
skin/hitcircleselect@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
|
@ -14,7 +14,9 @@ use std::str::FromStr;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ggez::{
|
use ggez::{
|
||||||
event::{EventHandler, KeyCode, KeyMods, MouseButton},
|
event::{EventHandler, KeyCode, KeyMods, MouseButton},
|
||||||
graphics::{self, Color, DrawParam, FilterMode, Image, Rect, Text, WHITE},
|
graphics::{
|
||||||
|
self, Color, DrawMode, DrawParam, FilterMode, Image, Mesh, Rect, StrokeOptions, Text, WHITE,
|
||||||
|
},
|
||||||
Context, GameError, GameResult,
|
Context, GameError, GameResult,
|
||||||
};
|
};
|
||||||
use image::io::Reader as ImageReader;
|
use image::io::Reader as ImageReader;
|
||||||
|
@ -30,7 +32,7 @@ use crate::audio::{AudioEngine, Sound};
|
||||||
use crate::beatmap::{BeatmapExt, STACK_DISTANCE};
|
use crate::beatmap::{BeatmapExt, STACK_DISTANCE};
|
||||||
use crate::hitobject::HitObjectExt;
|
use crate::hitobject::HitObjectExt;
|
||||||
use crate::skin::Skin;
|
use crate::skin::Skin;
|
||||||
use crate::utils;
|
use crate::utils::{self, rect_contains};
|
||||||
|
|
||||||
pub const PLAYFIELD_BOUNDS: Rect = Rect::new(112.0, 122.0, 800.0, 600.0);
|
pub const PLAYFIELD_BOUNDS: Rect = Rect::new(112.0, 122.0, 800.0, 600.0);
|
||||||
pub const DEFAULT_COLORS: &[(f32, f32, f32)] = &[
|
pub const DEFAULT_COLORS: &[(f32, f32, f32)] = &[
|
||||||
|
@ -42,6 +44,7 @@ pub const DEFAULT_COLORS: &[(f32, f32, f32)] = &[
|
||||||
|
|
||||||
pub type SliderCache = HashMap<Vec<Point<i32>>, Spline>;
|
pub type SliderCache = HashMap<Vec<Point<i32>>, Spline>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub enum Tool {
|
pub enum Tool {
|
||||||
Select,
|
Select,
|
||||||
Circle,
|
Circle,
|
||||||
|
@ -338,7 +341,7 @@ impl Game {
|
||||||
];
|
];
|
||||||
self.skin.sliderb.draw_frame(
|
self.skin.sliderb.draw_frame(
|
||||||
ctx,
|
ctx,
|
||||||
(cs_real * 2.0, cs_real * 2.0),
|
(cs_real * 1.8, cs_real * 1.8),
|
||||||
DrawParam::default().dest(ball_pos).color(color),
|
DrawParam::default().dest(ball_pos).color(color),
|
||||||
(travel_percent / 0.25) as usize,
|
(travel_percent / 0.25) as usize,
|
||||||
)?;
|
)?;
|
||||||
|
@ -361,9 +364,27 @@ impl Game {
|
||||||
// draw whatever tool user is using
|
// draw whatever tool user is using
|
||||||
let (mx, my) = self.mouse_pos;
|
let (mx, my) = self.mouse_pos;
|
||||||
match self.tool {
|
match self.tool {
|
||||||
|
Tool::Select => {
|
||||||
|
let (mx, my) = self.mouse_pos;
|
||||||
|
if let Some((dx, dy)) = self.left_drag_start {
|
||||||
|
if rect_contains(&PLAYFIELD_BOUNDS, dx, dy) {
|
||||||
|
let ax = dx.min(mx);
|
||||||
|
let ay = dy.min(my);
|
||||||
|
let bx = dx.max(mx);
|
||||||
|
let by = dy.max(my);
|
||||||
|
let drag_rect = Rect::new(ax, ay, bx - ax, by - ay);
|
||||||
|
let drag_rect = Mesh::new_rectangle(
|
||||||
|
ctx,
|
||||||
|
DrawMode::Stroke(StrokeOptions::default()),
|
||||||
|
drag_rect,
|
||||||
|
WHITE,
|
||||||
|
)?;
|
||||||
|
graphics::draw(ctx, &drag_rect, DrawParam::default())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Tool::Circle => {
|
Tool::Circle => {
|
||||||
let b = PLAYFIELD_BOUNDS;
|
if rect_contains(&PLAYFIELD_BOUNDS, mx, my) {
|
||||||
if mx > b.x && mx < b.x + b.h && my > b.y && my < b.y + b.h {
|
|
||||||
let pos = [mx, my];
|
let pos = [mx, my];
|
||||||
let color = Color::new(1.0, 1.0, 1.0, 0.4);
|
let color = Color::new(1.0, 1.0, 1.0, 0.4);
|
||||||
self.skin.hitcircle.draw(
|
self.skin.hitcircle.draw(
|
||||||
|
@ -460,6 +481,56 @@ impl Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_click(&mut self, btn: MouseButton, x: f32, y: f32) -> Result<()> {
|
fn handle_click(&mut self, btn: MouseButton, x: f32, y: f32) -> Result<()> {
|
||||||
|
println!("handled click {}", self.song.is_some());
|
||||||
|
if let Some(song) = &self.song {
|
||||||
|
println!("song exists! {:?} {:?}", btn, self.tool);
|
||||||
|
if let (MouseButton::Left, Tool::Select) = (btn, &self.tool) {
|
||||||
|
} else if let (MouseButton::Left, Tool::Circle) = (btn, &self.tool) {
|
||||||
|
println!("left, circle, {:?} {} {}", PLAYFIELD_BOUNDS, x, y);
|
||||||
|
if rect_contains(&PLAYFIELD_BOUNDS, x, y) {
|
||||||
|
let time = (song.position()? * 1000.0) as i32;
|
||||||
|
match self
|
||||||
|
.beatmap
|
||||||
|
.hit_objects
|
||||||
|
.binary_search_by_key(&time, |ho| ho.inner.start_time.0)
|
||||||
|
{
|
||||||
|
Ok(v) => {
|
||||||
|
println!("unfortunately already found at idx {}", v);
|
||||||
|
}
|
||||||
|
Err(idx) => {
|
||||||
|
use libosu::{
|
||||||
|
hitobject::HitObject,
|
||||||
|
hitsounds::{Additions, SampleInfo},
|
||||||
|
timing::TimestampMillis,
|
||||||
|
};
|
||||||
|
|
||||||
|
let pos_x = (x - PLAYFIELD_BOUNDS.x) / PLAYFIELD_BOUNDS.w * 512.0;
|
||||||
|
let pos_y = (y - PLAYFIELD_BOUNDS.y) / PLAYFIELD_BOUNDS.h * 384.0;
|
||||||
|
let inner = HitObject {
|
||||||
|
start_time: TimestampMillis(time),
|
||||||
|
pos: Point::new(pos_x as i32, pos_y as i32),
|
||||||
|
kind: HitObjectKind::Circle,
|
||||||
|
new_combo: false,
|
||||||
|
skip_color: 0,
|
||||||
|
additions: Additions::empty(),
|
||||||
|
sample_info: SampleInfo::default(),
|
||||||
|
timing_point: None,
|
||||||
|
};
|
||||||
|
let new_obj = HitObjectExt {
|
||||||
|
inner,
|
||||||
|
stacking: 0,
|
||||||
|
color_idx: 0,
|
||||||
|
number: 0,
|
||||||
|
};
|
||||||
|
println!("creating new hitobject: {:?}", new_obj);
|
||||||
|
self.beatmap.hit_objects.insert(idx, new_obj);
|
||||||
|
self.beatmap.compute_stacking();
|
||||||
|
self.beatmap.compute_colors(&self.combo_colors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -477,11 +548,7 @@ impl EventHandler for Game {
|
||||||
match btn {
|
match btn {
|
||||||
MouseButton::Left => {
|
MouseButton::Left => {
|
||||||
use self::seeker::BOUNDS;
|
use self::seeker::BOUNDS;
|
||||||
if x > BOUNDS.x
|
if rect_contains(&BOUNDS, x, y) {
|
||||||
&& x < BOUNDS.x + BOUNDS.w
|
|
||||||
&& y > BOUNDS.y
|
|
||||||
&& y < BOUNDS.y + BOUNDS.h
|
|
||||||
{
|
|
||||||
let jump_percent = (x - BOUNDS.x) / BOUNDS.w;
|
let jump_percent = (x - BOUNDS.x) / BOUNDS.w;
|
||||||
if let Some(song) = &self.song {
|
if let Some(song) = &self.song {
|
||||||
let pos = jump_percent as f64 * song.length().unwrap();
|
let pos = jump_percent as f64 * song.length().unwrap();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ggez::{
|
use ggez::{
|
||||||
graphics::{self, Color, DrawParam, Mesh, Rect},
|
graphics::{self, Color, DrawMode, DrawParam, FillOptions, Mesh, Rect},
|
||||||
mint::Point2,
|
mint::Point2,
|
||||||
Context,
|
Context,
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,14 @@ pub const BOUNDS: Rect = Rect::new(46.0, 732.0, 932.0, 36.0);
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub(super) fn draw_seeker(&self, ctx: &mut Context) -> Result<()> {
|
pub(super) fn draw_seeker(&self, ctx: &mut Context) -> Result<()> {
|
||||||
|
let rect = Mesh::new_rectangle(
|
||||||
|
ctx,
|
||||||
|
DrawMode::Fill(FillOptions::default()),
|
||||||
|
Rect::new(0.0, 732.0, 1024.0, 36.0),
|
||||||
|
Color::new(0.0, 0.0, 0.0, 0.7),
|
||||||
|
)?;
|
||||||
|
graphics::draw(ctx, &rect, DrawParam::default())?;
|
||||||
|
|
||||||
let line_y = BOUNDS.y + BOUNDS.h / 2.0;
|
let line_y = BOUNDS.y + BOUNDS.h / 2.0;
|
||||||
let line = Mesh::new_line(
|
let line = Mesh::new_line(
|
||||||
ctx,
|
ctx,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use libosu::hitobject::HitObject;
|
use libosu::hitobject::HitObject;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct HitObjectExt {
|
pub struct HitObjectExt {
|
||||||
pub inner: HitObject,
|
pub inner: HitObject,
|
||||||
pub stacking: usize,
|
pub stacking: usize,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use ggez::graphics::Rect;
|
||||||
|
|
||||||
pub fn fuck_you_windows(
|
pub fn fuck_you_windows(
|
||||||
parent: impl AsRef<Path>,
|
parent: impl AsRef<Path>,
|
||||||
|
@ -20,3 +21,7 @@ pub fn fuck_you_windows(
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rect_contains(rect: &Rect, x: f32, y: f32) -> bool {
|
||||||
|
x >= rect.x && x <= rect.x + rect.w && y >= rect.y && y <= rect.y + rect.h
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue