1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2025-01-05 19:58:09 +00:00

strumline refactor stuffy

This commit is contained in:
Cameron Taylor 2024-01-09 13:16:00 -05:00
parent e323f46569
commit 5d0c1521d5
5 changed files with 142 additions and 162 deletions

View file

@ -1791,63 +1791,7 @@ class PlayState extends MusicBeatSubState
{
if (playerStrumline?.notes?.members == null || opponentStrumline?.notes?.members == null) return;
// Process notes on the opponent's side.
for (note in opponentStrumline.notes.members)
{
if (note == null) continue;
var hitWindowStart = note.strumTime - Constants.HIT_WINDOW_MS;
var hitWindowCenter = note.strumTime;
var hitWindowEnd = note.strumTime + Constants.HIT_WINDOW_MS;
if (Conductor.instance.songPosition > hitWindowEnd)
{
if (note.hasMissed) continue;
note.tooEarly = false;
note.mayHit = false;
note.hasMissed = true;
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = true;
}
else if (Conductor.instance.songPosition > hitWindowCenter)
{
if (note.hasBeenHit) continue;
// Call an event to allow canceling the note hit.
// NOTE: This is what handles the character animations!
var event:NoteScriptEvent = new NoteScriptEvent(NOTE_HIT, note, 0, true);
dispatchEvent(event);
// Calling event.cancelEvent() skips all the other logic! Neat!
if (event.eventCanceled) continue;
// Command the opponent to hit the note on time.
// NOTE: This is what handles the strumline and cleaning up the note itself!
opponentStrumline.hitNote(note);
if (note.holdNoteSprite != null)
{
opponentStrumline.playNoteHoldCover(note.holdNoteSprite);
}
}
else if (Conductor.instance.songPosition > hitWindowStart)
{
if (note.hasBeenHit || note.hasMissed) continue;
note.tooEarly = false;
note.mayHit = true;
note.hasMissed = false;
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = false;
}
else
{
note.tooEarly = true;
note.mayHit = false;
note.hasMissed = false;
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = false;
}
}
opponentStrumline.processNotes(null, dispatchEvent);
// Process hold notes on the opponent's side.
for (holdNote in opponentStrumline.holdNotes.members)
@ -1868,57 +1812,7 @@ class PlayState extends MusicBeatSubState
// if (holdNote.missedNote && !holdNote.handledMiss) { holdNote.handledMiss = true; }
}
// Process notes on the player's side.
for (note in playerStrumline.notes.members)
{
if (note == null || note.hasBeenHit) continue;
var hitWindowStart = note.strumTime - Constants.HIT_WINDOW_MS;
var hitWindowCenter = note.strumTime;
var hitWindowEnd = note.strumTime + Constants.HIT_WINDOW_MS;
if (Conductor.instance.songPosition > hitWindowEnd)
{
note.tooEarly = false;
note.mayHit = false;
note.hasMissed = true;
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = true;
}
else if (Conductor.instance.songPosition > hitWindowStart)
{
note.tooEarly = false;
note.mayHit = true;
note.hasMissed = false;
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = false;
}
else
{
note.tooEarly = true;
note.mayHit = false;
note.hasMissed = false;
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = false;
}
// This becomes true when the note leaves the hit window.
// It might still be on screen.
if (note.hasMissed && !note.handledMiss)
{
// Call an event to allow canceling the note miss.
// NOTE: This is what handles the character animations!
var event:NoteScriptEvent = new NoteScriptEvent(NOTE_MISS, note, 0, true);
dispatchEvent(event);
// Calling event.cancelEvent() skips all the other logic! Neat!
if (event.eventCanceled) continue;
// Judge the miss.
// NOTE: This is what handles the scoring.
trace('Missed note! ${note.noteData}');
onNoteMiss(note);
note.handledMiss = true;
}
}
playerStrumline.processNotes(onNoteMiss, dispatchEvent);
// Process hold notes on the player's side.
// This handles scoring so we don't need it on the opponent's side.

