From 20d90169845f1e50f849e39f4c5f818359756c78 Mon Sep 17 00:00:00 2001 From: Cameron Taylor Date: Wed, 23 Oct 2024 19:19:06 -0400 Subject: [PATCH] feat: Added smoother scrolling when using the Chart Editor smoother drag / movement in chart editor playbarHead movement fixie --- .../ui/debug/charting/ChartEditorState.hx | 109 +++++------------- 1 file changed, 31 insertions(+), 78 deletions(-) diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index c11f13342..035884693 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -94,6 +94,7 @@ import funkin.ui.mainmenu.MainMenuState; import funkin.ui.transition.LoadingState; import funkin.util.Constants; import funkin.util.FileUtil; +import funkin.util.MathUtil; import funkin.util.logging.CrashHandler; import funkin.util.SortUtil; import funkin.util.WindowUtil; @@ -244,7 +245,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState /** * Duration, in seconds, for the scroll easing animation. */ - public static final SCROLL_EASE_DURATION:Float = 0.2; + public static final SCROLL_EASE_DURATION:Float = 0.4; // Other @@ -773,9 +774,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState /** * The current process that is lerping the scroll position. - * Used to cancel the previous lerp if the user scrolls again. */ - var currentScrollEase:Null; + var currentScrollEase:Null; /** * The position where the user middle clicked to place a scroll anchor. @@ -2707,6 +2707,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState playbarHeadLayout.playbarHead.width = FlxG.width; playbarHeadLayout.playbarHead.height = 10; playbarHeadLayout.playbarHead.styleString = 'padding-left: 0px; padding-right: 0px; border-left: 0px; border-right: 0px;'; + playbarHeadLayout.playbarHead.min = 0; playbarHeadLayout.playbarHead.onDragStart = function(_:DragEvent) { playbarHeadDragging = true; @@ -2723,13 +2724,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState } } - playbarHeadLayout.playbarHead.onDrag = function(_:DragEvent) { + playbarHeadLayout.playbarHead.onDrag = function(d:DragEvent) { if (playbarHeadDragging) { - // Set the song position to where the playhead was moved to. - scrollPositionInPixels = (songLengthInPixels) * playbarHeadLayout.playbarHead.value / 100; // Update the conductor and audio tracks to match. - moveSongToScrollPosition(); + currentScrollEase = d.value; } } @@ -2740,6 +2739,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (playbarHeadDraggingWasPlaying) { playbarHeadDraggingWasPlaying = false; + // Disabled code to resume song playback on drag. // startAudioPlayback(); } @@ -3417,10 +3417,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState audioInstTrack.time = -Conductor.instance.instrumentalOffset; } } + + if (!audioInstTrack.isPlaying && currentScrollEase != scrollPositionInPixels) easeSongToScrollPosition(currentScrollEase); } if (audioInstTrack != null && audioInstTrack.isPlaying) { + currentScrollEase = scrollPositionInPixels; + if (FlxG.keys.pressed.ALT) { // If middle mouse panning during song playback, we move ONLY the playhead, without scrolling. Neat! @@ -4057,27 +4061,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState shouldPause = true; } - if (Math.abs(scrollAmount) > GRID_SIZE * 8) - { - shouldEase = true; - } + shouldEase = true; + if (shouldPause) stopAudioPlayback(); // Resync the conductor and audio tracks. - if (scrollAmount != 0 || playheadAmount != 0) - { - this.playheadPositionInPixels += playheadAmount; - if (shouldEase) - { - easeSongToScrollPosition(this.scrollPositionInPixels + scrollAmount); - } - else - { - // Apply the scroll amount. - this.scrollPositionInPixels += scrollAmount; - moveSongToScrollPosition(); - } - } - if (shouldPause) stopAudioPlayback(); + if (playheadAmount != 0) this.playheadPositionInPixels += playheadAmount; + + if (scrollAmount != 0) currentScrollEase += scrollAmount; } /** @@ -4333,15 +4323,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { // Scroll up. var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.viewY; - scrollPositionInPixels -= diff * 0.5; // Too fast! - moveSongToScrollPosition(); + currentScrollEase -= diff * 0.5; // Too fast! } else if (FlxG.mouse.viewY > (playbarHeadLayout?.y ?? 0.0)) { // Scroll down. var diff:Float = FlxG.mouse.viewY - (playbarHeadLayout?.y ?? 0.0); - scrollPositionInPixels += diff * 0.5; // Too fast! - moveSongToScrollPosition(); + currentScrollEase += (diff * 0.5); // Too fast! } // Render the selection box. @@ -4480,8 +4468,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState var clickedPosInPixels:Float = FlxMath.remapToRange(FlxG.mouse.viewY, (notePreview?.y ?? 0.0), (notePreview?.y ?? 0.0) + (notePreview?.height ?? 0.0), 0, songLengthInPixels); - scrollPositionInPixels = clickedPosInPixels; - moveSongToScrollPosition(); + currentScrollEase = clickedPosInPixels; } else if (scrollAnchorScreenPos != null) { @@ -4540,15 +4527,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { // Scroll up. var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.viewY; - scrollPositionInPixels -= diff * 0.5; // Too fast! - moveSongToScrollPosition(); + currentScrollEase -= (diff * 0.5); } else if (FlxG.mouse.viewY > (playbarHeadLayout?.y ?? 0.0)) { // Scroll down. var diff:Float = FlxG.mouse.viewY - (playbarHeadLayout?.y ?? 0.0); - scrollPositionInPixels += diff * 0.5; // Too fast! - moveSongToScrollPosition(); + currentScrollEase += (diff * 0.5); } // Calculate distance between the position dragged to and the original position. @@ -5142,18 +5127,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { if (playbarHeadLayout == null) throw "ERROR: Tried to handle playbar, but playbarHeadLayout is null!"; + // Move the playhead to match the song position, if we aren't dragging it. + playbarHeadLayout.playbarHead.pos = currentScrollEase; + + playbarHeadLayout.playbarHead.max = songLengthInPixels; + // Make sure the playbar is never nudged out of the correct spot. playbarHeadLayout.x = 4; playbarHeadLayout.y = FlxG.height - 48 - 8; - // Move the playhead to match the song position, if we aren't dragging it. - if (!playbarHeadDragging) - { - var songPosPercent = scrollPositionInPixels / (songLengthInPixels) * 100; - - if (playbarHeadLayout.playbarHead.value != songPosPercent) playbarHeadLayout.playbarHead.value = songPosPercent; - } - var songPos:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset; var songPosMilliseconds:String = Std.string(Math.floor(Math.abs(songPos) % 1000)).lpad('0', 2).substr(0, 2); var songPosSeconds:String = Std.string(Math.floor((Math.abs(songPos) / 1000) % 60)).lpad('0', 2); @@ -6134,43 +6116,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ function easeSongToScrollPosition(targetScrollPosition:Float):Void { - if (currentScrollEase != null) cancelScrollEase(currentScrollEase); - - currentScrollEase = FlxTween.tween(this, {scrollPositionInPixels: targetScrollPosition}, SCROLL_EASE_DURATION, - { - ease: FlxEase.quintInOut, - onUpdate: this.onScrollEaseUpdate, - onComplete: this.cancelScrollEase, - type: ONESHOT - }); - } - - /** - * Callback function executed every frame that the scroll position is being eased. - * @param _ - */ - function onScrollEaseUpdate(_:FlxTween):Void - { + currentScrollEase = Math.max(0, targetScrollPosition); + currentScrollEase = Math.min(currentScrollEase, songLengthInPixels); + scrollPositionInPixels = MathUtil.smoothLerp(scrollPositionInPixels, currentScrollEase, FlxG.elapsed, SCROLL_EASE_DURATION, 1 / 1000); moveSongToScrollPosition(); } - /** - * Callback function executed when cancelling an existing scroll position ease. - * Ensures that the ease is immediately cancelled and the scroll position is set to the target value. - */ - function cancelScrollEase(_:FlxTween):Void - { - if (currentScrollEase != null) - { - @:privateAccess - var targetScrollPosition:Float = currentScrollEase._properties.scrollPositionInPixels; - - currentScrollEase.cancel(); - currentScrollEase = null; - this.scrollPositionInPixels = targetScrollPosition; - } - } - /** * Fix the current scroll position after exiting the PlayState used when testing. */ @@ -6351,6 +6302,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { if (audioInstTrack == null) return; + currentScrollEase = this.scrollPositionInPixels; + if (audioInstTrack.isPlaying) { // Pause