2024-06-15 04:59:58 +00:00
|
|
|
package funkin.ui.charSelect;
|
|
|
|
|
|
|
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
|
|
|
import flixel.tweens.FlxTween;
|
|
|
|
import flixel.tweens.FlxEase;
|
|
|
|
import flixel.math.FlxMath;
|
|
|
|
import funkin.util.FramesJSFLParser;
|
|
|
|
import funkin.util.FramesJSFLParser.FramesJSFLInfo;
|
|
|
|
import funkin.util.FramesJSFLParser.FramesJSFLFrame;
|
2024-09-01 07:22:34 +00:00
|
|
|
import funkin.modding.IScriptedClass.IBPMSyncedScriptedClass;
|
2024-06-15 04:59:58 +00:00
|
|
|
import flixel.math.FlxMath;
|
2024-09-01 07:22:34 +00:00
|
|
|
import funkin.modding.events.ScriptEvent;
|
2024-08-22 21:36:43 +00:00
|
|
|
import funkin.vis.dsp.SpectralAnalyzer;
|
2024-06-15 04:59:58 +00:00
|
|
|
|
2024-09-01 07:22:34 +00:00
|
|
|
class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
|
2024-06-15 04:59:58 +00:00
|
|
|
{
|
|
|
|
var fadeTimer:Float = 0;
|
|
|
|
var fadingStatus:FadeStatus = OFF;
|
|
|
|
var fadeAnimIndex:Int = 0;
|
|
|
|
|
|
|
|
var animInInfo:FramesJSFLInfo;
|
|
|
|
var animOutInfo:FramesJSFLInfo;
|
|
|
|
|
|
|
|
var intendedYPos:Float = 0;
|
|
|
|
var intendedAlpha:Float = 0;
|
2024-08-22 21:36:43 +00:00
|
|
|
var list:Array<String> = [];
|
|
|
|
|
|
|
|
var analyzer:SpectralAnalyzer;
|
2024-06-15 04:59:58 +00:00
|
|
|
|
2024-08-29 18:32:10 +00:00
|
|
|
var curGF:GFChar = GF;
|
|
|
|
|
2024-06-15 04:59:58 +00:00
|
|
|
public function new()
|
|
|
|
{
|
|
|
|
super(0, 0, Paths.animateAtlas("charSelect/gfChill"));
|
2024-08-28 00:48:56 +00:00
|
|
|
|
2024-08-22 21:36:43 +00:00
|
|
|
list = anim.curSymbol.getFrameLabelNames();
|
|
|
|
|
2024-06-15 04:59:58 +00:00
|
|
|
switchGF("bf");
|
|
|
|
}
|
|
|
|
|
2024-08-29 18:32:10 +00:00
|
|
|
override public function update(elapsed:Float):Void
|
2024-06-15 04:59:58 +00:00
|
|
|
{
|
|
|
|
super.update(elapsed);
|
|
|
|
|
|
|
|
switch (fadingStatus)
|
|
|
|
{
|
|
|
|
case OFF:
|
|
|
|
// do nothing if it's off!
|
|
|
|
// or maybe force position to be 0,0?
|
|
|
|
// maybe reset timers?
|
|
|
|
resetFadeAnimParams();
|
|
|
|
case FADE_OUT:
|
|
|
|
doFade(animOutInfo);
|
|
|
|
case FADE_IN:
|
|
|
|
doFade(animInInfo);
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2024-09-01 07:22:34 +00:00
|
|
|
#if FEATURE_DEBUG_FUNCTIONS
|
2024-06-15 04:59:58 +00:00
|
|
|
if (FlxG.keys.justPressed.J)
|
|
|
|
{
|
|
|
|
alpha = 1;
|
|
|
|
x = y = 0;
|
|
|
|
fadingStatus = FADE_OUT;
|
|
|
|
}
|
|
|
|
if (FlxG.keys.justPressed.K)
|
|
|
|
{
|
|
|
|
alpha = 0;
|
|
|
|
fadingStatus = FADE_IN;
|
|
|
|
}
|
2024-09-01 07:22:34 +00:00
|
|
|
#end
|
2024-06-15 04:59:58 +00:00
|
|
|
}
|
|
|
|
|
2024-09-01 07:22:34 +00:00
|
|
|
public function onStepHit(event:SongTimeScriptEvent):Void {}
|
|
|
|
|
|
|
|
var danceEvery:Int = 2;
|
|
|
|
|
|
|
|
public function onBeatHit(event:SongTimeScriptEvent):Void
|
|
|
|
{
|
|
|
|
// TODO: There's a minor visual bug where there's a little stutter.
|
|
|
|
// This happens because the animation is getting restarted while it's already playing.
|
|
|
|
// I tried make this not interrupt an existing idle,
|
|
|
|
// but isAnimationFinished() and isLoopComplete() both don't work! What the hell?
|
|
|
|
// danceEvery isn't necessary if that gets fixed.
|
|
|
|
if (getCurrentAnimation() == "idle" && (event.beat % danceEvery == 0))
|
|
|
|
{
|
|
|
|
trace('GF beat hit');
|
|
|
|
playAnimation("idle", true, false, false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-08-22 21:36:43 +00:00
|
|
|
override public function draw()
|
|
|
|
{
|
|
|
|
if (analyzer != null) drawFFT();
|
|
|
|
super.draw();
|
|
|
|
}
|
|
|
|
|
|
|
|
function drawFFT()
|
|
|
|
{
|
2024-08-29 19:26:35 +00:00
|
|
|
if (curGF == NENE)
|
2024-08-22 21:36:43 +00:00
|
|
|
{
|
|
|
|
var levels = analyzer.getLevels();
|
|
|
|
var frame = anim.curSymbol.timeline.get("VIZ_bars").get(anim.curFrame);
|
|
|
|
var elements = frame.getList();
|
|
|
|
var len:Int = cast Math.min(elements.length, 7);
|
|
|
|
|
|
|
|
for (i in 0...len)
|
|
|
|
{
|
|
|
|
var animFrame:Int = Math.round(levels[i].value * 12);
|
|
|
|
|
|
|
|
#if desktop
|
2024-09-04 14:58:18 +00:00
|
|
|
// Web version scales with the Flixel volume level.
|
|
|
|
// This line brings platform parity but looks worse.
|
|
|
|
// animFrame = Math.round(animFrame * FlxG.sound.volume);
|
2024-08-22 21:36:43 +00:00
|
|
|
#end
|
|
|
|
|
|
|
|
animFrame = Math.floor(Math.min(12, animFrame));
|
|
|
|
animFrame = Math.floor(Math.max(0, animFrame));
|
|
|
|
|
|
|
|
animFrame = Std.int(Math.abs(animFrame - 12)); // shitty dumbass flip, cuz dave got da shit backwards lol!
|
|
|
|
|
|
|
|
elements[i].symbol.firstFrame = animFrame;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-15 04:59:58 +00:00
|
|
|
/**
|
|
|
|
* @param animInfo Should not be confused with animInInfo!
|
|
|
|
* This is merely a local var for the function!
|
|
|
|
*/
|
2024-08-29 18:32:10 +00:00
|
|
|
function doFade(animInfo:FramesJSFLInfo):Void
|
2024-06-15 04:59:58 +00:00
|
|
|
{
|
|
|
|
fadeTimer += FlxG.elapsed;
|
|
|
|
if (fadeTimer >= 1 / 24)
|
|
|
|
{
|
|
|
|
fadeTimer = 0;
|
|
|
|
// only inc the index for the first frame, used for reference of where to "start"
|
|
|
|
if (fadeAnimIndex == 0)
|
|
|
|
{
|
|
|
|
fadeAnimIndex++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var curFrame:FramesJSFLFrame = animInfo.frames[fadeAnimIndex];
|
|
|
|
var prevFrame:FramesJSFLFrame = animInfo.frames[fadeAnimIndex - 1];
|
|
|
|
|
|
|
|
var xDiff:Float = curFrame.x - prevFrame.x;
|
|
|
|
var yDiff:Float = curFrame.y - prevFrame.y;
|
|
|
|
var alphaDiff:Float = curFrame.alpha - prevFrame.alpha;
|
|
|
|
alphaDiff /= 100; // flash exports alpha as a whole number
|
|
|
|
|
|
|
|
alpha += alphaDiff;
|
|
|
|
alpha = FlxMath.bound(alpha, 0, 1);
|
|
|
|
x += xDiff;
|
|
|
|
y += yDiff;
|
|
|
|
|
|
|
|
fadeAnimIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fadeAnimIndex >= animInfo.frames.length) fadingStatus = OFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
function resetFadeAnimParams()
|
|
|
|
{
|
|
|
|
fadeTimer = 0;
|
|
|
|
fadeAnimIndex = 0;
|
|
|
|
}
|
|
|
|
|
2024-08-29 18:32:10 +00:00
|
|
|
/**
|
|
|
|
* For switching between "GFs" such as gf, nene, etc
|
|
|
|
* @param bf Which BF we are selecting, so that we know the accompyaning GF
|
|
|
|
*/
|
|
|
|
public function switchGF(bf:String):Void
|
2024-06-15 04:59:58 +00:00
|
|
|
{
|
2024-08-29 18:32:10 +00:00
|
|
|
var prevGF:GFChar = curGF;
|
|
|
|
switch (bf)
|
2024-06-15 04:59:58 +00:00
|
|
|
{
|
|
|
|
case "pico":
|
2024-08-29 18:32:10 +00:00
|
|
|
curGF = NENE;
|
2024-06-15 04:59:58 +00:00
|
|
|
case "bf":
|
2024-08-29 18:32:10 +00:00
|
|
|
curGF = GF;
|
2024-06-15 04:59:58 +00:00
|
|
|
default:
|
2024-08-29 18:32:10 +00:00
|
|
|
curGF = GF;
|
2024-06-15 04:59:58 +00:00
|
|
|
}
|
|
|
|
|
2024-08-29 18:32:10 +00:00
|
|
|
// We don't need to update any anims if we didn't change GF
|
2024-09-01 07:22:34 +00:00
|
|
|
if (prevGF != curGF)
|
|
|
|
{
|
|
|
|
loadAtlas(Paths.animateAtlas("charSelect/" + curGF + "Chill"));
|
2024-06-15 04:59:58 +00:00
|
|
|
|
2024-09-01 07:22:34 +00:00
|
|
|
animInInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "In.txt"));
|
|
|
|
animOutInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "Out.txt"));
|
|
|
|
}
|
2024-06-15 04:59:58 +00:00
|
|
|
|
2024-09-01 07:22:34 +00:00
|
|
|
playAnimation("idle", true, false, false);
|
2024-08-28 00:48:56 +00:00
|
|
|
// addFrameCallback(getNextFrameLabel("idle"), () -> playAnimation("idle", true, false, false));
|
2024-06-15 04:59:58 +00:00
|
|
|
|
|
|
|
updateHitbox();
|
|
|
|
}
|
2024-09-01 07:22:34 +00:00
|
|
|
|
|
|
|
public function onScriptEvent(event:ScriptEvent):Void {};
|
|
|
|
|
|
|
|
public function onCreate(event:ScriptEvent):Void {};
|
|
|
|
|
|
|
|
public function onDestroy(event:ScriptEvent):Void {};
|
|
|
|
|
|
|
|
public function onUpdate(event:UpdateScriptEvent):Void {};
|
2024-06-15 04:59:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enum FadeStatus
|
|
|
|
{
|
|
|
|
OFF;
|
|
|
|
FADE_OUT;
|
|
|
|
FADE_IN;
|
|
|
|
}
|
2024-08-29 18:32:10 +00:00
|
|
|
|
|
|
|
enum abstract GFChar(String) from String to String
|
|
|
|
{
|
|
|
|
var GF = "gf";
|
|
|
|
var NENE = "nene";
|
|
|
|
}
|