View file

@ -14,6 +14,7 @@ import funkin.play.notes.SustainTrail;
import funkin.data.song.SongData.SongNoteData;
import funkin.ui.options.PreferencesMenu;
import funkin.util.SortUtil;
import funkin.modding.events.ScriptEvent;
/**
* A group of sprites which handles the receptor, the note splashes, and the notes (with sustains) for a given player.
@ -142,6 +143,86 @@ class Strumline extends FlxSpriteGroup
updateNotes();
}
/**
* Process the notes in this strumline.
* @param onNoteMiss
* @param dispatchEvent TODO: better way to do this? Maybe passing in current dispatchEvent function from current state?
*/
public function processNotes(?onNoteMiss:NoteSprite->Void, ?dispatchEvent:ScriptEvent->Void)
{
for (note in notes.members)
{
if (note == null || (isPlayer && note.hasBeenHit)) continue;
var hitWindowStart = note.strumTime - Constants.HIT_WINDOW_MS;
var hitWindowCenter = note.strumTime;
var hitWindowEnd = note.strumTime + Constants.HIT_WINDOW_MS;
if (Conductor.instance.songPosition > hitWindowEnd)
{
if (!isPlayer && note.hasMissed) continue;
note.tooEarly = false;
note.mayHit = false;
note.hasMissed = true;
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = true;
}
else if (Conductor.instance.songPosition > hitWindowCenter)
{
// only run this on opponent strumlines!
if (!isPlayer) continue;
// Call an event to allow canceling the note hit.
// NOTE: This is what handles the character animations!
var event:NoteScriptEvent = new NoteScriptEvent(NOTE_HIT, note, 0, true);
if (dispatchEvent != null) dispatchEvent(event);
// Calling event.cancelEvent() skips all other logic! Neat!
if (event.eventCanceled) continue;
// Command the opponent to hit the note on time.
// NOTE: This is what handles the strumline and cleaning up the note itself!
hitNote(note);
if (note.holdNoteSprite != null)
{
playNoteHoldCover(note.holdNoteSprite);
}
}
else if (Conductor.instance.songPosition > hitWindowStart)
{
if (!isPlayer && (note.hasBeenHit || note.hasMissed)) continue;
note.tooEarly = false;
note.mayHit = true;
note.hasMissed = false;
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = false;
}
else
{
note.tooEarly = true;
note.mayHit = false;
note.hasMissed = false;
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = false;
}
if (note.hasMissed && !note.handledMiss)
{
var event:NoteScriptEvent = new NoteScriptEvent(NOTE_MISS, note, 0, true);
if (dispatchEvent != null) dispatchEvent(event);
if (event.eventCanceled) continue;
if (onNoteMiss != null) onNoteMiss(note);
note.handledMiss = true;
}
}
}
var frameMax:Int;
var animFinishedEver:Bool;

View file

@ -48,6 +48,8 @@ class DebugMenuSubState extends MusicBeatSubState
items.onChange.add(onMenuChange);
add(items);
FlxTransitionableState.skipNextTransIn = true;
// Create each menu item.
// Call onMenuChange when the first item is created to move the camera .
onMenuChange(createItem("CHART EDITOR", openChartEditor));
@ -88,8 +90,6 @@ class DebugMenuSubState extends MusicBeatSubState
function openChartEditor()
{
FlxTransitionableState.skipNextTransIn = true;
FlxG.switchState(new ChartEditorState());
}

View file

