Fix for BPM changes, plus working on hold note rendering

This commit is contained in:
EliteMasterEric 2023-07-19 21:16:39 -04:00
parent c56517f94f
commit 16e3bfe85e
3 changed files with 65 additions and 141 deletions

View file

@ -316,7 +316,8 @@ class Conductor
}
}
resultStep += Math.floor((ms - lastTimeChange.timeStamp) / stepLengthMs);
var resultFractionalStep:Float = (ms - lastTimeChange.timeStamp) / stepLengthMs;
resultStep += resultFractionalStep; // Math.floor();
return resultStep;
}

View file

@ -34,16 +34,6 @@ class ChartEditorNoteSprite extends FlxSprite
*/
public var noteStyle(get, null):String;
/**
* This note is the previous sprite in a sustain chain.
*/
public var parentNoteSprite(default, set):ChartEditorNoteSprite = null;
/**
* This note is the next sprite in a sustain chain.
*/
public var childNoteSprite(default, set):ChartEditorNoteSprite = null;
public function new(parent:ChartEditorState)
{
super();
@ -124,14 +114,6 @@ class ChartEditorNoteSprite extends FlxSprite
if (this.noteData == null)
{
// Disown parent.
this.parentNoteSprite = null;
if (this.childNoteSprite != null)
{
// Kill all children and disown them.
this.childNoteSprite.noteData = null;
this.childNoteSprite = null;
}
this.kill();
return this.noteData;
}
@ -170,71 +152,22 @@ class ChartEditorNoteSprite extends FlxSprite
}
}
if (parentNoteSprite == null)
this.x = cursorColumn * ChartEditorState.GRID_SIZE;
// Notes far in the song will start far down, but the group they belong to will have a high negative offset.
if (this.noteData.stepTime >= 0)
{
this.x = cursorColumn * ChartEditorState.GRID_SIZE;
// Notes far in the song will start far down, but the group they belong to will have a high negative offset.
if (this.noteData.stepTime >= 0)
{
// noteData.stepTime is a calculated value which accounts for BPM changes
this.y = this.noteData.stepTime * ChartEditorState.GRID_SIZE;
}
if (origin != null)
{
this.x += origin.x;
this.y += origin.y;
}
}
else
{
// If this is a hold note, we need to adjust the position to be centered.
if (parentNoteSprite.parentNoteSprite == null)
{
this.x = parentNoteSprite.x;
this.x += (ChartEditorState.GRID_SIZE / 2);
this.x -= this.width / 2;
}
else
{
this.x = parentNoteSprite.x;
}
this.y = parentNoteSprite.y;
if (parentNoteSprite.parentNoteSprite == null)
{
this.y += parentNoteSprite.height / 2;
}
else
{
this.y += parentNoteSprite.height - 1;
}
}
}
function set_parentNoteSprite(value:ChartEditorNoteSprite):ChartEditorNoteSprite
{
this.parentNoteSprite = value;
if (this.parentNoteSprite != null)
{
this.noteData = this.parentNoteSprite.noteData;
// noteData.stepTime is a calculated value which accounts for BPM changes
var stepTime:Float = this.noteData.stepTime;
var roundedStepTime:Float = Math.floor(stepTime + 0.01); // Add epsilon to fix rounding issues
this.y = roundedStepTime * ChartEditorState.GRID_SIZE;
}
return this.parentNoteSprite;
}
function set_childNoteSprite(value:ChartEditorNoteSprite):ChartEditorNoteSprite
{
this.childNoteSprite = value;
if (this.parentNoteSprite != null)
if (origin != null)
{
this.noteData = this.parentNoteSprite.noteData;
this.x += origin.x;
this.y += origin.y;
}
return this.childNoteSprite;
}
function get_noteStyle():String
@ -247,7 +180,6 @@ class ChartEditorNoteSprite extends FlxSprite
{
// Decide whether to display a note or a sustain.
var baseAnimationName:String = 'tap';
if (this.parentNoteSprite != null) baseAnimationName = (this.childNoteSprite != null) ? 'hold' : 'holdEnd';
// Play the appropriate animation for the type, direction, and skin.
var animationName:String = '${baseAnimationName}${this.noteData.getDirectionName()}${this.noteStyle}';
@ -260,17 +192,6 @@ class ChartEditorNoteSprite extends FlxSprite
{
case 'tap':
this.setGraphicSize(0, ChartEditorState.GRID_SIZE);
case 'hold':
if (parentNoteSprite.parentNoteSprite == null)
{
this.setGraphicSize(Std.int(ChartEditorState.GRID_SIZE / 2), Std.int(ChartEditorState.GRID_SIZE / 2));
}
else
{
this.setGraphicSize(Std.int(ChartEditorState.GRID_SIZE / 2), ChartEditorState.GRID_SIZE);
}
case 'holdEnd':
this.setGraphicSize(Std.int(ChartEditorState.GRID_SIZE / 2), Std.int(ChartEditorState.GRID_SIZE / 2));
}
this.updateHitbox();
@ -294,11 +215,4 @@ class ChartEditorNoteSprite extends FlxSprite
return false;
}
public function getBaseNoteSprite()
{
if (this.parentNoteSprite == null) return this;
else
return this.parentNoteSprite;
}
}

