diff --git a/source/funkin/graphics/TypedGroup.hx b/source/funkin/graphics/TypedGroup.hx index 894ac17f..b533d333 100644 --- a/source/funkin/graphics/TypedGroup.hx +++ b/source/funkin/graphics/TypedGroup.hx @@ -12,13 +12,15 @@ typedef Group = TypedGroup; @:access(flixel.FlxCamera) class TypedGroup extends #if (flixel >= "5.7.0") FlxTypedContainer #else FlxTypedGroup #end { - public inline function setNull(object:T) { + public inline function setNull(object:T):Void + { var index:Int = members.indexOf(object); if (index != -1) members.unsafeSet(index, null); } - public function insertTop(object:T) { + public function insertTop(object:T):Void + { var index:Int = members.length; while (index > 0) { index--; @@ -31,7 +33,8 @@ class TypedGroup extends #if (flixel >= "5.7.0") FlxTypedContainer extends #if (flixel >= "5.7.0") FlxTypedContainer Void, recurse:Bool = false) { + override function forEachAlive(func:T -> Void, recurse:Bool = false):Void + { members.fastForEach((basic, i) -> { if (basic != null) if (basic.exists) if (basic.alive) func(basic); diff --git a/source/funkin/objects/note/BasicNote.hx b/source/funkin/objects/note/BasicNote.hx index 6ab4bd58..acfd8b76 100644 --- a/source/funkin/objects/note/BasicNote.hx +++ b/source/funkin/objects/note/BasicNote.hx @@ -60,6 +60,8 @@ class BasicNote extends SmartSprite implements INoteData implements ITimingObjec loadFromSprite(curSkinData.baseSprite); } + public function updateAnim():Void {} + public var approachAngle(default, set):Float = 0; function set_approachAngle(value:Float):Float { if (approachAngle != value) calcApproachTrig(value); diff --git a/source/funkin/objects/note/Note.hx b/source/funkin/objects/note/Note.hx index 484db3cf..abde208c 100644 --- a/source/funkin/objects/note/Note.hx +++ b/source/funkin/objects/note/Note.hx @@ -13,7 +13,7 @@ class Note extends BasicNote updateAnim(); } - public function updateAnim() { + override function updateAnim() { playAnim('scroll' + CoolUtil.directionArray[noteData]); } diff --git a/source/funkin/objects/note/Sustain.hx b/source/funkin/objects/note/Sustain.hx index 9142d2e0..4fca6fc2 100644 --- a/source/funkin/objects/note/Sustain.hx +++ b/source/funkin/objects/note/Sustain.hx @@ -119,7 +119,7 @@ class Sustain extends BasicNote override function updateSprites():Void { loadFromSprite(curSkinData.baseSprite); - playAnim("hold" + CoolUtil.directionArray[noteData]); + updateAnim(); targetStrum = targetStrum; smoothTiles = Math.round(125 / height); @@ -132,10 +132,14 @@ class Sustain extends BasicNote clipRect.width = repeatWidth; } + override function updateAnim() { + playAnim("hold" + CoolUtil.directionArray[noteData]); + } + override function setupTile(tileX:Int, tileY:Int, baseFrame:FlxFrame):FlxPoint { switch (tileY) { case 0: playAnim("hold" + CoolUtil.directionArray[noteData] + "-end"); // Tail - case 1: playAnim("hold" + CoolUtil.directionArray[noteData]); // Piece + case 1: updateAnim(); // Piece } return super.setupTile(tileX, tileY, frame); } diff --git a/source/funkin/states/editors/newchart/ChartDebug.hx b/source/funkin/states/editors/newchart/ChartDebug.hx new file mode 100644 index 00000000..9336a029 --- /dev/null +++ b/source/funkin/states/editors/newchart/ChartDebug.hx @@ -0,0 +1,216 @@ +package funkin.states.editors.newchart; + +import flixel.addons.display.FlxBackdrop; +import flixel.addons.display.FlxGridOverlay; + +typedef ChartBpm = { + var time:Float; + var bpm:Float; +} + +typedef ChartSong = { + notes:Array, + events:Array, + bpms:Array +} + +class ChartDebug extends MusicBeatState +{ + public var songFile:ChartSong; + + var downscroll:Bool = true; + var grid:Grid; + + override function create() + { + super.create(); + + grid = new Grid(); + add(grid); + + loadSong("bopeebo", "hard"); + } + + // TODO: draw this based on each bpm change till the end of the song rather than per note + + /*function addNote(data:NoteJson):Void + { + var note = grid.notes.recycle(ChartNote); + grid.notes.add(note); + + var time:Float = data.time; + var lane:Int = data.lane; + + note.y = getTimeY(time); + note.x = grid.notesGrid.x + (lane * Grid.tileSize); + note.load(data, getLastCrochet(time)); + } + + function addEvent(data:EventJson):Void + { + var event = grid.events.recycle(); + grid.events.add(event); + } + + function getLastCrochet(time:Float):Float + { + var lastChange:ChartBpm = null; + songFile.bpms.fastForEach((change, i) -> + { + if (change.time > time) + break; + + lastChange = change; + }); + + return (60 / lastChange.bpm) * 1000; + } + + // Runs a function for each bpm change of a song before a time and returns the last crochet + function forEachChange(time:Float, call:(ChartBpm, Float)->Void):Float + { + var bpms = songFile.bpms; + var crochet:Float = 0; + + var i = 1; + var l = bpms.length; + + while (i < l) { + var change = bpms[i]; + if (change.time > time) + break; + + crochet = (60 / change.bpm) * 1000; + call(change, crochet); + + i++; + } + + return crochet; + } + + function getTimeY(time:Float):Float + { + var yResult:Float = 0; + + forEachChange(time, (change, crochet) -> { + yResult += FlxMath.remapToRange( + time - change.time, + 0, 4 * crochet, + 0, 16 * Grid.tileSize + ); + }); + + if (downscroll) { + yResult *= -1; + yResult += Grid.tileSize * 16; + } + + return yResult; + }*/ + + /** Redraw all notes and events from the song **/ + function reload():Void + { + grid.notes.killMembers(); + grid.events.killMembers(); + + //songFile.notes.fastForEach((note, i) -> addNote(note)); + //songFile.events.fastForEach((event, i) -> addEvent(event)); + } + + function loadSong(name:String, difficulty:String) + { + var file = Song.checkSong(Song.loadFromFile(difficulty, name)); + Conductor.loadSong(name); + + songFile = { + notes: [], + events: [], + bpms: [{time: 0, bpm: file.bpm}] + } + + file.notes.fastForEach((section, i) -> { + section.sectionNotes.fastForEach((note, i) -> songFile.notes.push(note)); + section.sectionEvents.fastForEach((event, i) -> songFile.events.push(event)); + }); + + reload(); + } +} + +class Grid extends Group +{ + inline public static var tileSize:Int = 40; + + public var notesGrid:FlxBackdrop; + public var eventsGrid:FlxBackdrop; + + public var notes:TypedGroup; + public var events:TypedGroup; + + public function new() { + super(); + + notesGrid = new FlxBackdrop(makeGrid(8), Y); + notesGrid.screenCenter(X); + add(notesGrid); + + eventsGrid = new FlxBackdrop(makeGrid(1), Y); + eventsGrid.x = (notesGrid.x + notesGrid.width) + (tileSize / 2); + add(eventsGrid); + + notes = new TypedGroup(); + add(notes); + + events = new TypedGroup(); + add(events); + } + + function makeGrid(lanes:Int) { + return FlxGridOverlay.createGrid( + tileSize, tileSize, + tileSize * lanes, tileSize * 18, + true, 0xff7c7c7c, 0xff6e6e6e + ); + } +} + +class GridItem extends SpriteGroup +{ + +} + +class ChartNote extends GridItem +{ + var note:Note; + var sustain:Sustain; + + public function new() { + super(0,0,2); + + note = new Note(); + sustain = new Sustain(); + + add(sustain); + add(note); + + note.setGraphicSize(Grid.tileSize); + note.updateHitbox(); + + sustain.setScale(note.scale.x, true); + } + + public function load(data:NoteJson, crochet:Float) + { + note.noteData = sustain.noteData = data.lane; + note.updateAnim(); + + //sustain.repeatHeight = + } +} + +class ChartEvent extends GridItem +{ + +} \ No newline at end of file diff --git a/source/funkin/states/newchart/ChartEditor.hx b/source/funkin/states/newchart/ChartEditor.hx deleted file mode 100644 index c6b2488c..00000000 --- a/source/funkin/states/newchart/ChartEditor.hx +++ /dev/null @@ -1,33 +0,0 @@ -package funkin.states.newchart; - -class ChartEditor extends MusicBeatState -{ - public static var SONG:SwagSong; - - var bg:FlxSpriteExt; - var grid:ChartGrid; - - override function create() - { - super.create(); - - setupSong("bopeebo", "hard"); - - bg = new FlxSpriteExt().loadImage("menuDesat"); - bg.scrollFactor.set(); - bg.color = 0xFF242424; - add(bg); - - grid = new ChartGrid(); - add(grid); - } - - public static function setupSong(song:String, diff:String, ?input:SwagSong):SwagSong - { - SONG = input ?? Song.loadFromFile(diff, song); - Conductor.loadSong(SONG.song); - Conductor.bpm = SONG.bpm; - Conductor.songPosition = 0.0; - return SONG; - } -} \ No newline at end of file diff --git a/source/funkin/states/newchart/ChartGrid.hx b/source/funkin/states/newchart/ChartGrid.hx deleted file mode 100644 index f17987ab..00000000 --- a/source/funkin/states/newchart/ChartGrid.hx +++ /dev/null @@ -1,228 +0,0 @@ -package funkin.states.newchart; - -import flixel.addons.display.FlxBackdrop; -import openfl.events.MouseEvent; -import flixel.addons.display.FlxGridOverlay; - -@:access(flixel.input.mouse.FlxMouse) -class ChartGrid extends Group -{ - inline static var TILE:Int = 40; - - var downscroll:Bool = false; - - var notesGrid:FlxBackdrop; - var eventsGrid:FlxBackdrop; - var content:ChartGridContent; - - var beats:FlxBackdrop; - - var strumline:ChartStrumLine; - - public function new() { - super(); - - // Use the same bitmap for batch rendering on both grids - var bitmap = FlxGridOverlay.createGrid(1, 1, 8, 16, true, 0xff7c7c7c, 0xff6e6e6e); - - notesGrid = new FlxBackdrop(bitmap, Y); - notesGrid.scale.set(TILE, TILE); - notesGrid.updateHitbox(); - add(notesGrid); - - eventsGrid = new FlxBackdrop(bitmap, Y); - eventsGrid.scale.set(TILE, TILE); - eventsGrid.updateHitbox(); - add(eventsGrid); - - // Adjust events grid shit - eventsGrid.frame.frame.x = 1; - eventsGrid.frame.frame.width = 1; - eventsGrid.frame = eventsGrid.frame; - eventsGrid.width = TILE; - - notesGrid.screenCenter(X); - eventsGrid.x = notesGrid.x - TILE - 10; - - beats = new FlxBackdrop(null, Y); - beats.setPosition(notesGrid.x, notesGrid.y); - beats.makeGraphic(1, 1, 0xff565456); - beats.antialiasing = false; - beats.scale.set(notesGrid.width, 2); - beats.updateHitbox(); - add(beats); - - var separator = new FlxSpriteExt().makeRect(2, FlxG.height, FlxColor.BLACK); - separator.antialiasing = false; - separator.scrollFactor.set(); - separator.screenCenter(X); - add(separator); - - strumline = new ChartStrumLine(notesGrid.x); - add(strumline); - - content = new ChartGridContent(); - add(content); - - prepareBpmChanges(); - prepareObjects(); - - setSnap(4); - updatePosition(); - - FlxG.mouse._stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); - } - - override function update(elapsed:Float) - { - /*if (FlxG.keys.justPressed.SPACE) - { - if (Conductor.playing) - { - Conductor.songPosition = getTime(); - Conductor.pause(); - Conductor.sync(); - } - else - { - Conductor.inst.time = Conductor.songPosition + Conductor.offset[0] + Conductor.latency; - Conductor.resume(); - Conductor.sync(); - } - }*/ - - if (Conductor.playing) - { - updatePosition(); - } - else - { - var mult:Int = FlxG.keys.pressed.SHIFT ? 4 : 1; - - if (FlxG.keys.justPressed.A) curSection += (downscroll ? mult : -mult); - if (FlxG.keys.justPressed.D) curSection += (downscroll ? -mult : mult); - - if (FlxG.keys.pressed.W) move((downscroll ? elapsed : -elapsed) * mult); - if (FlxG.keys.pressed.S) move((downscroll ? -elapsed : elapsed) * mult); - } - } - - function move(elapsed:Float):Void - { - Conductor.songPosition = boundTime(Conductor.songPosition + elapsed * 1000); - - if (Conductor.songPosition >= sectionTimes[curSection + 1]) - { - if ((curSection + 1) != (sectionTimes.length - 1)) - curSection++; - } - else if (Conductor.songPosition < sectionTimes[curSection]) - { - curSection--; - Conductor.songPosition = sectionTimes[curSection + 1] - 1; // Adjust time - } - - updatePosition(); - } - - function updatePosition() { - strumline.y = getCurrentTimeY(); - FlxG.camera.scroll.y = strumline.y - (downscroll ? 480 : 240); - } - - function setSnap(snap:Int = 4) - { - beats.spacing.y = ((snap / 2) * TILE) - 1; - } - - // Save doing the mouse stuff on update - function onMouseMove(e) - { - // TODO: add tile logic and all that bullshit - } - - // Use inst time when possible to avoid needing to sync all the time lol - inline function getTime():Float { - return Conductor.playing ? Conductor.inst.time - Conductor.offset[0] - Conductor.latency : Conductor.songPosition; - } - - // TODO: Change the 16 with the snap later - inline function getTimeY(time:Float):Float { - var range:Float = inline FlxMath.remapToRange(time, 0, Conductor.sectionCrochet, 0, TILE * 16); - return downscroll ? -(range + TILE) : range; - } - - // Get the conductor songPosition time Y - inline function getCurrentTimeY():Float { - return getTimeY(boundTime(getTime())); - } - - // Bound a time value to the inst length - inline function boundTime(time:Float) { - return FlxMath.bound(time, 0, Conductor.inst.length - Conductor.offset[0] - Conductor.latency); - } - - // TODO: - // Merge prepareObjects and prepareBPM since the notes gotta change position depending on the bpm - // Maybe generate notes first and make another function to position them at runtime? - // Make a beats seperator class to accomodate for that too - - function prepareObjects() { - ChartEditor.SONG.notes.fastForEach((section, i) -> - { - var array:Array = []; - - section.sectionNotes.fastForEach((note, i) -> { - var note = makeNote(note[0], note[1], note[2]); - array.push(note); - }); - - content.sectionNotes.push(array); - }); - } - - public var sectionTimes:Array = []; - - function prepareBpmChanges() { - sectionTimes.splice(0, sectionTimes.length); - - var time:Float = 0.0; - var bpm = ChartEditor.SONG.bpm; - - ChartEditor.SONG.notes.fastForEach((section, i) -> { - sectionTimes.push(time); - - if (section.changeBPM) - bpm = section.bpm; - - time += 4 * (60000 / bpm); - }); - - sectionTimes.push(time); - } - - function makeNote(strumTime:Float, noteData:Int, ?susLength:Float) { - var note = new ChartNote(noteData, susLength ?? 0, downscroll); - note.setPos( - notesGrid.x + (TILE * noteData), - getTimeY(strumTime) - ); - return note; - } - - var curSection(default, set):Int = 0; - inline function set_curSection(value:Int):Int - { - value = cast FlxMath.bound(value, 0, ChartEditor.SONG.notes.length - 1); - - Conductor.songPosition = sectionTimes[value] ?? sectionTimes[sectionTimes.length - 1]; - updatePosition(); - - return content.renderSection = curSection = value; - } - - override function destroy() { - super.destroy(); - FlxG.mouse._stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); - } -} \ No newline at end of file diff --git a/source/funkin/states/newchart/ChartGridContent.hx b/source/funkin/states/newchart/ChartGridContent.hx deleted file mode 100644 index 23224921..00000000 --- a/source/funkin/states/newchart/ChartGridContent.hx +++ /dev/null @@ -1,30 +0,0 @@ -package funkin.states.newchart; - -class ChartGridContent extends FlxBasic -{ - public var sectionNotes:Array> = []; - public var sectionEvents:Array> = []; - public var sectionTexts:Array> = []; - - public var renderSection:Int = 0; - public var renderRange:Int = 3; - - override function draw():Void - { - for (i in 0...renderRange) - { - var index:Int = renderSection - 1 + i; - - // Sustains, Notes, Events, Texts - // For text rendering maybe make a sort for repeating text graphics? - // To save on bitmaps + batch rendering shit - - if (sectionNotes[index] != null) { - sectionNotes[index].fastForEach((object, i) -> { - if (object != null) if (object.exists) if (object.visible) - object.draw(); - }); - } - } - } -} \ No newline at end of file diff --git a/source/funkin/states/newchart/ChartNote.hx b/source/funkin/states/newchart/ChartNote.hx deleted file mode 100644 index 41dbfd16..00000000 --- a/source/funkin/states/newchart/ChartNote.hx +++ /dev/null @@ -1,55 +0,0 @@ -package funkin.states.newchart; - -class ChartNote extends Group -{ - var note:Note; - var sustain:Sustain; - - var hasSustain:Bool; - - public function new(noteData:Int, susLength:Float, downscroll:Bool) { - super(); - - note = new Note(0); - note.setGraphicSize(40, 40); - note.updateHitbox(); - - hasSustain = (susLength > 0); - - if (hasSustain) - { - sustain = new Sustain(0); - sustain.setScale(note.scale.x); - add(sustain); - - sustain.setTiles(1, 1); - sustain.repeatHeight = FlxMath.remapToRange(susLength, 0, Conductor.stepCrochet, 0, 40) + 20; - - sustain.offset.y = 0; - sustain.offset.x -= (20 - (sustain.width * 0.5)); - sustain.origin.set((sustain.width * .5) / sustain.scale.x, 0); - - sustain.approachAngle = downscroll ? 180 : 0; - } - - add(note); - set(noteData); - } - - public function setPos(x:Float, y:Float):Void - { - note.setPosition(x, y); - if (hasSustain) - sustain.setPosition(x, y + 20); - } - - public function set(noteData:Int):Void - { - noteData %= 4; - note.noteData = noteData; - note.updateAnim(); - - if (hasSustain) - sustain.noteData = noteData; - } -} \ No newline at end of file diff --git a/source/funkin/states/newchart/ChartStrumLine.hx b/source/funkin/states/newchart/ChartStrumLine.hx deleted file mode 100644 index 697f012c..00000000 --- a/source/funkin/states/newchart/ChartStrumLine.hx +++ /dev/null @@ -1,16 +0,0 @@ -package funkin.states.newchart; - -class ChartStrumLine extends SpriteGroup -{ - public function new(X:Float) { - super(X); - - for (i in 0...8) { - var strum = new NoteStrum(i * 40, 0, i % 4); - strum.alpha = 0.8; - strum.setGraphicSize(40, 40); - strum.updateHitbox(); - add(strum); - } - } -} \ No newline at end of file diff --git a/source/funkin/util/song/Song.hx b/source/funkin/util/song/Song.hx index 2015adbf..59107961 100644 --- a/source/funkin/util/song/Song.hx +++ b/source/funkin/util/song/Song.hx @@ -9,7 +9,8 @@ import funkin.util.song.formats.QuaFormat; import funkin.util.song.formats.GhFormat; import funkin.util.song.formats.FunkinFormat; -abstract NoteJson(Array) from Array to Array { +abstract NoteJson(Array) from Array to Array +{ public var time(get, set):Float; inline function set_time(value):Float return this[0] = value; inline function get_time():Float return this[0];