@ -7,7 +7,6 @@ import flash.text.TextField;
import flash.text.TextFormatAlign;
import flixel.math.FlxMath;
import flixel.system.debug.DebuggerUtil;
import flixel.system.debug.stats.Stats;
import flixel.util.FlxColor;
import flixel.util.FlxDestroyUtil;
@ -16,13 +15,31 @@ import flixel.util.FlxDestroyUtil;
* SHAMELESSLY STOLEN FROM FLIXEL
* https://github.com/HaxeFlixel/flixel/blob/master/flixel/system/debug/stats/StatsGraph.hx
*/
#if FLX_DEBUG
class CoolStatsGraph extends Sprite
{
static inline var AXIS_COLOR:FlxColor = 0xffffff;
static inline var AXIS_ALPHA:Float = 0.5;
static inline var HISTORY_MAX:Int = 500;
/**
* How often to update the stats, in ms. The lower, the more performance-intense!
*/
static inline var UPDATE_DELAY:Int = 250;
/**
* The initial width of the stats window.
*/
static inline var INITIAL_WIDTH:Int = 160;
static inline var FPS_COLOR:FlxColor = 0xff96ff00;
static inline var MEMORY_COLOR:FlxColor = 0xff009cff;
static inline var DRAW_TIME_COLOR:FlxColor = 0xffA60004;
static inline var UPDATE_TIME_COLOR:FlxColor = 0xffdcd400;
public static inline var LABEL_COLOR:FlxColor = 0xaaffffff;
public static inline var TEXT_SIZE:Int = 11;
public static inline var DECIMALS:Int = 1;
public var minLabel:TextField;
public var curLabel:TextField;
public var maxLabel:TextField;
@ -45,6 +62,7 @@ class CoolStatsGraph extends Sprite
public function new(X:Int, Y:Int, Width:Int, Height:Int, GraphColor:FlxColor, Unit:String, LabelWidth:Int = 45, ?Label:String)
{
super();
x = X;
y = Y;
_width = Width - LabelWidth;
@ -57,11 +75,11 @@ class CoolStatsGraph extends Sprite
_axis = new Shape();
_axis.x = _labelWidth + 10;
maxLabel = DebuggerUtil.createTextField(0, 0, Stats.LABEL_COLOR, Stats.TEXT_SIZE);
curLabel = DebuggerUtil.createTextField(0, (_height / 2) - (Stats.TEXT_SIZE / 2), graphColor, Stats.TEXT_SIZE);
minLabel = DebuggerUtil.createTextField(0, _height - Stats.TEXT_SIZE, Stats.LABEL_COLOR, Stats.TEXT_SIZE);
maxLabel = DebuggerUtil.createTextField(0, 0, LABEL_COLOR, TEXT_SIZE);
curLabel = DebuggerUtil.createTextField(0, (_height / 2) - (TEXT_SIZE / 2), graphColor, TEXT_SIZE);
minLabel = DebuggerUtil.createTextField(0, _height - TEXT_SIZE, LABEL_COLOR, TEXT_SIZE);
avgLabel = DebuggerUtil.createTextField(_labelWidth + 20, (_height / 2) - (Stats.TEXT_SIZE / 2) - 10, Stats.LABEL_COLOR, Stats.TEXT_SIZE);
avgLabel = DebuggerUtil.createTextField(_labelWidth + 20, (_height / 2) - (TEXT_SIZE / 2) - 10, LABEL_COLOR, TEXT_SIZE);
avgLabel.width = _width;
avgLabel.defaultTextFormat.align = TextFormatAlign.CENTER;
avgLabel.alpha = 0.5;
@ -136,7 +154,7 @@ class CoolStatsGraph extends Sprite
function formatValue(value:Float):String
{
return FlxMath.roundDecimal(value, Stats.DECIMALS) + " " + _unit;
return FlxMath.roundDecimal(value, DECIMALS) + " " + _unit;
}
public function average():Float
@ -157,4 +175,3 @@ class CoolStatsGraph extends Sprite
history = null;
}
}
#end

View file

