Change event params a bit and fix cam zooming
This commit is contained in:
@@ -33,7 +33,7 @@ class EventsData {
|
||||
],
|
||||
"BPM Change" => [{name: "Target BPM", type: TFloat(1.00, 9999, 0.001, 3), defValue: 100}],
|
||||
"Continuous BPM Change" => [{name: "Target BPM", type: TFloat(1.00, 9999, 0.001, 3), defValue: 100}, {name: "Time (steps)", type: TFloat(0.25, 9999, 0.25, 2), defValue: 4}],
|
||||
"Time Signature Change" => [{name: "Target Beat Count", type: TFloat(1), defValue: 4}, {name: "Target Step Count", type: TFloat(1), defValue: 4}],
|
||||
"Time Signature Change" => [{name: "Target Numerator", type: TFloat(1), defValue: 4}, {name: "Target Denominator", type: TFloat(1), defValue: 4}],
|
||||
"Scroll Speed Change" => [
|
||||
{name: "Tween Speed?", type: TBool, defValue: true},
|
||||
{name: "New Speed", type: TFloat(0.01, 99, 0.01, 2), defValue: 1.},
|
||||
|
||||
@@ -6,6 +6,12 @@ import funkin.backend.chart.ChartData;
|
||||
import funkin.backend.system.interfaces.IBeatReceiver;
|
||||
import funkin.editors.charter.Charter;
|
||||
|
||||
enum BeatType {
|
||||
STEP;
|
||||
BEAT;
|
||||
MEASURE;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
class BPMChangeEvent
|
||||
{
|
||||
@@ -25,6 +31,16 @@ class BPMChangeEvent
|
||||
|
||||
final class Conductor
|
||||
{
|
||||
public static function getBeats(?every:BeatType, interval:Float, offset:Float = 0):Float {
|
||||
final beat = switch(every) {
|
||||
case MEASURE: curMeasureFloat;
|
||||
case STEP: curStepFloat;
|
||||
default: curBeatFloat;
|
||||
}
|
||||
if (interval <= 0) return beat - offset;
|
||||
else return Math.floor((beat - offset) * interval) / interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* FlxSignals
|
||||
*/
|
||||
@@ -96,12 +112,21 @@ final class Conductor
|
||||
return bpmChangeMap.length == 0 ? 4 : bpmChangeMap[curChangeIndex].beatsPerMeasure;
|
||||
|
||||
/**
|
||||
* Number of steps per beat (bottom number in time signature). Defaults to 4.
|
||||
* Number of steps per beat. Defaults to 4.
|
||||
* Not a divisor number for time signature, it does the complete opposite.
|
||||
* It's because CNE Conductor is based in sixteenth note instead of beat.
|
||||
*/
|
||||
public static var stepsPerBeat(get, never):Float;
|
||||
public static var stepsPerBeat(get, never):Int;
|
||||
private static function get_stepsPerBeat()
|
||||
return bpmChangeMap.length == 0 ? 4 : bpmChangeMap[curChangeIndex].stepsPerBeat;
|
||||
|
||||
/**
|
||||
* How much value notes to divide for beat (bottom or divisor number in time signature).
|
||||
* Only for a convinient way to access divisor instead of multiply by steps per beat.
|
||||
*/
|
||||
public static var denominator(get, never):Int;
|
||||
private static function get_denominator() return Math.floor(16 / stepsPerBeat);
|
||||
|
||||
/**
|
||||
* Current step
|
||||
*/
|
||||
@@ -231,13 +256,13 @@ final class Conductor
|
||||
|
||||
if (curChange.songTime != time) curChange = mapBPMChange(curChange, time, curChange.bpm);
|
||||
curChange.beatsPerMeasure = params[0];
|
||||
curChange.stepsPerBeat = params[1];
|
||||
|
||||
curChange.stepsPerBeat = Math.floor(16 / params[1]); // convert from denominator to stepsPerBeat
|
||||
|
||||
curChange.stepTime = CoolUtil.floorInt(curChange.stepTime + .99998);
|
||||
curChange.beatTime = CoolUtil.floorInt(curChange.beatTime + .99998);
|
||||
curChange.measureTime = CoolUtil.floorInt(curChange.measureTime + .99998);
|
||||
} else if (name == "Continuous BPM Change") {
|
||||
|
||||
}
|
||||
else if (name == "Continuous BPM Change") {
|
||||
var prevBPM = curChange.bpm;
|
||||
if (curChange.bpm == params[0]) {
|
||||
invalidEvents.push(e);
|
||||
@@ -266,7 +291,7 @@ final class Conductor
|
||||
bpmChangeMap = [curChange];
|
||||
invalidEvents = [];
|
||||
|
||||
for(event in Charter.instance.eventsGroup.members) {
|
||||
for (event in Charter.instance.eventsGroup.members) {
|
||||
event.events.sort(function(a, b) {
|
||||
if (MathUtil.equal(a.time, b.time)) {
|
||||
if (a.name == "Continuous BPM Change") return 1;
|
||||
@@ -282,11 +307,8 @@ final class Conductor
|
||||
if ((e.name == "BPM Change" || e.name == "Time Signature Change" || e.name == "Continuous BPM Change")) {
|
||||
curChange = mapEvent(e, curChange);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static var elapsed:Float;
|
||||
@@ -303,12 +325,10 @@ final class Conductor
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastSongPos != (lastSongPos = FlxG.sound.music.time - songOffset)) {
|
||||
// update conductor
|
||||
if (lastSongPos != (lastSongPos = FlxG.sound.music.time - songOffset))
|
||||
songPosition = lastSongPos;
|
||||
} else {
|
||||
else
|
||||
songPosition += songOffset + elapsed * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
private static function onStateSwitch(newState:FlxState) {
|
||||
|
||||
@@ -13,7 +13,7 @@ class ConductorInfo extends FramerateCategory {
|
||||
_text += '\n - ${Conductor.curStep} steps';
|
||||
_text += '\n - ${Conductor.curMeasure} measures';
|
||||
_text += '\nCurrent BPM: ${Conductor.bpm}';
|
||||
_text += '\nTime Signature: ${Conductor.beatsPerMeasure}/${Conductor.stepsPerBeat}';
|
||||
_text += '\nTime Signature: ${Conductor.beatsPerMeasure}/${Conductor.denominator}';
|
||||
|
||||
this.text.text = _text;
|
||||
super.__enterFrame(t);
|
||||
|
||||
@@ -1243,12 +1243,13 @@ class Charter extends UIState {
|
||||
for (strumLine in strumLines.members) strumLine.vocals.pause();
|
||||
}
|
||||
|
||||
songPosInfo.text = '${CoolUtil.timeToStr(Conductor.songPosition)} / ${CoolUtil.timeToStr(songLength)}'
|
||||
+ '\nStep: ${curStep}'
|
||||
+ '\nBeat: ${curBeat}'
|
||||
+ '\nMeasure: ${curMeasure}'
|
||||
+ '\nBPM: ${Math.floor(Conductor.bpm*1000)/1000}'
|
||||
+ '\nTime Signature: ${Conductor.beatsPerMeasure}/${Conductor.stepsPerBeat}';
|
||||
var curChange = Conductor.curChange;
|
||||
songPosInfo.text = '${CoolUtil.timeToStr(songPos)} / ${CoolUtil.timeToStr(songLength)}'
|
||||
+ '\nStep: $curStep'
|
||||
+ '\nBeat: $curBeat'
|
||||
+ '\nMeasure: $curMeasure'
|
||||
+ '\nBPM: ${(curChange != null && curChange.continuous && curChange.endSongTime > songPos) ? CoolUtil.quantize(Conductor.bpm, 2) : Conductor.bpm}'
|
||||
+ '\nTime Signature: ${Conductor.beatsPerMeasure}/${Conductor.denominator}';
|
||||
|
||||
if (charterCamera.zoom != (charterCamera.zoom = lerp(charterCamera.zoom, __camZoom, __firstFrame ? 1 : 0.125)))
|
||||
updateDisplaySprites();
|
||||
|
||||
@@ -140,7 +140,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
|
||||
graphic = defaultPath;
|
||||
}
|
||||
|
||||
return new FlxSprite().loadGraphic(graphic);
|
||||
return new FlxSprite(graphic);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,7 +154,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
|
||||
public static function getEventComponent(type:String, x:Float = 0.0, y:Float = 0.0) {
|
||||
var componentPath = Paths.image("editors/charter/event-icons/components/" + type);
|
||||
if(Assets.exists(componentPath))
|
||||
return new FlxSprite(x, y).loadGraphic(componentPath);
|
||||
return new FlxSprite(x, y, componentPath);
|
||||
|
||||
Logs.trace('Could not find component $type', WARNING);
|
||||
return null;
|
||||
@@ -423,12 +423,10 @@ class EventNumber extends FlxSprite {
|
||||
this.align = align;
|
||||
this.spacing = spacing;
|
||||
|
||||
|
||||
|
||||
if (number == 0) {
|
||||
this.digits.insert(0, 0);
|
||||
} else {
|
||||
|
||||
}
|
||||
else {
|
||||
var decimals:Float = FlxMath.roundDecimal(Math.abs(number % 1), precision);
|
||||
if (decimals > 0) this.digits.insert(0, FRAME_POINT);
|
||||
while(decimals > 0) {
|
||||
|
||||
@@ -15,7 +15,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
public var songNameTextBox:UITextBox;
|
||||
public var bpmStepper:UINumericStepper;
|
||||
public var beatsPerMeasureStepper:UINumericStepper;
|
||||
public var stepsPerBeatStepper :UINumericStepper;
|
||||
public var denominatorStepper :UINumericStepper;
|
||||
public var needsVoicesCheckbox:UICheckbox;
|
||||
public var customPropertiesButtonList:UIButtonList<PropertyButton>;
|
||||
|
||||
@@ -63,10 +63,10 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
|
||||
add(new UIText(beatsPerMeasureStepper.x + 30, beatsPerMeasureStepper.y + 3, 0, "/", 22));
|
||||
|
||||
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, metadata.stepsPerBeat, 1, 0, 1, null, 54);
|
||||
add(stepsPerBeatStepper);
|
||||
denominatorStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, Math.floor(16 / metadata.stepsPerBeat), 1, 0, 1, null, 54);
|
||||
add(denominatorStepper);
|
||||
|
||||
needsVoicesCheckbox = new UICheckbox(stepsPerBeatStepper.x + 80 + 26, stepsPerBeatStepper.y, "Voices", metadata.needsVoices);
|
||||
needsVoicesCheckbox = new UICheckbox(denominatorStepper.x + 80 + 26, denominatorStepper.y, "Voices", metadata.needsVoices);
|
||||
add(needsVoicesCheckbox);
|
||||
addLabelOn(needsVoicesCheckbox, "Needs Voices");
|
||||
needsVoicesCheckbox.y += 6; needsVoicesCheckbox.x += 4;
|
||||
@@ -142,7 +142,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
}
|
||||
|
||||
public function saveMeta() {
|
||||
for (stepper in [bpmStepper, beatsPerMeasureStepper, stepsPerBeatStepper])
|
||||
for (stepper in [bpmStepper, beatsPerMeasureStepper, denominatorStepper])
|
||||
@:privateAccess stepper.__onChange(stepper.label.text);
|
||||
|
||||
var customVals = {};
|
||||
@@ -154,7 +154,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
name: songNameTextBox.label.text,
|
||||
bpm: bpmStepper.value,
|
||||
beatsPerMeasure: Std.int(beatsPerMeasureStepper.value),
|
||||
stepsPerBeat: Std.int(stepsPerBeatStepper.value),
|
||||
stepsPerBeat: Std.int(16 / denominatorStepper.value),
|
||||
needsVoices: needsVoicesCheckbox.checked,
|
||||
displayName: displayNameTextBox.label.text,
|
||||
icon: iconTextBox.label.text,
|
||||
|
||||
@@ -19,7 +19,7 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
public var songNameTextBox:UITextBox;
|
||||
public var bpmStepper:UINumericStepper;
|
||||
public var beatsPerMeasureStepper:UINumericStepper;
|
||||
public var stepsPerBeatStepper :UINumericStepper;
|
||||
public var denominatorStepper :UINumericStepper;
|
||||
public var needsVoicesCheckbox:UICheckbox;
|
||||
public var instExplorer:UIFileExplorer;
|
||||
public var voicesExplorer:UIFileExplorer;
|
||||
@@ -79,12 +79,12 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
|
||||
songDataGroup.add(new UIText(beatsPerMeasureStepper.x + 30, beatsPerMeasureStepper.y + 3, 0, "/", 22));
|
||||
|
||||
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
|
||||
songDataGroup.add(stepsPerBeatStepper);
|
||||
denominatorStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
|
||||
songDataGroup.add(denominatorStepper);
|
||||
|
||||
var voicesUIText:UIText = null;
|
||||
|
||||
needsVoicesCheckbox = new UICheckbox(stepsPerBeatStepper.x + 80 + 26, stepsPerBeatStepper.y, "Voices", true);
|
||||
needsVoicesCheckbox = new UICheckbox(denominatorStepper.x + 80 + 26, denominatorStepper.y, "Voices", true);
|
||||
needsVoicesCheckbox.onChecked = function(checked) {
|
||||
if (voicesExplorer == null) return;
|
||||
|
||||
@@ -243,14 +243,14 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
}
|
||||
|
||||
function saveSongInfo() {
|
||||
for (stepper in [bpmStepper, beatsPerMeasureStepper, stepsPerBeatStepper])
|
||||
for (stepper in [bpmStepper, beatsPerMeasureStepper, denominatorStepper])
|
||||
@:privateAccess stepper.__onChange(stepper.label.text);
|
||||
|
||||
var meta:ChartMetaData = {
|
||||
name: songNameTextBox.label.text,
|
||||
bpm: bpmStepper.value,
|
||||
beatsPerMeasure: Std.int(beatsPerMeasureStepper.value),
|
||||
stepsPerBeat: Std.int(stepsPerBeatStepper.value),
|
||||
stepsPerBeat: Std.int(16 / denominatorStepper.value),
|
||||
needsVoices: needsVoicesCheckbox.checked,
|
||||
displayName: displayNameTextBox.label.text,
|
||||
icon: iconTextBox.label.text,
|
||||
|
||||
@@ -224,23 +224,29 @@ class PlayState extends MusicBeatState
|
||||
*/
|
||||
public var camZooming:Bool = false;
|
||||
/**
|
||||
* Interval of cam zooming (beats).
|
||||
* For example: if set to 4, the camera will zoom every 4 beats.
|
||||
* Interval of cam zooming (in conductor values).
|
||||
* Example: If Interval is 1 and Beat Type is on MEASURE, it'll zoom every a measure.
|
||||
* NOTE: Will set to 4 if not found any other time signatures unlike 4/4
|
||||
*/
|
||||
public var camZoomingInterval:Int = 4;
|
||||
public var camZoomingInterval:Float = 1;
|
||||
/**
|
||||
* Number of Conductor values to offset camZooming by.
|
||||
*/
|
||||
public var camZoomingOffset:Float = 0;
|
||||
/**
|
||||
* Beat type for interval of cam zooming.
|
||||
* Example: If Beat Type is on STEP and Interval is 2, it'll zoom every 2 steps.
|
||||
* NOTE: Will set to BEAT if not found any other time signatures unlike 4/4
|
||||
*/
|
||||
public var camZoomingEvery:BeatType = MEASURE;
|
||||
/**
|
||||
* Stores what was the last beat for the cam zooming intervals.
|
||||
*/
|
||||
public var camZoomingLastBeat:Float;
|
||||
/**
|
||||
* How strong the cam zooms should be (defaults to 1)
|
||||
*/
|
||||
public var camZoomingStrength:Float = 1;
|
||||
/**
|
||||
* Number of Beats to offset camZooming by.
|
||||
* Will automatically be set when a Time Signature Change Occurs.
|
||||
*/
|
||||
public var camZoomingOffset:Float = 0;
|
||||
/**
|
||||
* The curBeat position of the last Time Signature Change that occured
|
||||
*/
|
||||
public var lastTimeSigBeat:Float = 0;
|
||||
/**
|
||||
* Maximum amount of zoom for the camera.
|
||||
*/
|
||||
@@ -1020,21 +1026,34 @@ class PlayState extends MusicBeatState
|
||||
{
|
||||
if (songData == null) songData = SONG;
|
||||
|
||||
events = songData.events != null ? [for(e in songData.events) e] : [];
|
||||
// get first camera focus
|
||||
for(e in events) {
|
||||
if (e.time > 10) break;
|
||||
if (e.name == "Camera Movement") {
|
||||
executeEvent(e);
|
||||
break;
|
||||
var foundCam = false;
|
||||
var foundSigs = songData.meta.beatsPerMeasure.getDefault(4) != 4 || songData.meta.stepsPerBeat.getDefault(4) != 4;
|
||||
|
||||
if (events == null) events = [];
|
||||
else events = [
|
||||
for (e in songData.events) {
|
||||
switch (e.name) {
|
||||
case "Camera Movement": if (!foundCam && e.time < 10) {
|
||||
foundCam = true;
|
||||
executeEvent(e);
|
||||
}
|
||||
case "Time Signature Change": if (!foundSigs && (e.params[0] != 4 || e.params[1] != 4)) {
|
||||
foundSigs = true;
|
||||
}
|
||||
}
|
||||
e;
|
||||
}
|
||||
];
|
||||
|
||||
if (!foundSigs) {
|
||||
camZoomingInterval = 4;
|
||||
camZoomingEvery = BEAT;
|
||||
}
|
||||
|
||||
events.sort(function(p1, p2) {
|
||||
return FlxSort.byValues(FlxSort.DESCENDING, p1.time, p2.time);
|
||||
});
|
||||
|
||||
camZoomingInterval = cast songData.meta.beatsPerMeasure.getDefault(4);
|
||||
|
||||
curSong = songData.meta.name.toLowerCase();
|
||||
|
||||
inst = FlxG.sound.load(Paths.inst(SONG.meta.name, difficulty));
|
||||
@@ -1284,6 +1303,15 @@ class PlayState extends MusicBeatState
|
||||
}
|
||||
}
|
||||
|
||||
if (Options.camZoomOnBeat && camZooming && FlxG.camera.zoom < maxCamZoom) {
|
||||
var beat = Conductor.getBeats(camZoomingEvery, camZoomingInterval, camZoomingOffset);
|
||||
if (camZoomingLastBeat != beat) {
|
||||
camZoomingLastBeat = beat;
|
||||
FlxG.camera.zoom += 0.015 * camZoomingStrength;
|
||||
camHUD.zoom += 0.03 * camZoomingStrength;
|
||||
}
|
||||
}
|
||||
|
||||
if (doIconBop)
|
||||
for (icon in iconArray)
|
||||
if (icon.updateBump != null)
|
||||
@@ -1470,9 +1498,6 @@ class PlayState extends MusicBeatState
|
||||
if (strumLines.members[event.params[0]] != null && strumLines.members[event.params[0]].characters != null)
|
||||
for (char in strumLines.members[event.params[0]].characters)
|
||||
if (char != null) char.playAnim(event.params[1], event.params[2], null);
|
||||
case "Time Signature Change":
|
||||
lastTimeSigBeat = Conductor.getTimeInBeats(event.time);
|
||||
// the rest is automatically handled by conductor
|
||||
case "Unknown": // nothing
|
||||
}
|
||||
}
|
||||
@@ -1885,13 +1910,6 @@ class PlayState extends MusicBeatState
|
||||
override function beatHit(curBeat:Int)
|
||||
{
|
||||
super.beatHit(curBeat);
|
||||
|
||||
camZoomingOffset = curBeat - lastTimeSigBeat;
|
||||
|
||||
if (Options.camZoomOnBeat && camZooming && FlxG.camera.zoom < maxCamZoom && camZoomingOffset % camZoomingInterval == 0) {
|
||||
FlxG.camera.zoom += 0.015 * camZoomingStrength;
|
||||
camHUD.zoom += 0.03 * camZoomingStrength;
|
||||
}
|
||||
|
||||
if (doIconBop)
|
||||
for (icon in iconArray)
|
||||
|
||||
@@ -53,7 +53,7 @@ class GameplayOptions extends OptionsScreen {
|
||||
__lastBeat = Conductor.curBeat;
|
||||
}
|
||||
|
||||
var beat = Math.floor(Conductor.getStepForTime(FlxG.sound.music.time) / Conductor.stepsPerBeat);
|
||||
var beat = Math.floor(Conductor.getTimeInBeats(FlxG.sound.music.time));
|
||||
if (__lastSongBeat != beat) {
|
||||
__metronome.replay();
|
||||
__lastSongBeat = beat;
|
||||
|
||||
Reference in New Issue
Block a user