Skip to content

Commit

Permalink
Add support for overlapping notes in chart editor preview
Browse files Browse the repository at this point in the history
Also fixes some inconsistencies in the documentation
  • Loading branch information
NotHyper-474 committed Jan 23, 2025
1 parent 7891d3e commit 4fc9737
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 13 deletions.
31 changes: 29 additions & 2 deletions source/funkin/ui/debug/charting/ChartEditorState.hx
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,32 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
return currentNoteSelection;
}

var currentOverlappingNotes(default, set):Array<SongNoteData> = [];

function set_currentOverlappingNotes(value:Array<SongNoteData>):Array<SongNoteData>
{
// This value is true if all elements of the current overlapping array are also in the new array.
var isSuperset:Bool = currentOverlappingNotes.isSubset(value);
var isEqual:Bool = currentOverlappingNotes.isEqualUnordered(value);

currentOverlappingNotes = value;

if (!isEqual)
{
if (currentOverlappingNotes.length > 0 && isSuperset)
{
notePreview.addOverlappingNotes(currentOverlappingNotes, Std.int(songLengthInMs));
}
else
{
// The new array might add or remove elements from the old array, so we have to redraw the note preview.
notePreviewDirty = true;
}
}

return currentOverlappingNotes;
}

/**
* The events which are currently in the user's selection.
*/
Expand Down Expand Up @@ -3754,7 +3780,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
}

// Gather stacked notes to render later
var stackedNotes = SongNoteDataUtils.listStackedNotes(currentSongChartNoteData, stackNoteThreshold);
currentOverlappingNotes = SongNoteDataUtils.listStackedNotes(currentSongChartNoteData, stackNoteThreshold);

// Readd selection squares for selected notes.
// Recycle selection squares if possible.
Expand Down Expand Up @@ -3818,7 +3844,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
var stepLength = noteSprite.noteData.getStepLength();
selectionSquare.height = (stepLength <= 0) ? GRID_SIZE : ((stepLength + 1) * GRID_SIZE);
}
else if (doesNoteStack(noteSprite.noteData, stackedNotes))
else if (doesNoteStack(noteSprite.noteData, currentOverlappingNotes))
{
// TODO: Maybe use another way to display these notes
var selectionSquare:ChartEditorSelectionSquareSprite = renderedSelectionSquares.recycle(buildSelectionSquare);
Expand Down Expand Up @@ -6237,6 +6263,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
notePreview.erase();
notePreview.addNotes(currentSongChartNoteData, Std.int(songLengthInMs));
notePreview.addSelectedNotes(currentNoteSelection, Std.int(songLengthInMs));
notePreview.addOverlappingNotes(currentOverlappingNotes, Std.int(songLengthInMs));
notePreview.addEvents(currentSongChartEventData, Std.int(songLengthInMs));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class ChartEditorNotePreview extends FlxSprite
static final RIGHT_COLOR:FlxColor = 0xFFCC1111;
static final EVENT_COLOR:FlxColor = 0xFF111111;
static final SELECTED_COLOR:FlxColor = 0xFFFFFF00;
static final OVERLAPPING_COLOR:FlxColor = 0xFF640000;

var previewHeight:Int;

Expand Down Expand Up @@ -58,21 +59,22 @@ class ChartEditorNotePreview extends FlxSprite
* @param note The data for the note.
* @param songLengthInMs The total length of the song in milliseconds.
*/
public function addNote(note:SongNoteData, songLengthInMs:Int, ?isSelection:Bool = false):Void
public function addNote(note:SongNoteData, songLengthInMs:Int, ?previewType:NotePreviewType = None):Void
{
var noteDir:Int = note.getDirection();
var mustHit:Bool = note.getStrumlineIndex() == 0;
drawNote(noteDir, mustHit, Std.int(note.time), songLengthInMs, isSelection);
drawNote(noteDir, mustHit, Std.int(note.time), songLengthInMs, previewType);
}

/**
* Add a song event to the preview.
* @param event The data for the event.
* @param songLengthInMs The total length of the song in milliseconds.
* @param isSelection If current event is selected, which then it's forced to be yellow.
*/
public function addEvent(event:SongEventData, songLengthInMs:Int, ?isSelection:Bool = false):Void
public function addEvent(event:SongEventData, songLengthInMs:Int, isSelection:Bool = false):Void
{
drawNote(-1, false, Std.int(event.time), songLengthInMs, isSelection);
drawNote(-1, false, Std.int(event.time), songLengthInMs, isSelection ? Selection : None);
}

/**
Expand All @@ -84,7 +86,7 @@ class ChartEditorNotePreview extends FlxSprite
{
for (note in notes)
{
addNote(note, songLengthInMs, false);
addNote(note, songLengthInMs, None);
}
}

Expand All @@ -97,7 +99,20 @@ class ChartEditorNotePreview extends FlxSprite
{
for (note in notes)
{
addNote(note, songLengthInMs, true);
addNote(note, songLengthInMs, Selection);
}
}

/**
* Add an array of overlapping notes to the preview.
* @param notes The data for the notes
* @param songLengthInMs The total length of the song in milliseconds.
*/
public function addOverlappingNotes(notes:Array<SongNoteData>, songLengthInMs:Int):Void
{
for (note in notes)
{
addNote(note, songLengthInMs, Overlapping);
}
}

Expand Down Expand Up @@ -133,9 +148,9 @@ class ChartEditorNotePreview extends FlxSprite
* @param mustHit False if opponent, true if player.
* @param strumTimeInMs Time in milliseconds to strum the note.
* @param songLengthInMs Length of the song in milliseconds.
* @param isSelection If current note is selected note, which then it's forced to be green
* @param previewType If the note should forcibly be colored as selected or overlapping.
*/
public function drawNote(dir:Int, mustHit:Bool, strumTimeInMs:Int, songLengthInMs:Int, ?isSelection:Bool = false):Void
public function drawNote(dir:Int, mustHit:Bool, strumTimeInMs:Int, songLengthInMs:Int, ?previewType:NotePreviewType = None):Void
{
var color:FlxColor = switch (dir)
{
Expand All @@ -148,10 +163,15 @@ class ChartEditorNotePreview extends FlxSprite

var noteHeight:Int = NOTE_HEIGHT;

if (isSelection != null && isSelection)
switch (previewType)
{
color = SELECTED_COLOR;
noteHeight += 1;
case Selection:
color = SELECTED_COLOR;
noteHeight += 1;
case Overlapping:
color = OVERLAPPING_COLOR;
noteHeight += 2;
default:
}

var noteX:Float = NOTE_WIDTH * dir;
Expand All @@ -178,3 +198,10 @@ class ChartEditorNotePreview extends FlxSprite
FlxSpriteUtil.drawRect(this, noteX, noteY, width, height, color);
}
}

enum NotePreviewType
{
None;
Selection;
Overlapping;
}

0 comments on commit 4fc9737

Please sign in to comment.