fixing beat and measure lines with time sig changes (#2)
This commit is contained in:
@@ -192,6 +192,7 @@ final class Conductor
|
||||
beatsPerMeasure: song.meta.beatsPerMeasure.getDefault(4),
|
||||
stepsPerBeat: CoolUtil.floorInt(song.meta.stepsPerBeat.getDefault(4))
|
||||
};
|
||||
curChangeIndex = 0;
|
||||
bpmChangeMap = [curChange];
|
||||
if (song.events == null) return;
|
||||
|
||||
@@ -450,8 +451,19 @@ final class Conductor
|
||||
}
|
||||
}
|
||||
|
||||
public static function getMeasuresInTime(measureTime:Float, from:Int = 0):Float {
|
||||
var index = getMeasuresInChangeIndex(measureTime, from);
|
||||
if (index == -1) return measureTime * (60000 / 100 / 4);
|
||||
else if (index == 0) return measureTime * (15000 / bpmChangeMap[index].bpm) * bpmChangeMap[index].stepsPerBeat * bpmChangeMap[index].beatsPerMeasure;
|
||||
else {
|
||||
var change = bpmChangeMap[index];
|
||||
var stepTime = change.stepTime + (measureTime - change.measureTime) * change.stepsPerBeat * change.beatsPerMeasure;
|
||||
return getStepsWithBPMInTime(stepTime, index, getStepsWithIndexInBPM(stepTime, index));
|
||||
}
|
||||
}
|
||||
|
||||
public static function getBeatsInTime(beatTime:Float, from:Int = 0):Float {
|
||||
var index = getStepsInChangeIndex(beatTime, from);
|
||||
var index = getBeatsInChangeIndex(beatTime, from);
|
||||
if (index == -1) return beatTime * (60000 / 100);
|
||||
else if (index == 0) return beatTime * (15000 / bpmChangeMap[index].bpm) * bpmChangeMap[index].stepsPerBeat;
|
||||
else {
|
||||
|
||||
@@ -16,6 +16,7 @@ import flixel.input.keyboard.FlxKey;
|
||||
import flixel.sound.FlxSound;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.editors.charter.CharterBackdropGroup.CharterBackdropDummy;
|
||||
import funkin.editors.charter.CharterBackdropGroup.CharterGridSeperatorBase;
|
||||
import funkin.backend.system.Conductor;
|
||||
import funkin.backend.chart.*;
|
||||
import funkin.backend.chart.ChartData;
|
||||
@@ -622,6 +623,8 @@ class Charter extends UIState {
|
||||
gridBackdrops.bottomLimitY = __endStep * 40;
|
||||
eventsBackdrop.bottomSeparator.y = gridBackdrops.bottomLimitY-2;
|
||||
|
||||
CharterGridSeperatorBase.lastConductorSprY = Math.NEGATIVE_INFINITY;
|
||||
|
||||
updateWaveforms();
|
||||
}
|
||||
|
||||
@@ -1631,11 +1634,9 @@ class Charter extends UIState {
|
||||
}
|
||||
function _view_showeventSecSeparator(t) {
|
||||
t.icon = (Options.charterShowSections = !Options.charterShowSections) ? 1 : 0;
|
||||
eventsBackdrop.eventSecSeparator.visible = gridBackdrops.sectionsVisible = Options.charterShowSections;
|
||||
}
|
||||
function _view_showeventBeatSeparator(t) {
|
||||
t.icon = (Options.charterShowBeats = !Options.charterShowBeats) ? 1 : 0;
|
||||
eventsBackdrop.eventBeatSeparator.visible = gridBackdrops.beatsVisible = Options.charterShowBeats;
|
||||
}
|
||||
function _view_switchWaveformDetail(t) {
|
||||
t.icon = (Options.charterLowDetailWaveforms = !Options.charterLowDetailWaveforms) ? 1 : 0;
|
||||
@@ -1837,8 +1838,8 @@ class Charter extends UIState {
|
||||
public function updateBPMEvents() {
|
||||
buildEvents();
|
||||
|
||||
Conductor.mapBPMChanges(PlayState.SONG);
|
||||
Conductor.changeBPM(PlayState.SONG.meta.bpm, cast PlayState.SONG.meta.beatsPerMeasure.getDefault(4), cast PlayState.SONG.meta.stepsPerBeat.getDefault(4));
|
||||
Conductor.mapBPMChanges(PlayState.SONG);
|
||||
|
||||
refreshBPMSensitive();
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
|
||||
|
||||
public var conductorSprY:Float = 0;
|
||||
public var bottomLimitY:Float = 0;
|
||||
public var sectionsVisible:Bool = true;
|
||||
public var beatsVisible:Bool = true;
|
||||
|
||||
// Just here so you can update display sprites all dat and above
|
||||
public var strumlinesAmount:Int = 0;
|
||||
@@ -61,8 +59,6 @@ class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
|
||||
|
||||
grid.conductorFollowerSpr.y = conductorSprY;
|
||||
grid.bottomSeparator.y = (grid.bottomLimit.y = bottomLimitY)-2;
|
||||
grid.sectionSeparator.visible = sectionsVisible;
|
||||
grid.beatSeparator.visible = beatsVisible;
|
||||
|
||||
grid.waveformSprite.shader = strumLine.waveformShader;
|
||||
|
||||
@@ -119,8 +115,7 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
public var waveformSprite:FlxSprite;
|
||||
|
||||
public var conductorFollowerSpr:FlxSprite;
|
||||
public var beatSeparator:FlxBackdrop;
|
||||
public var sectionSeparator:FlxBackdrop;
|
||||
public var beatSeparator:CharterGridSeperator;
|
||||
|
||||
public var notesGroup:FlxTypedGroup<CharterNote> = new FlxTypedGroup<CharterNote>();
|
||||
public var strumLine:CharterStrumline;
|
||||
@@ -136,23 +131,14 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
waveformSprite.updateHitbox();
|
||||
add(waveformSprite);
|
||||
|
||||
sectionSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
sectionSeparator.y = -2;
|
||||
sectionSeparator.visible = Options.charterShowSections;
|
||||
|
||||
beatSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
beatSeparator.y = -1;
|
||||
beatSeparator.visible = Options.charterShowBeats;
|
||||
|
||||
for(sep in [sectionSeparator, beatSeparator]) {
|
||||
sep.makeSolid(1, 1, -1);
|
||||
sep.alpha = 0.5;
|
||||
sep.scrollFactor.set(1, 1);
|
||||
sep.scale.set((4 * 40), sep == sectionSeparator ? 4 : 2);
|
||||
sep.updateHitbox();
|
||||
}
|
||||
beatSeparator = new CharterGridSeperator();
|
||||
beatSeparator.makeSolid(1, 1, -1);
|
||||
beatSeparator.alpha = 0.5;
|
||||
beatSeparator.scrollFactor.set(1, 1);
|
||||
beatSeparator.scale.set((4 * 40), 2);
|
||||
beatSeparator.updateHitbox();
|
||||
add(beatSeparator);
|
||||
add(sectionSeparator);
|
||||
|
||||
add(notesGroup);
|
||||
|
||||
bottomSeparator = new FlxSprite(0,-2);
|
||||
@@ -200,15 +186,12 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
alpha = strumLine.strumLine.visible ? 0.9 : 0.4;
|
||||
} else alpha = 0.9;
|
||||
|
||||
for (spr in [gridBackDrop, sectionSeparator, beatSeparator, topLimit, bottomLimit,
|
||||
for (spr in [gridBackDrop, beatSeparator, topLimit, bottomLimit,
|
||||
topSeparator, bottomSeparator, conductorFollowerSpr, waveformSprite]) {
|
||||
spr.x = x; if (spr != waveformSprite) spr.alpha = alpha;
|
||||
spr.cameras = this.cameras;
|
||||
}
|
||||
|
||||
sectionSeparator.spacing.y = (10 * Conductor.beatsPerMeasure * Conductor.stepsPerBeat) - 1;
|
||||
beatSeparator.spacing.y = (20 * Conductor.stepsPerBeat) - 1;
|
||||
|
||||
topLimit.scale.set(4 * 40, Math.ceil(FlxG.height / cameras[0].zoom));
|
||||
topLimit.updateHitbox();
|
||||
topLimit.y = -topLimit.height;
|
||||
@@ -237,6 +220,159 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
}
|
||||
}
|
||||
|
||||
class CharterGridSeperatorBase extends FlxSprite {
|
||||
|
||||
private static var minStep:Float = 0;
|
||||
private static var maxStep:Float = 0;
|
||||
|
||||
private static var minBeat:Float = 0;
|
||||
private static var maxBeat:Float = 0;
|
||||
|
||||
private static var minMeasure:Float = 0;
|
||||
private static var maxMeasure:Float = 0;
|
||||
|
||||
private static var lastMinBeat:Float = -1;
|
||||
private static var lastMaxBeat:Float = -1;
|
||||
|
||||
private static var lastMinMeasure:Float = -1;
|
||||
private static var lastMaxMeasure:Float = -1;
|
||||
|
||||
public static var lastConductorSprY:Float = Math.NEGATIVE_INFINITY;
|
||||
|
||||
private static var beatStepTimes:Array<Float> = [];
|
||||
private static var measureStepTimes:Array<Float> = [];
|
||||
private static var timeSignatureChangeGaps:Array<Float> = [];
|
||||
|
||||
private function recalculateBeats() {
|
||||
var conductorSprY = Charter.instance.gridBackdrops.conductorSprY;
|
||||
if (conductorSprY == lastConductorSprY) return;
|
||||
|
||||
var zoomOffset = ((FlxG.height * (1/cameras[0].zoom)) * 0.5);
|
||||
|
||||
minStep = (conductorSprY - zoomOffset)/40;
|
||||
maxStep = (conductorSprY + zoomOffset)/40;
|
||||
|
||||
var minTime:Float = Conductor.getStepsInTime(minStep);
|
||||
var maxTime:Float = Conductor.getStepsInTime(maxStep);
|
||||
|
||||
var minBpmChange = Conductor.bpmChangeMap[Conductor.getTimeInChangeIndex(minTime)];
|
||||
var maxBpmChange = Conductor.bpmChangeMap[Conductor.getTimeInChangeIndex(maxTime)];
|
||||
|
||||
minBeat = Conductor.getTimeInBeats(minTime);
|
||||
maxBeat = Conductor.getTimeInBeats(maxTime);
|
||||
|
||||
minMeasure = minBpmChange.measureTime + (minBeat - minBpmChange.beatTime) / minBpmChange.beatsPerMeasure;
|
||||
maxMeasure = maxBpmChange.measureTime + (maxBeat - maxBpmChange.beatTime) / maxBpmChange.beatsPerMeasure;
|
||||
|
||||
//cap out the beats/measures at the end of the song
|
||||
var endTime = Conductor.getStepsInTime(Charter.instance.__endStep);
|
||||
var endBeat = Conductor.getTimeInBeats(endTime);
|
||||
var endBpmChange = Conductor.bpmChangeMap[Conductor.getTimeInChangeIndex(endTime)];
|
||||
var endMeasure = endBpmChange.measureTime + (endBeat - endBpmChange.beatTime) / endBpmChange.beatsPerMeasure;
|
||||
|
||||
if (maxBeat > endBeat) maxBeat = endBeat;
|
||||
if (maxMeasure > endMeasure) maxMeasure = endMeasure;
|
||||
if (minMeasure < 0) minMeasure = 0;
|
||||
if (minBeat < 0) minBeat = 0;
|
||||
|
||||
//only calculate if needed
|
||||
if ((minBeat != lastMinBeat) || (maxBeat != lastMaxBeat) || (minMeasure != lastMinMeasure) || (maxMeasure != lastMaxMeasure) || lastConductorSprY == Math.NEGATIVE_INFINITY) {
|
||||
calculateTimeSignatureGaps();
|
||||
calculateStepTimes();
|
||||
lastMinBeat = minBeat;
|
||||
lastMaxBeat = maxBeat;
|
||||
lastMinMeasure = minMeasure;
|
||||
lastMaxMeasure = maxMeasure;
|
||||
}
|
||||
|
||||
lastConductorSprY = conductorSprY;
|
||||
}
|
||||
|
||||
private inline function calculateTimeSignatureGaps() {
|
||||
//for time signatures that start mid step
|
||||
timeSignatureChangeGaps.splice(0, timeSignatureChangeGaps.length);
|
||||
for (i => change in Conductor.bpmChangeMap) {
|
||||
if (change.stepTime >= minStep && change.stepTime <= maxStep) {
|
||||
//get step while ignoring the current change
|
||||
var index = CoolUtil.boundInt(i-1, 0, Conductor.bpmChangeMap.length - 1);
|
||||
var step = Conductor.getTimeWithBPMInSteps(change.songTime, index, Conductor.getTimeWithIndexInBPM(change.songTime, index));
|
||||
|
||||
if (Math.ceil(step) - step > 0) { //mid step change
|
||||
timeSignatureChangeGaps.push(step);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline function calculateStepTimes() {
|
||||
beatStepTimes.splice(0, beatStepTimes.length);
|
||||
for (i in Math.floor(minBeat)...Math.ceil(maxBeat)) {
|
||||
beatStepTimes.push(Conductor.getTimeInSteps(Conductor.getBeatsInTime(i)));
|
||||
}
|
||||
measureStepTimes.splice(0, measureStepTimes.length);
|
||||
for (i in Math.floor(minMeasure)...Math.ceil(maxMeasure)) {
|
||||
measureStepTimes.push(Conductor.getTimeInSteps(Conductor.getMeasuresInTime(i)));
|
||||
}
|
||||
}
|
||||
|
||||
override public function draw() {
|
||||
|
||||
//should only need to recalculate once per frame and will be shared across each instance
|
||||
recalculateBeats();
|
||||
|
||||
drawTimeSignatureChangeGaps();
|
||||
|
||||
if (Options.charterShowBeats) drawBeats();
|
||||
if (Options.charterShowSections) drawMeasures();
|
||||
}
|
||||
|
||||
private function drawBeats(offset:Float = 0.0) {
|
||||
for (i in beatStepTimes) {
|
||||
y = (i*40)+offset;
|
||||
super.draw();
|
||||
}
|
||||
}
|
||||
private function drawMeasures(offset:Float = 0.0) {
|
||||
for (i in measureStepTimes) {
|
||||
y = (i*40)+offset;
|
||||
super.draw();
|
||||
}
|
||||
}
|
||||
private function drawTimeSignatureChangeGaps() {
|
||||
if (timeSignatureChangeGaps.length == 0) return;
|
||||
var prevColor = color;
|
||||
var prevBlend = blend;
|
||||
|
||||
color = 0xFF888888;
|
||||
blend = MULTIPLY;
|
||||
|
||||
for (step in timeSignatureChangeGaps) {
|
||||
y = step*40;
|
||||
var diff = Math.ceil(step) - step;
|
||||
scale.y = diff*40;
|
||||
updateHitbox();
|
||||
|
||||
super.draw();
|
||||
}
|
||||
|
||||
color = prevColor;
|
||||
blend = prevBlend;
|
||||
}
|
||||
}
|
||||
|
||||
class CharterGridSeperator extends CharterGridSeperatorBase {
|
||||
override private function drawBeats(offset:Float = 0.0) {
|
||||
scale.y = 2;
|
||||
updateHitbox();
|
||||
super.drawBeats(-2);
|
||||
}
|
||||
override private function drawMeasures(offset:Float = 0.0) {
|
||||
scale.y = 4;
|
||||
updateHitbox();
|
||||
super.drawMeasures(-3);
|
||||
}
|
||||
}
|
||||
|
||||
class CharterBackdropDummy extends UISprite {
|
||||
var parent:CharterBackdropGroup;
|
||||
public function new(parent:CharterBackdropGroup) {
|
||||
@@ -258,8 +394,7 @@ class CharterBackdropDummy extends UISprite {
|
||||
}
|
||||
|
||||
class EventBackdrop extends FlxBackdrop {
|
||||
public var eventBeatSeparator:FlxBackdrop;
|
||||
public var eventSecSeparator:FlxBackdrop;
|
||||
public var eventBeatSeparator:CharterEventGridSeperator;
|
||||
|
||||
public var topSeparator:FlxSprite;
|
||||
public var bottomSeparator:FlxSprite;
|
||||
@@ -269,25 +404,10 @@ class EventBackdrop extends FlxBackdrop {
|
||||
alpha = 0.9;
|
||||
|
||||
// Separators
|
||||
eventSecSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
eventSecSeparator.y = -2;
|
||||
eventSecSeparator.visible = Options.charterShowSections;
|
||||
|
||||
eventBeatSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
eventBeatSeparator.y = -1;
|
||||
eventBeatSeparator.visible = Options.charterShowBeats;
|
||||
|
||||
for(sep in [eventSecSeparator, eventBeatSeparator]) {
|
||||
sep.makeSolid(1, 1, -1);
|
||||
sep.alpha = 0.5;
|
||||
sep.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
eventSecSeparator.scale.set(20, 4);
|
||||
eventSecSeparator.updateHitbox();
|
||||
|
||||
eventBeatSeparator.scale.set(10, 2);
|
||||
eventBeatSeparator.updateHitbox();
|
||||
eventBeatSeparator = new CharterEventGridSeperator();
|
||||
eventBeatSeparator.makeSolid(1, 1, -1);
|
||||
eventBeatSeparator.alpha = 0.5;
|
||||
eventBeatSeparator.scrollFactor.set(1, 1);
|
||||
|
||||
bottomSeparator = new FlxSprite(0,-2);
|
||||
bottomSeparator.makeSolid(1, 1, -1);
|
||||
@@ -308,23 +428,32 @@ class EventBackdrop extends FlxBackdrop {
|
||||
public override function draw() {
|
||||
super.draw();
|
||||
|
||||
eventSecSeparator.spacing.y = (10 * Conductor.beatsPerMeasure * Conductor.stepsPerBeat) - 1;
|
||||
eventBeatSeparator.spacing.y = (20 * Conductor.stepsPerBeat) - 1;
|
||||
|
||||
eventSecSeparator.cameras = cameras;
|
||||
eventSecSeparator.x = (x+width) - 20;
|
||||
if (eventSecSeparator.visible) eventSecSeparator.draw();
|
||||
|
||||
eventBeatSeparator.cameras = cameras;
|
||||
eventBeatSeparator.x = (x+width) - 10;
|
||||
if (eventBeatSeparator.visible) eventBeatSeparator.draw();
|
||||
eventBeatSeparator.xPos = x+width;
|
||||
eventBeatSeparator.draw();
|
||||
|
||||
topSeparator.x = (x+width) - 20;
|
||||
topSeparator.cameras = this.cameras;
|
||||
if (!eventSecSeparator.visible) topSeparator.draw();
|
||||
if (!Options.charterShowSections) topSeparator.draw();
|
||||
|
||||
bottomSeparator.x = (x+width) - 20;
|
||||
bottomSeparator.cameras = this.cameras;
|
||||
bottomSeparator.draw();
|
||||
}
|
||||
}
|
||||
class CharterEventGridSeperator extends CharterGridSeperatorBase {
|
||||
public var xPos:Float = 0.0;
|
||||
override private function drawBeats(offset:Float = 0.0) {
|
||||
scale.set(10, 2);
|
||||
updateHitbox();
|
||||
x = xPos-10;
|
||||
super.drawBeats(-2);
|
||||
}
|
||||
override private function drawMeasures(offset:Float = 0.0) {
|
||||
scale.set(20, 4);
|
||||
updateHitbox();
|
||||
x = xPos-20;
|
||||
super.drawMeasures(-3);
|
||||
}
|
||||
override private function drawTimeSignatureChangeGaps() {}
|
||||
}
|
||||
Reference in New Issue
Block a user