@ -8,7 +8,6 @@ import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.math.FlxMath;
import funkin.ui.MusicBeatSubState;
import flixel.sound.FlxSound;
import flixel.system.debug.stats.StatsGraph;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import funkin.audio.visualize.PolygonSpectogram;
@ -16,12 +15,17 @@ import funkin.play.notes.NoteSprite;
import funkin.ui.debug.latency.CoolStatsGraph;
import haxe.Timer;
import openfl.events.KeyboardEvent;
import funkin.input.PreciseInputManager;
import funkin.play.notes.Strumline;
import funkin.play.notes.notestyle.NoteStyle;
import funkin.data.notestyle.NoteStyleData;
import funkin.data.notestyle.NoteStyleRegistry;
class LatencyState extends MusicBeatSubState
{
var offsetText:FlxText;
var noteGrp:FlxTypedGroup<NoteSprite>;
var strumLine:FlxSprite;
var strumLine:Strumline;
var blocks:FlxTypedGroup<FlxSprite>;
@ -34,10 +38,8 @@ class LatencyState extends MusicBeatSubState
var offsetsPerBeat:Array<Int> = [];
var swagSong:HomemadeMusic;
#if FLX_DEBUG
var funnyStatsGraph:CoolStatsGraph;
var realStats:CoolStatsGraph;
#end
override function create()
{
@ -51,33 +53,24 @@ class LatencyState extends MusicBeatSubState
FlxG.sound.music = swagSong;
FlxG.sound.music.play();
#if FLX_DEBUG
funnyStatsGraph = new CoolStatsGraph(0, Std.int(FlxG.height / 2), FlxG.width, Std.int(FlxG.height / 2), FlxColor.PINK, "time");
funnyStatsGraph = new CoolStatsGraph(0, Std.int(FlxG.height / 3), Std.int(FlxG.width / 2), Std.int(FlxG.height / 3), FlxColor.PINK, "time");
funnyStatsGraph.curLabel.y += 32;
FlxG.addChildBelowMouse(funnyStatsGraph);
realStats = new CoolStatsGraph(0, Std.int(FlxG.height / 2), FlxG.width, Std.int(FlxG.height / 2), FlxColor.YELLOW, "REAL");
realStats = new CoolStatsGraph(0, Std.int(FlxG.height / 3), Std.int(FlxG.width / 2), Std.int(FlxG.height / 3), FlxColor.YELLOW, "REAL");
realStats.curLabel.y -= 32;
FlxG.addChildBelowMouse(realStats);
#end
FlxG.stage.addEventListener(KeyboardEvent.KEY_DOWN, key -> {
trace(key.charCode);
if (key.charCode == 120) generateBeatStuff();
trace("\tEVENT PRESS: \t" + FlxG.sound.music.time + " " + Timer.stamp());
// trace(FlxG.sound.music.prevTimestamp);
trace(FlxG.sound.music.time);
trace("\tFR FR PRESS: \t" + swagSong.getTimeWithDiff());
// trace("\tREDDIT: \t" + swagSong.frfrTime + " " + Timer.stamp());
// @:privateAccess
// trace("\tREDDIT: \t" + FlxG.sound.music._channel.position + " " + Timer.stamp());
// trace("EVENT LISTENER: " + key);
PreciseInputManager.instance.onInputPressed.add(function(event:PreciseInputEvent) {
strumLine.pressKey(event.noteDirection);
strumLine.playPress(event.noteDirection);
generateBeatStuff(event);
});
// FlxG.sound.playMusic(Paths.sound('soundTest'));
// funnyStatsGraph.hi
PreciseInputManager.instance.onInputReleased.add(function(event:PreciseInputEvent) {
strumLine.playStatic(event.noteDirection);
strumLine.releaseKey(event.noteDirection);
});
Conductor.instance.forceBPM(60);
@ -139,10 +132,11 @@ class LatencyState extends MusicBeatSubState
}
offsetText = new FlxText();
offsetText.size = 20;
offsetText.screenCenter();
add(offsetText);
strumLine = new FlxSprite(FlxG.width / 2, 100).makeGraphic(FlxG.width, 5);
strumLine = new Strumline(NoteStyleRegistry.instance.fetchDefault(), true);
add(strumLine);
}
@ -175,15 +169,8 @@ class LatencyState extends MusicBeatSubState
trace(FlxG.sound.music._channel.position);
*/
#if FLX_DEBUG
funnyStatsGraph.update(FlxG.sound.music.time % 500);
funnyStatsGraph.update(Conductor.instance.songPosition % 500);
realStats.update(swagSong.getTimeWithDiff() % 500);
#end
if (FlxG.keys.justPressed.S)
{
trace("\tUPDATE PRESS: \t" + FlxG.sound.music.time + " " + Timer.stamp());
}
// if (FlxG.keys.justPressed.SPACE)
// {
@ -192,17 +179,15 @@ class LatencyState extends MusicBeatSubState
// FlxG.sound.music.resume();
// }
if (FlxG.keys.pressed.D) FlxG.sound.music.time += 1000 * FlxG.elapsed;
Conductor.instance.update(swagSong.getTimeWithDiff() - Conductor.instance.inputOffset);
Conductor.instance.update();
// Conductor.instance.songPosition += (Timer.stamp() * 1000) - FlxG.sound.music.prevTimestamp;
songPosVis.x = songPosToX(Conductor.instance.songPosition);
songVisFollowAudio.x = songPosToX(Conductor.instance.songPosition - Conductor.instance.instrumentalOffset);
songVisFollowVideo.x = songPosToX(Conductor.instance.songPosition - Conductor.instance.inputOffset);
offsetText.text = "INST Offset: " + Conductor.instance.instrumentalOffset + "ms";
offsetText.text += "\nINPUT Offset: " + Conductor.instance.inputOffset + "ms";
offsetText.text = "INST Offset (CTRL+Left/Right to change): " + Conductor.instance.instrumentalOffset + "ms";
offsetText.text += "\nINPUT Offset (Left/Right to change): " + Conductor.instance.inputOffset + "ms";
offsetText.text += "\ncurrentStep: " + Conductor.instance.currentStep;
offsetText.text += "\ncurrentBeat: " + Conductor.instance.currentBeat;
@ -267,19 +252,23 @@ class LatencyState extends MusicBeatSubState
super.update(elapsed);
}
function generateBeatStuff()
function generateBeatStuff(event:PreciseInputEvent)
{
Conductor.instance.update(swagSong.getTimeWithDiff());
// Conductor.instance.update(swagSong.getTimeWithDiff());
var inputLatencyMs:Float = haxe.Int64.toInt(PreciseInputManager.getCurrentTimestamp() - event.timestamp) / 1000.0 / 1000.0;
trace("input latency: " + inputLatencyMs + "ms");
trace("cur timestamp: " + PreciseInputManager.getCurrentTimestamp() + "ns");
trace("event timestamp: " + event.timestamp + "ns");
var closestBeat:Int = Math.round(Conductor.instance.songPosition / (Conductor.instance.stepLengthMs * 2)) % diffGrp.members.length;
var getDiff:Float = Conductor.instance.songPosition - (closestBeat * (Conductor.instance.stepLengthMs * 2));
getDiff -= Conductor.instance.inputOffset;
getDiff -= inputLatencyMs;
// lil fix for end of song
if (closestBeat == 0 && getDiff >= Conductor.instance.stepLengthMs * 2) getDiff -= FlxG.sound.music.length;
trace("\tDISTANCE TO CLOSEST BEAT: " + getDiff + "ms");
trace("\tCLOSEST BEAT: " + closestBeat);
beatTrail.x = songPosVis.x;
diffGrp.members[closestBeat].text = getDiff + "ms";
@ -295,7 +284,6 @@ class LatencyState extends MusicBeatSubState
class HomemadeMusic extends FlxSound
{
public var prevTimestamp:Int = 0;
public var timeWithDiff:Float = 0;
public function new()
{