View file

@ -1,5 +1,6 @@
package funkin.ui.debug.charting;
import funkin.graphics.rendering.SustainTrail;
import funkin.util.SortUtil;
import funkin.ui.debug.charting.ChartEditorCommand;
import flixel.input.keyboard.FlxKey;
@ -944,6 +945,8 @@ class ChartEditorState extends HaxeUIState
*/
var renderedNotes:FlxTypedSpriteGroup<ChartEditorNoteSprite>;
var renderedHoldNotes:FlxTypedSpriteGroup<SustainTrail>;
/**
* The sprite group containing the song events.
* Only displays a subset of the data from `currentSongChartEventData`,
@ -1706,7 +1709,6 @@ class ChartEditorState extends HaxeUIState
var cursorFractionalStep:Float = cursorY / GRID_SIZE / (16 / noteSnapQuant);
var cursorStep:Int = Std.int(Math.floor(cursorFractionalStep));
var cursorMs:Float = Conductor.getStepTimeInMs(cursorStep);
trace('${cursorFractionalStep} ${cursorStep} ${cursorMs}');
// The direction value for the column at the cursor.
var cursorColumn:Int = Math.floor(cursorX / GRID_SIZE);
if (cursorColumn < 0) cursorColumn = 0;
@ -1858,8 +1860,7 @@ class ChartEditorState extends HaxeUIState
{
if (highlightedNote != null)
{
// Handle the case of clicking on a sustain piece.
highlightedNote = highlightedNote.getBaseNoteSprite();
// TODO: Handle the case of clicking on a sustain piece.
// Control click to select/deselect an individual note.
if (isNoteSelected(highlightedNote.noteData))
{
@ -2055,8 +2056,7 @@ class ChartEditorState extends HaxeUIState
if (highlightedNote != null)
{
// Handle the case of clicking on a sustain piece.
highlightedNote = highlightedNote.getBaseNoteSprite();
// TODO: Handle the case of clicking on a sustain piece.
// Remove the note.
performCommand(new RemoveNotesCommand([highlightedNote.noteData]));
}
@ -2167,18 +2167,18 @@ class ChartEditorState extends HaxeUIState
// Kill the note sprite and recycle it.
noteSprite.noteData = null;
}
else if (noteSprite.noteData.length > 0 && (noteSprite.parentNoteSprite == null && noteSprite.childNoteSprite == null))
{
// Note was extended.
// Kill the note sprite and recycle it.
noteSprite.noteData = null;
}
else if (noteSprite.noteData.length == 0 && (noteSprite.parentNoteSprite != null || noteSprite.childNoteSprite != null))
{
// Note was shortened.
// Kill the note sprite and recycle it.
noteSprite.noteData = null;
}
// else if (noteSprite.noteData.length > 0 && (noteSprite.parentNoteSprite == null && noteSprite.childNoteSprite == null))
// {
// // Note was extended.
// // Kill the note sprite and recycle it.
// noteSprite.noteData = null;
// }
// else if (noteSprite.noteData.length == 0 && (noteSprite.parentNoteSprite != null || noteSprite.childNoteSprite != null))
// {
// // Note was shortened.
// // Kill the note sprite and recycle it.
// noteSprite.noteData = null;
// }
else
{
// Note is already displayed and should remain displayed.
@ -2252,30 +2252,34 @@ class ChartEditorState extends HaxeUIState
// TODO: Replace this with SustainTrail.
if (noteSprite.noteData.length > 0)
{
var holdNoteSprite:SustainTrail = renderedHoldNotes.recycle(() -> new SustainTrail(this));
var noteLengthPixels:Float = noteSprite.noteData.stepLength * GRID_SIZE;
// If the note is a hold, we need to make sure it's long enough.
var noteLengthSteps:Float = noteSprite.noteData.stepLength;
var lastNoteSprite:ChartEditorNoteSprite = noteSprite;
while (noteLengthSteps > 0)
{
if (noteLengthSteps <= 1.0)
{
// Last note in the hold.
// TODO: We may need to make it shorter and clip it visually.
}
var nextNoteSprite:ChartEditorNoteSprite = renderedNotes.recycle(ChartEditorNoteSprite);
nextNoteSprite.parentState = this;
nextNoteSprite.parentNoteSprite = lastNoteSprite;
lastNoteSprite.childNoteSprite = nextNoteSprite;
lastNoteSprite = nextNoteSprite;
noteLengthSteps -= 1;
}
// Make sure the last note sprite shows the end cap properly.
lastNoteSprite.childNoteSprite = null;
// var noteLengthSteps:Float = ;
// var lastNoteSprite:ChartEditorNoteSprite = noteSprite;
//
// while (noteLengthSteps > 0)
// {
// if (noteLengthSteps <= 1.0)
// {
// // Last note in the hold.
// // TODO: We may need to make it shorter and clip it visually.
// }
//
// var nextNoteSprite:ChartEditorNoteSprite = renderedNotes.recycle(ChartEditorNoteSprite);
// nextNoteSprite.parentState = this;
// nextNoteSprite.parentNoteSprite = lastNoteSprite;
// lastNoteSprite.childNoteSprite = nextNoteSprite;
//
// lastNoteSprite = nextNoteSprite;
//
// noteLengthSteps -= 1;
// }
//
// // Make sure the last note sprite shows the end cap properly.
// lastNoteSprite.childNoteSprite = null;
// var noteLengthPixels:Float = (noteLengthMs / Conductor.stepLengthMs + 1) * GRID_SIZE;
// add(new FlxSprite(noteSprite.x, noteSprite.y - renderedNotes.y + noteLengthPixels).makeGraphic(40, 2, 0xFFFF0000));
@ -2326,7 +2330,8 @@ class ChartEditorState extends HaxeUIState
// Recycle selection squares if possible.
for (noteSprite in renderedNotes.members)
{
if (isNoteSelected(noteSprite.noteData) && noteSprite.parentNoteSprite == null)
// TODO: Handle selection of hold notes.
if (isNoteSelected(noteSprite.noteData))
{
var selectionSquare:FlxSprite = renderedSelectionSquares.recycle(buildSelectionSquare);
@ -2833,11 +2838,13 @@ class ChartEditorState extends HaxeUIState
// Assume notes are sorted by time.
for (noteData in currentSongChartNoteData)
{
// Check for notes between the old and new song positions.
if (noteData.time < oldSongPosition) // Note is in the past.
continue;
if (noteData.time >= newSongPosition) // Note is in the future.
return;
if (noteData.time > newSongPosition) // Note is in the future.
return; // Assume all notes are also in the future.
// Note was just hit.
@ -3122,6 +3129,8 @@ class ChartEditorState extends HaxeUIState
Conductor.forceBPM(null); // Disable the forced BPM.
Conductor.mapTimeChanges(currentSongMetadata.timeChanges);
sortChartData();
loadInstrumentalFromAsset(Paths.inst(songId));
var voiceList:Array<String> = song.getDifficulty(selectedDifficulty).buildVoiceList();