Speed slider

This commit is contained in:
nise.moe 2024-03-03 17:26:45 +01:00
parent 3ddddc168b
commit 923848a156
8 changed files with 126 additions and 82 deletions

View File

@ -37,6 +37,7 @@
"sonner": "^1.3.1", "sonner": "^1.3.1",
"tailwind-merge": "^2.0.0", "tailwind-merge": "^2.0.0",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"ts-md5": "^1.3.1",
"zustand": "^4.4.1" "zustand": "^4.4.1"
}, },
"devDependencies": { "devDependencies": {
@ -3645,6 +3646,14 @@
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
}, },
"node_modules/ts-md5": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz",
"integrity": "sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg==",
"engines": {
"node": ">=12"
}
},
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.6.2", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",

View File

@ -46,6 +46,7 @@
"sonner": "^1.3.1", "sonner": "^1.3.1",
"tailwind-merge": "^2.0.0", "tailwind-merge": "^2.0.0",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"ts-md5": "^1.3.1",
"zustand": "^4.4.1" "zustand": "^4.4.1"
} }
} }

View File

@ -6,7 +6,7 @@ import { Button } from "../components/ui/button";
import { ArrowLeft, ArrowRight, PauseIcon, PlayIcon } from "lucide-react"; import { ArrowLeft, ArrowRight, PauseIcon, PlayIcon } from "lucide-react";
export function SongSlider() { export function SongSlider() {
const { beatmap, replay, playing, time } = state(); const { beatmap, replay, playing, time, speed } = state();
if (!beatmap || !replay) { if (!beatmap || !replay) {
return; return;
} }
@ -45,7 +45,6 @@ export function SongSlider() {
</div> </div>
<Slider <Slider
step={10} step={10}
min={0} min={0}
@ -55,6 +54,23 @@ export function SongSlider() {
OsuRenderer.setTime(value[0]); OsuRenderer.setTime(value[0]);
}} }}
/> />
<div className="flex flex-col items-start w-full ">
<p className="text-sm opacity-50">Current speed</p>
<p>{speed}x</p>
</div>
<Slider
step={0.1}
min={0.1}
max={2}
value={[speed]}
onValueChange={(value: any) => {
OsuRenderer.setSpeed(value[0]);
}}
/>
</Card> </Card>
); );
} }

View File

@ -1,9 +1,12 @@
import { Vector2 } from "osu-classes"; import { Vector2 } from "osu-classes";
import p5 from "p5"; import p5 from "p5";
import { loadImageAsync } from "@/utils"; import { loadImageAsync } from "@/utils";
import { Md5 } from "ts-md5";
export class Drawer { export class Drawer {
private static imageCache: Record<string, p5.Graphics> = {};
static images = { static images = {
cursor: undefined as any as p5.Image, cursor: undefined as any as p5.Image,
cursortrail: undefined as any as p5.Image, cursortrail: undefined as any as p5.Image,
@ -128,6 +131,8 @@ export class Drawer {
static drawSliderBody(origin: Vector2, path: Vector2[], radius: number) { static drawSliderBody(origin: Vector2, path: Vector2[], radius: number) {
Drawer.p.push(); Drawer.p.push();
const cacheKey = Md5.hashStr(JSON.stringify(origin) + JSON.stringify(path) + JSON.stringify(radius));
if (!this.imageCache[cacheKey]) {
const g = Drawer.p.createGraphics(512 * 4, 384 * 4); const g = Drawer.p.createGraphics(512 * 4, 384 * 4);
g.scale(2); g.scale(2);
g.translate(512 - 256, 384 - 192); g.translate(512 - 256, 384 - 192);
@ -167,12 +172,15 @@ export class Drawer {
g.endShape(); g.endShape();
} }
this.imageCache[cacheKey] = g;
}
Drawer.p.imageMode(Drawer.p.CORNER); Drawer.p.imageMode(Drawer.p.CORNER);
Drawer.p.image(g, -256, -192, 512 * 2, 384 * 2); Drawer.p.image(this.imageCache[cacheKey], -256, -192, 512 * 2, 384 * 2);
Drawer.p.pop(); Drawer.p.pop();
} }
static drawCursorPath( static drawCursorPath(
path: { path: {
position: Vector2; position: Vector2;

View File

@ -20,6 +20,7 @@ export enum OsuRendererEvents {
LOAD = "LOAD", LOAD = "LOAD",
PLAY = "PLAY", PLAY = "PLAY",
TIME = "TIME", TIME = "TIME",
SPEED = "SPEED",
} }
export class OsuRendererBridge extends EventEmitter { export class OsuRendererBridge extends EventEmitter {
@ -37,6 +38,7 @@ export class OsuRenderer {
static event = new OsuRendererBridge(); static event = new OsuRendererBridge();
static speedMultiplier = 0.5;
static time: number = 0; static time: number = 0;
static beatmap: StandardBeatmap; static beatmap: StandardBeatmap;
static og_beatmap: StandardBeatmap; static og_beatmap: StandardBeatmap;
@ -64,7 +66,7 @@ export class OsuRenderer {
} }
if (this.playing) { if (this.playing) {
this.setTime(this.time + (Date.now() - this.lastRender)); this.setTime(this.time + ((Date.now() - this.lastRender) * this.speedMultiplier));
} }
this.lastRender = Date.now(); this.lastRender = Date.now();
@ -189,6 +191,11 @@ export class OsuRenderer {
this.event.emit(OsuRendererEvents.TIME); this.event.emit(OsuRendererEvents.TIME);
} }
static setSpeed(speed: number) {
this.speedMultiplier = speed;
this.event.emit(OsuRendererEvents.SPEED);
}
private static renderObject(hitObject: StandardHitObject) { private static renderObject(hitObject: StandardHitObject) {
if (hitObject instanceof Circle) { if (hitObject instanceof Circle) {
this.renderCircle(hitObject); this.renderCircle(hitObject);
@ -318,15 +325,6 @@ export class OsuRenderer {
Drawer.drawSliderFollowPoint(sliderPos, hitObject.radius); Drawer.drawSliderFollowPoint(sliderPos, hitObject.radius);
} }
// if (GameplayAnalyzer.renderJudgements[hitObject.startTime]) {
// Drawer.setDrawingOpacity(opacity / 2);
// Drawer.drawCircleJudgement(
// hitObject.stackedStartPosition,
// hitObject.radius,
// GameplayAnalyzer.renderJudgements[hitObject.startTime]
// );
// }
Drawer.endDrawing(); Drawer.endDrawing();
return arScale; return arScale;
} }

View File

@ -52,5 +52,10 @@ export class Renderer {
time: OsuRenderer.time, time: OsuRenderer.time,
}); });
}); });
OsuRenderer.event.on(OsuRendererEvents.SPEED, () => {
state.setState({
speed: OsuRenderer.speedMultiplier,
});
});
} }
} }

View File

@ -55,6 +55,7 @@ export const state = create<{
mods: IMod[] | null; mods: IMod[] | null;
playing: boolean; playing: boolean;
time: number; time: number;
speed: number;
}>(() => ({ }>(() => ({
metadataEditorDialog: false, metadataEditorDialog: false,
openDialog: false, openDialog: false,
@ -69,6 +70,7 @@ export const state = create<{
mods: null, mods: null,
playing: false, playing: false,
time: 0, time: 0,
speed: 1
})); }));
state.subscribe((newState) => { state.subscribe((newState) => {

View File

@ -1899,6 +1899,11 @@ ts-interface-checker@^0.1.9:
resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz"
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
ts-md5@^1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz"
integrity sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg==
tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0: tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0:
version "2.6.2" version "2.6.2"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"