Made more menus adapted to wide-screens & fixed some bugs

* Made stuff on the edge of the screen get moved away by the notch
* Made FreeplayState look better on wide-screens
* Adapted StoryMenuState to wide-screens
* Fixed the transition being small on some screen sizes
* refactored some code
This commit is contained in:
KarimAkra
2025-04-15 21:37:06 +03:00
parent 7b1abe437f
commit 9cf134fc2a
15 changed files with 448 additions and 230 deletions
+17 -10
View File
@@ -3,6 +3,7 @@ package;
import flixel.FlxG;
import flixel.FlxGame;
import flixel.FlxState;
import flixel.system.scaleModes.FullScreenScaleMode;
import funkin.Preferences;
import funkin.util.logging.CrashHandler;
import funkin.ui.debug.MemoryCounter;
@@ -139,16 +140,13 @@ class Main extends Sprite
#end
#if mobile
flixel.FlxG.game.addChild(fpsCounter);
FlxG.scaleMode = new flixel.system.scaleModes.FullScreenScaleMode();
#else
addChild(fpsCounter);
FlxG.scaleMode = new FullScreenScaleMode();
FlxG.game.addChild(fpsCounter);
#end
// #if desktop
// FlxG.stage.window.width = 1280;
// FlxG.stage.window.height = 540;
// #end
#if !mobile
addChild(fpsCounter);
#end
#if hxcpp_debug_server
trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.');
@@ -182,13 +180,22 @@ class Main extends Sprite
scale = scale < 1 ? scale : 1;
#end
if (fpsCounter != null) fpsCounter.scaleX = fpsCounter.scaleY = scale;
if (fpsCounter != null)
{
fpsCounter.scaleX = fpsCounter.scaleY = #if android (scale > 1 ? scale : 1) #else (scale < 1 ? scale : 1) #end;
#if mobile
fpsCounter.x = 10 + FullScreenScaleMode.notchSize.x;
#end
}
if (memoryCounter != null)
{
memoryCounter.scaleX = memoryCounter.scaleY = scale;
memoryCounter.y = 13 * scale;
memoryCounter.y = 13 * #if android (scale > 1 ? scale : 1) #else (scale < 1 ? scale : 1) #end;
#if mobile
memoryCounter.x = 10 + FullScreenScaleMode.notchSize.x;
#end
}
}
}
@@ -8,14 +8,25 @@ import flixel.FlxG;
import android.os.Build;
import android.Tools;
#end
#if mobile
import funkin.mobile.util.ScreenUtil;
#end
class FullScreenScaleMode extends BaseScaleMode
{
public static var windowScale:FlxPoint = FlxPoint.get(1, 1);
public static var cutoutSize:FlxPoint = FlxPoint.get(0, 0);
// x is game ratio, y is window ratio.
public static var ratio:FlxPoint = FlxPoint.get(-1, -1);
public static final cutoutSize:FlxPoint = FlxPoint.get(0, 0);
public static final notchPosition:FlxPoint = FlxPoint.get(0, 0);
public static final notchSize:FlxPoint = FlxPoint.get(0, 0);
public static final gameCutoutSize:FlxPoint = FlxPoint.get(0, 0);
public static final gameNotchPosition:FlxPoint = FlxPoint.get(0, 0);
public static final gameNotchSize:FlxPoint = FlxPoint.get(0, 0);
public static final windowScale:FlxPoint = FlxPoint.get(1, 1);
public static var gameRatio:Float = -1;
public static var windowRatio:Float = -1;
public static var ratioAxis:FlxAxes = X;
public static var enabled(default, set):Bool;
public static var instance:FullScreenScaleMode = null;
@@ -36,63 +47,112 @@ class FullScreenScaleMode extends BaseScaleMode
updateCutoutSize(Width, Height);
updateScaleOffset();
updateGamePosition();
#if mobile
updateNotch();
#end
if ((cutoutSize.x > 0 || cutoutSize.y > 0) && enabled)
{
// trace('\nresized the game!\nDevice Size: ${deviceSize}\nGame Size: ${gameSize}\nCutout Size: ${cutoutSize}');
fillScreen();
}
}
override function updateGameSize(Width:Int, Height:Int):Void
{
ratio.x = FlxG.width / FlxG.height;
ratio.y = Width / Height;
gameRatio = FlxG.width / FlxG.height;
windowRatio = Width / Height;
ratioAxis = ratio.y < ratio.x ? Y : X;
ratioAxis = windowRatio < gameRatio ? Y : X;
// trace('ratio axis: ' + ratioAxis);
if (ratioAxis == Y)
{
gameSize.x = Width;
gameSize.y = Math.floor(gameSize.x / ratio.x);
gameSize.y = Math.floor(gameSize.x / gameRatio);
enabled = false;
}
else
{
gameSize.y = Height;
gameSize.x = Math.floor(gameSize.y * ratio.x);
gameSize.x = Math.floor(gameSize.y * gameRatio);
}
}
public function updateCutoutSize(Width:Float, Height:Float)
{
cutoutSize.set(0, 0);
gameCutoutSize.set(0, 0);
if (ratioAxis == Y)
if (enabled)
{
cutoutSize.y = Height - gameSize.y;
}
else
{
cutoutSize.x = Width - gameSize.x;
if (ratioAxis == Y)
{
cutoutSize.y = Height - gameSize.y;
#if android
gameCutoutSize.y = cutoutSize.y / 2;
// #elseif ios
// gameCutoutSize.y = cutoutSize.y * 2;
#else
gameCutoutSize.y = cutoutSize.y;
#end
}
else
{
cutoutSize.x = Width - gameSize.x;
#if android
gameCutoutSize.x = cutoutSize.x / 2;
// #elseif ios
// gameCutoutSize.x = cutoutSize.x * 2;
#else
gameCutoutSize.x = cutoutSize.x;
#end
}
}
}
#if mobile
public function updateNotch()
{
if (enabled)
{
var notch:lime.math.Rectangle = ScreenUtil.getNotchRect();
notchPosition.set(notch.x, notch.y);
notchSize.set(notch.width, notch.height);
#if android
gameNotchPosition.set(notchPosition.x / 2, notchPosition.y / 2);
gameNotchSize.set(notchSize.x / 2, notchSize.y / 2);
// #elseif ios
// gameNotchPosition.set(notchPosition.x * 2, notchPosition.y * 2);
// gameNotchSize.set(notchSize.x * 2, notchSize.y * 2);
#else
gameNotchPosition.set(notchPosition.x, notchPosition.y);
gameNotchSize.set(notchSize.x, notchSize.y);
#end
}
else
{
notchPosition.set(0, 0);
gameNotchPosition.set(0, 0);
notchSize.set(0, 0);
gameNotchSize.set(0, 0);
}
}
#end
public function fillScreen()
{
// this scale thing needs to be looked into cuz it seems incorrect..
windowScale.set(1, 1);
if (ratioAxis == Y)
{
gameSize.y += cutoutSize.y;
FlxG.height = Math.floor(gameSize.y / scale.y);
windowScale.x = (FlxG.height / FlxG.initialHeight) / scale.y;
windowScale.y = (FlxG.height / FlxG.initialHeight);
}
else
{
gameSize.x += cutoutSize.x;
FlxG.width = Math.floor(gameSize.x / scale.x);
windowScale.x = (FlxG.width / FlxG.initialWidth) / scale.x;
windowScale.x = (FlxG.width / FlxG.initialWidth);
}
// trace('resized game with size $gameSize and scale ${scale}');
@@ -103,13 +163,12 @@ class FullScreenScaleMode extends BaseScaleMode
@:noCompletion
private static function set_enabled(Value:Bool):Bool
{
// No idea what to do about this for iOS
#if android
if (!(VERSION.SDK_INT >= VERSION_CODES.P || Tools.isTablet()))
// TODO (??): Make the game work properly on screens that are wide vertically
// TODO: Figure out a way to configure this for iOS Platforms.
if (ratioAxis == Y #if andorid || !(VERSION.SDK_INT >= VERSION_CODES.P || Tools.isTablet()) #end)
{
Value = false;
}
#end
enabled = Value;
@@ -129,6 +188,7 @@ class FullScreenScaleMode extends BaseScaleMode
if (FlxG.stage != null)
{
instance.onMeasure(FlxG.stage.stageWidth, FlxG.stage.stageHeight);
FlxG.signals.gameResized.dispatch(FlxG.stage.stageWidth, FlxG.stage.stageHeight);
}
}
+7
View File
@@ -127,6 +127,13 @@ class InitState extends FlxState
// Don't play transition in when entering the title state.
FlxTransitionableState.skipNextTransIn = true;
FlxG.signals.gameResized.add(function(width:Int, height:Int) {
FlxTransitionableState.defaultTransIn = new TransitionData(FADE, FlxColor.BLACK, 1, new FlxPoint(0, -1), tileData,
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
FlxTransitionableState.defaultTransOut = new TransitionData(FADE, FlxColor.BLACK, 0.7, new FlxPoint(0, 1), tileData,
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
});
//
// NEWGROUNDS API SETUP
//
@@ -82,7 +82,7 @@ class MobileControlsSchemeMenu extends MusicBeatSubState
hsv.saturation = 0.9;
hsv.value = 3.6;
menuBG.shader = hsv;
menuBG.setGraphicSize(Std.int(menuBG.width * 1.1));
menuBG.setGraphicSize(Std.int(FlxG.width * 1.1));
menuBG.updateHitbox();
menuBG.screenCenter();
menuBG.scrollFactor.set(0, 0);
+65
View File
@@ -0,0 +1,65 @@
package funkin.mobile.util;
#if ios
import funkin.mobile.external.ScreenUtils;
#elseif android
import android.Tools;
#end
import lime.math.Rectangle;
/**
* A Utility class to get mobile screen related informations.
*/
class ScreenUtil
{
/**
* Get `Rectangle` Object that contains the dimensions of the screen's Notch.
* @return Rectangle
*/
public static function getNotchRect():Rectangle
{
var rectangle:Rectangle = new Rectangle();
#if ios
final top:Float = -1;
final left:Float = -1;
final right:Float = -1;
final bottom:Float = -1;
ScreenUtils.getSafeAreaInsets(cpp.Pointer.addressOf(top).raw, cpp.Pointer.addressOf(bottom).raw, cpp.Pointer.addressOf(left).raw,
cpp.Pointer.addressOf(right).raw);
rectangle.x = left;
rectangle.y = top;
rectangle.width = right - left;
rectangle.height = bottom - top;
#elseif android
var rectDimensions:Array<Array<Float>> = [[], [], [], []];
for (rect in Tools.getCutoutDimensions())
{
rectDimensions[0].push(rect.x);
rectDimensions[1].push(rect.y);
rectDimensions[2].push(rect.width);
rectDimensions[3].push(rect.height);
}
for (i => dimensions in rectDimensions)
{
for (dimension in dimensions)
{
switch (i)
{
case 0:
rectangle.x += dimension;
case 1:
rectangle.y += dimension;
case 2:
rectangle.width += dimension;
case 3:
rectangle.height += dimension;
}
}
}
#end
return rectangle;
}
}
+1 -1
View File
@@ -1874,7 +1874,7 @@ class PlayState extends MusicBeatSubState
add(playerStrumline);
add(opponentStrumline);
var cutoutSize = flixel.system.scaleModes.FullScreenScaleMode.cutoutSize.x / 2.0;
var cutoutSize = flixel.system.scaleModes.FullScreenScaleMode.gameCutoutSize.x / 2.0;
// Position the player strumline on the right half of the screen
playerStrumline.x = (FlxG.width / 2 + Constants.STRUMLINE_X_OFFSET) + (cutoutSize / 2.0); // Classic style
// playerStrumline.x = FlxG.width - playerStrumline.width - Constants.STRUMLINE_X_OFFSET; // Centered style
+39 -25
View File
@@ -8,6 +8,7 @@ import funkin.graphics.FunkinSprite;
import flixel.effects.FlxFlicker;
import flixel.graphics.frames.FlxBitmapFont;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.system.scaleModes.FullScreenScaleMode;
import flixel.math.FlxPoint;
import funkin.ui.MusicBeatSubState;
import flixel.math.FlxRect;
@@ -88,6 +89,8 @@ class ResultState extends MusicBeatSubState
final cameraScroll:FunkinCamera;
final cameraEverything:FunkinCamera;
var blackTopBar:FlxSprite = new FlxSprite();
public function new(params:ResultsStateParams)
{
super();
@@ -119,15 +122,15 @@ class ResultState extends MusicBeatSubState
bgFlash = FlxGradient.createGradientFlxSprite(FlxG.width, FlxG.height, [0xFFFFF1A6, 0xFFFFF1BE], 90);
resultsAnim = FunkinSprite.createSparrow(-200, -10, "resultScreen/results");
resultsAnim = FunkinSprite.createSparrow(FlxG.width - (1480 + (FullScreenScaleMode.gameCutoutSize.x / 2)), -10, "resultScreen/results");
ratingsPopin = FunkinSprite.createSparrow(-135, 135, "resultScreen/ratingsPopin");
ratingsPopin = FunkinSprite.createSparrow(-135 + FullScreenScaleMode.gameNotchSize.x, 135, "resultScreen/ratingsPopin");
scorePopin = FunkinSprite.createSparrow(-180, 515, "resultScreen/scorePopin");
scorePopin = FunkinSprite.createSparrow(-180 + FullScreenScaleMode.gameNotchSize.x, 515, "resultScreen/scorePopin");
highscoreNew = new FlxSprite(44, 557);
highscoreNew = new FlxSprite(44 + FullScreenScaleMode.gameNotchSize.x, 557);
score = new ResultScore(35, 305, 10, params.scoreData.score);
score = new ResultScore(35 + FullScreenScaleMode.gameNotchSize.x, 305, 10, params.scoreData.score);
rankBg = new FunkinSprite(0, 0);
}
@@ -166,7 +169,7 @@ class ResultState extends MusicBeatSubState
add(bgFlash);
// The sound system which falls into place behind the score text. Plays every time!
var soundSystem:FlxSprite = FunkinSprite.createSparrow(-15, -180, 'resultScreen/soundSystem');
var soundSystem:FlxSprite = FunkinSprite.createSparrow(-15 + FullScreenScaleMode.gameNotchSize.x, -180, 'resultScreen/soundSystem');
soundSystem.animation.addByPrefix("idle", "sound system", 24, false);
soundSystem.visible = false;
new FlxTimer().start(8 / 24, _ -> {
@@ -199,7 +202,8 @@ class ResultState extends MusicBeatSubState
switch (animData.renderType)
{
case 'animateatlas':
var animation:FlxAtlasSprite = new FlxAtlasSprite(offsets[0], offsets[1], Paths.animateAtlas(animPath, animLibrary));
var animation:FlxAtlasSprite = new FlxAtlasSprite(offsets[0] + (FullScreenScaleMode.gameCutoutSize.x / 2), offsets[1],
Paths.animateAtlas(animPath, animLibrary));
animation.zIndex = animData.zIndex ?? 500;
animation.scale.set(animData.scale ?? 1.0, animData.scale ?? 1.0);
@@ -248,7 +252,7 @@ class ResultState extends MusicBeatSubState
// Add to the scene.
add(animation);
case 'sparrow':
var animation:FunkinSprite = FunkinSprite.createSparrow(offsets[0], offsets[1], animPath);
var animation:FunkinSprite = FunkinSprite.createSparrow(offsets[0] + (FullScreenScaleMode.gameCutoutSize.x / 2), offsets[1], animPath);
animation.animation.addByPrefix('idle', '', 24, false, false, false);
if (animData.loopFrame != null)
@@ -280,6 +284,16 @@ class ResultState extends MusicBeatSubState
add(songName);
blackTopBar.loadGraphic(funkin.util.BitmapUtil.createResultsBar());
blackTopBar.y = -blackTopBar.height;
FlxTween.tween(blackTopBar, {y: 0}, 7 / 24, {ease: FlxEase.quartOut, startDelay: 3 / 24});
blackTopBar.zIndex = 1010;
add(blackTopBar);
difficulty.y += (blackTopBar.height - 148);
clearPercentSmall.y += (blackTopBar.height - 148);
songName.y += (blackTopBar.height - 148);
var angleRad = songName.angle * Math.PI / 180;
speedOfTween.x = -1.0 * Math.cos(angleRad);
speedOfTween.y = -1.0 * Math.sin(angleRad);
@@ -291,12 +305,6 @@ class ResultState extends MusicBeatSubState
maskShaderDifficulty.swagMaskX = difficulty.x - 30;
var blackTopBar:FlxSprite = new FlxSprite().loadGraphic(Paths.image("resultScreen/topBarBlack"));
blackTopBar.y = -blackTopBar.height;
FlxTween.tween(blackTopBar, {y: 0}, 7 / 24, {ease: FlxEase.quartOut, startDelay: 3 / 24});
blackTopBar.zIndex = 1010;
add(blackTopBar);
resultsAnim.animation.addByPrefix("result", "results instance 1", 24, false);
resultsAnim.visible = false;
resultsAnim.zIndex = 1200;
@@ -370,10 +378,10 @@ class ResultState extends MusicBeatSubState
* NOTE: We display how many notes were HIT, not how many notes there were in total.
*
*/
var totalHit:TallyCounter = new TallyCounter(375, hStuf * 3, params.scoreData.tallies.totalNotesHit);
var totalHit:TallyCounter = new TallyCounter(375 + FullScreenScaleMode.gameNotchSize.x, hStuf * 3, params.scoreData.tallies.totalNotesHit);
ratingGrp.add(totalHit);
var maxCombo:TallyCounter = new TallyCounter(375, hStuf * 4, params.scoreData.tallies.maxCombo);
var maxCombo:TallyCounter = new TallyCounter(375 + FullScreenScaleMode.gameNotchSize.x, hStuf * 4, params.scoreData.tallies.maxCombo);
ratingGrp.add(maxCombo);
if (params.scoreData.tallies.totalNotesHit >= 1000)
@@ -387,19 +395,24 @@ class ResultState extends MusicBeatSubState
hStuf += 2;
var tallySick:TallyCounter = new TallyCounter(230, (hStuf * 5) + extraYOffset, params.scoreData.tallies.sick, 0xFF89E59E);
var tallySick:TallyCounter = new TallyCounter(230 + FullScreenScaleMode.gameNotchSize.x, (hStuf * 5) + extraYOffset, params.scoreData.tallies.sick,
0xFF89E59E);
ratingGrp.add(tallySick);
var tallyGood:TallyCounter = new TallyCounter(210, (hStuf * 6) + extraYOffset, params.scoreData.tallies.good, 0xFF89C9E5);
var tallyGood:TallyCounter = new TallyCounter(210 + FullScreenScaleMode.gameNotchSize.x, (hStuf * 6) + extraYOffset, params.scoreData.tallies.good,
0xFF89C9E5);
ratingGrp.add(tallyGood);
var tallyBad:TallyCounter = new TallyCounter(190, (hStuf * 7) + extraYOffset, params.scoreData.tallies.bad, 0xFFE6CF8A);
var tallyBad:TallyCounter = new TallyCounter(190 + FullScreenScaleMode.gameNotchSize.x, (hStuf * 7) + extraYOffset, params.scoreData.tallies.bad,
0xFFE6CF8A);
ratingGrp.add(tallyBad);
var tallyShit:TallyCounter = new TallyCounter(220, (hStuf * 8) + extraYOffset, params.scoreData.tallies.shit, 0xFFE68C8A);
var tallyShit:TallyCounter = new TallyCounter(220 + FullScreenScaleMode.gameNotchSize.x, (hStuf * 8) + extraYOffset, params.scoreData.tallies.shit,
0xFFE68C8A);
ratingGrp.add(tallyShit);
var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, params.scoreData.tallies.missed, 0xFFC68AE6);
var tallyMissed:TallyCounter = new TallyCounter(260 + FullScreenScaleMode.gameNotchSize.x, (hStuf * 9) + extraYOffset, params.scoreData.tallies.missed,
0xFFC68AE6);
ratingGrp.add(tallyMissed);
score.visible = false;
@@ -486,7 +499,8 @@ class ResultState extends MusicBeatSubState
trace('Clear percent target: ' + clearPercentFloat + ', round: ' + clearPercentTarget);
var clearPercentCounter:ClearPercentCounter = new ClearPercentCounter(FlxG.width / 2 + 190, FlxG.height / 2 - 70, clearPercentLerp);
var clearPercentCounter:ClearPercentCounter = new ClearPercentCounter((FlxG.width / 2 + 190) + (FullScreenScaleMode.gameCutoutSize.x / 2),
FlxG.height / 2 - 70, clearPercentLerp);
FlxTween.tween(clearPercentCounter, {curNumber: clearPercentTarget}, 58 / 24,
{
ease: FlxEase.quartOut,
@@ -651,18 +665,18 @@ class ResultState extends MusicBeatSubState
var diffYTween:Float = 122;
difficulty.y = -difficulty.height;
FlxTween.tween(difficulty, {y: diffYTween}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.8});
FlxTween.tween(difficulty, {y: diffYTween + (blackTopBar.height - 148)}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.8});
if (clearPercentSmall != null)
{
clearPercentSmall.x = (difficulty.x + difficulty.width) + 60;
clearPercentSmall.y = -clearPercentSmall.height;
FlxTween.tween(clearPercentSmall, {y: 122 - 5}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.85});
FlxTween.tween(clearPercentSmall, {y: (122 - 5) + (blackTopBar.height - 148)}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.85});
}
songName.y = -songName.height;
var fuckedupnumber = (10) * (songName.text.length / 15);
FlxTween.tween(songName, {y: diffYTween - 25 - fuckedupnumber}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.9});
FlxTween.tween(songName, {y: (diffYTween - 25 - fuckedupnumber) + ((blackTopBar.height - 148) / 1)}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.9});
songName.x = clearPercentSmall.x + 94;
new FlxTimer().start(timerLength, _ -> {
+2 -3
View File
@@ -155,10 +155,9 @@ class VideoCutscene
// Resize videos bigger or smaller than the screen.
vid.bitmap.onFormatSetup.add(function():Void {
if (vid == null) return;
vid.setGraphicSize(FlxG.width, FlxG.height);
vid.setGraphicSize(FlxG.initialWidth, FlxG.initialHeight);
vid.updateHitbox();
vid.x = 0;
vid.y = 0;
vid.screenCenter();
// vid.scale.set(0.5, 0.5);
});
@@ -90,6 +90,11 @@ class IntroSubState extends MusicBeatSubState
{
vid.zIndex = 0;
vid.bitmap.onEndReached.add(onLightsEnd);
vid.bitmap.onFormatSetup.add(() -> {
vid.setGraphicSize(FlxG.initialWidth, FlxG.initialHeight);
vid.updateHitbox();
vid.screenCenter();
});
add(vid);
if (vid.load(filePath)) vid.play();
+18 -12
View File
@@ -100,7 +100,7 @@ class FreeplayState extends MusicBeatSubState
/**
* For scaling some sprites on wide displays.
*/
public static var CUTOUT_WIDTH:Float = FullScreenScaleMode.cutoutSize.x / 1.5;
public static var CUTOUT_WIDTH:Float = FullScreenScaleMode.gameCutoutSize.x / 1.5;
/**
* For positioning the DJ on wide displays.
@@ -152,7 +152,7 @@ class FreeplayState extends MusicBeatSubState
var dj:Null<FreeplayDJ> = null;
#if mobile
var djHitbox:FlxSprite = new FlxSprite((FullScreenScaleMode.cutoutSize.x * DJ_POS_MULTI) + 58, 358);
var djHitbox:FlxSprite = new FlxSprite((FullScreenScaleMode.gameCutoutSize.x * DJ_POS_MULTI) + 58, 358);
#end
var ostName:FlxText;
@@ -217,7 +217,7 @@ class FreeplayState extends MusicBeatSubState
public function new(?params:FreeplayStateParams, ?stickers:StickerSubState)
{
// shit needs re-calculating.,.,.,.
CUTOUT_WIDTH = FullScreenScaleMode.cutoutSize.x / 1.5;
CUTOUT_WIDTH = FullScreenScaleMode.gameCutoutSize.x / 1.5;
currentCharacterId = params?.character ?? rememberedCharacterId;
styleData = FreeplayStyleRegistry.instance.fetchEntry(currentCharacterId);
@@ -623,7 +623,7 @@ class FreeplayState extends MusicBeatSubState
});
}
FlxTween.tween(grpDifficulties, {x: (CUTOUT_WIDTH * DJ_POS_MULTI) + 90}, 0.6, {ease: FlxEase.quartOut});
FlxTween.tween(grpDifficulties, {x: 90 + (CUTOUT_WIDTH * DJ_POS_MULTI)}, 0.6, {ease: FlxEase.quartOut});
if (diffSelLeft != null) diffSelLeft.visible = true;
if (diffSelRight != null) diffSelRight.visible = true;
@@ -690,7 +690,7 @@ class FreeplayState extends MusicBeatSubState
funnyCam.bgColor = FlxColor.TRANSPARENT;
FlxG.cameras.add(funnyCam, false);
rankVignette.scale.set(2, 2);
rankVignette.scale.set(2 * FullScreenScaleMode.windowScale.x, 2 * FullScreenScaleMode.windowScale.y);
rankVignette.updateHitbox();
rankVignette.blend = BlendMode.ADD;
// rankVignette.cameras = [rankCamera];
@@ -1665,7 +1665,7 @@ class FreeplayState extends MusicBeatSubState
// Reset position if no significant drag
else
{
diff.x = 90;
diff.x = 90 + (CUTOUT_WIDTH * DJ_POS_MULTI);
}
_sub = 0;
break;
@@ -1693,7 +1693,15 @@ class FreeplayState extends MusicBeatSubState
break;
}
}
// FlxG.mouse.visible = true;
else
{
for (diff in grpDifficulties.group.members)
{
if (diff == null || diff.difficultyId != currentDifficulty) continue;
if (diff.x != 90) diff.x = 90 + (CUTOUT_WIDTH * DJ_POS_MULTI);
}
}
#end
if (controls.BACK)
@@ -1812,12 +1820,12 @@ class FreeplayState extends MusicBeatSubState
final newX = (change > 0) ? 500 : -320;
busy = true;
FlxTween.tween(diff, {x: newX}, 0.1,
FlxTween.tween(diff, {x: newX + (CUTOUT_WIDTH * DJ_POS_MULTI)}, 0.05,
{
ease: FlxEase.circInOut,
onComplete: function(_) {
busy = false;
diff.x = 90;
diff.x = 90 + (CUTOUT_WIDTH * DJ_POS_MULTI);
diff.visible = false;
}
});
@@ -1891,8 +1899,8 @@ class FreeplayState extends MusicBeatSubState
final isCurrentDiff:Bool = diffSprite.difficultyId == currentDifficulty;
if (change == 0) diffSprite.visible = isCurrentDiff;
if (!isCurrentDiff || change == 0) continue;
FlxTween.tween(diffSprite, {x: 90 + (CUTOUT_WIDTH * DJ_POS_MULTI)}, 0.02, {ease: FlxEase.circInOut});
diffSprite.x = (change > 0) ? -320 : 500;
@@ -2587,9 +2595,7 @@ class FreeplaySongData
typedef FreeplayStateParams =
{
?character:String,
?fromCharSelect:Bool,
?fromResults:FromResultsParams,
};
+128 -129
View File
@@ -38,7 +38,7 @@ class OptionsState extends MusicBeatState
var menuBG = new FlxSprite().loadGraphic(Paths.image('menuBG'));
var hsv = new HSVShader(-0.6, 0.9, 3.6);
menuBG.shader = hsv;
menuBG.setGraphicSize(Std.int(menuBG.width * 1.1));
menuBG.setGraphicSize(Std.int(FlxG.width * 1.1));
menuBG.updateHitbox();
menuBG.screenCenter();
menuBG.scrollFactor.set(0, 0);
@@ -66,140 +66,139 @@ class OptionsState extends MusicBeatState
#else
controls.onExit.add(exitToMainMenu);
optionsCodex.setPage(Controls);
}
super.create();
}
function exitControls():Void
{
// Apply any changes to the controls.
PlayerSettings.reset();
PlayerSettings.init();
} super.create();
} function exitControls():Void
{
// Apply any changes to the controls.
PlayerSettings.reset();
PlayerSettings.init();
optionsCodex.switchPage(Options);
}
optionsCodex.switchPage(Options);
}
function exitToMainMenu()
{
optionsCodex.currentPage.enabled = false;
// TODO: Animate this transition?
FlxG.switchState(() -> new MainMenuState());
}
}
function exitToMainMenu()
{
optionsCodex.currentPage.enabled = false;
// TODO: Animate this transition?
FlxG.switchState(() -> new MainMenuState());
}
} /**
* Our default Page when we enter the OptionsState, a bit of the root
*/
/**
* Our default Page when we enter the OptionsState, a bit of the root
*/
class OptionsMenu extends Page<OptionsMenuPageName>
{
var items:TextMenuList;
public function new()
{
super();
add(items = new TextMenuList());
createItem("PREFERENCES", function() codex.switchPage(Preferences));
#if mobile
if (FlxG.gamepads.numActiveGamepads > 0)
{
createItem("CONTROLS", function() codex.switchPage(Controls));
}
createItem("CONTROL SCHEMES", function() {
FlxG.state.openSubState(new MobileControlsSchemeMenu());
});
#else
createItem("CONTROLS", function() codex.switchPage(Controls));
#end
createItem("INPUT OFFSETS", function() {
#if web
LoadingState.transitionToState(() -> new LatencyState());
#else
FlxG.state.openSubState(new LatencyState());
#end
});
#if FEATURE_NEWGROUNDS
if (NewgroundsClient.instance.isLoggedIn())
{
createItem("LOGOUT OF NG", function() {
NewgroundsClient.instance.logout(function() {
// Reset the options menu when logout succeeds.
// This means the login option will be displayed.
FlxG.resetState();
}, function() {
FlxG.log.warn("Newgrounds logout failed!");
});
});
}
else
{
createItem("LOGIN TO NG", function() {
NewgroundsClient.instance.login(function() {
// Reset the options menu when login succeeds.
// This means the logout option will be displayed.
// NOTE: If the user presses login and opens the browser,
// then navigates the UI
FlxG.resetState();
}, function() {
FlxG.log.warn("Newgrounds login failed!");
});
});
}
#end
createItem("CLEAR SAVE DATA", function() {
promptClearSaveData();
});
createItem("EXIT", exit);
}
function createItem(name:String, callback:Void->Void, fireInstantly = false)
{
var item = items.createItem(0, 100 + items.length * 100, name, BOLD, callback);
item.fireInstantly = fireInstantly;
item.screenCenter(X);
return item;
}
override function set_enabled(value:Bool)
{
items.enabled = value;
return super.set_enabled(value);
}
/**
* True if this page has multiple options, excluding the exit option.
* If false, there's no reason to ever show this page.
*/
public function hasMultipleOptions():Bool
{
return items.length > 2;
}
var prompt:Prompt;
function promptClearSaveData():Void
{
if (prompt != null) return;
prompt = new Prompt("This will delete
class OptionsMenu extends Page<OptionsMenuPageName>
{
var items:TextMenuList;
public function new()
{
super();
add(items = new TextMenuList());
createItem("PREFERENCES", function() codex.switchPage(Preferences));
#if mobile
if (FlxG.gamepads.numActiveGamepads > 0)
{
createItem("CONTROLS", function() codex.switchPage(Controls));
}
createItem("CONTROL SCHEMES", function() {
FlxG.state.openSubState(new MobileControlsSchemeMenu());
});
#else
createItem("CONTROLS", function() codex.switchPage(Controls));
#end
createItem("INPUT OFFSETS", function() {
#if web
LoadingState.transitionToState(() -> new LatencyState());
#else
FlxG.state.openSubState(new LatencyState());
#end
});
#if FEATURE_NEWGROUNDS
if (NewgroundsClient.instance.isLoggedIn())
{
createItem("LOGOUT OF NG", function() {
NewgroundsClient.instance.logout(function() {
// Reset the options menu when logout succeeds.
// This means the login option will be displayed.
FlxG.resetState();
}, function() {
FlxG.log.warn("Newgrounds logout failed!");
});
});
}
else
{
createItem("LOGIN TO NG", function() {
NewgroundsClient.instance.login(function() {
// Reset the options menu when login succeeds.
// This means the logout option will be displayed.
// NOTE: If the user presses login and opens the browser,
// then navigates the UI
FlxG.resetState();
}, function() {
FlxG.log.warn("Newgrounds login failed!");
});
});
}
#end
createItem("CLEAR SAVE DATA", function() {
promptClearSaveData();
});
createItem("EXIT", exit);
}
function createItem(name:String, callback:Void->Void, fireInstantly = false)
{
var item = items.createItem(0, 100 + items.length * 100, name, BOLD, callback);
item.fireInstantly = fireInstantly;
item.screenCenter(X);
return item;
}
override function set_enabled(value:Bool)
{
items.enabled = value;
return super.set_enabled(value);
}
/**
* True if this page has multiple options, excluding the exit option.
* If false, there's no reason to ever show this page.
*/
public function hasMultipleOptions():Bool
{
return items.length > 2;
}
var prompt:Prompt;
function promptClearSaveData():Void
{
if (prompt != null) return;
prompt = new Prompt("This will delete
\nALL your save data.
\nAre you sure?
", Custom("Delete", "Cancel"));
prompt.create();
prompt.createBgFromMargin(100, 0xFFFAFD6D);
prompt.back.scrollFactor.set(0, 0);
add(prompt);
prompt.create();
prompt.createBgFromMargin(100, 0xFFFAFD6D);
prompt.back.scrollFactor.set(0, 0);
add(prompt);
prompt.onYes = function() {
// Clear the save data.
funkin.save.Save.clearData();
prompt.onYes = function() {
// Clear the save data.
funkin.save.Save.clearData();
FlxG.switchState(() -> new funkin.InitState());
}
FlxG.switchState(() -> new funkin.InitState());
}
prompt.onNo = function() {
prompt.close();
prompt.destroy();
prompt = null;
}
}
}
enum abstract OptionsMenuPageName(String) to PageName
{
var Options = "options";
var Controls = "controls";
var Colors = "colors";
var Mods = "mods";
var Preferences = "preferences";
}
prompt.onNo = function() {
prompt.close();
prompt.destroy();
prompt = null;
}
}
}
enum abstract OptionsMenuPageName(String) to PageName
{
var Options = "options";
var Controls = "controls";
var Colors = "colors";
var Mods = "mods";
var Preferences = "preferences";
}
+4 -2
View File
@@ -26,6 +26,7 @@ import funkin.util.MathUtil;
import funkin.mobile.util.SwipeUtil;
import funkin.mobile.util.TouchUtil;
import openfl.utils.Assets;
import flixel.system.scaleModes.FullScreenScaleMode;
#if FEATURE_DISCORD_RPC
import funkin.api.discord.DiscordClient;
#end
@@ -197,7 +198,7 @@ class StoryMenuState extends MusicBeatState
buildLevelTitles();
leftDifficultyArrow = new FlxSprite(870, 480);
leftDifficultyArrow = new FlxSprite(FlxG.width - 410, 480);
leftDifficultyArrow.frames = Paths.getSparrowAtlas('storymenu/ui/arrows');
leftDifficultyArrow.animation.addByPrefix('idle', 'leftIdle0');
leftDifficultyArrow.animation.addByPrefix('press', 'leftConfirm0');
@@ -207,7 +208,7 @@ class StoryMenuState extends MusicBeatState
buildDifficultySprite(Constants.DEFAULT_DIFFICULTY);
buildDifficultySprite();
rightDifficultyArrow = new FlxSprite(1245, leftDifficultyArrow.y);
rightDifficultyArrow = new FlxSprite(FlxG.width - 35, leftDifficultyArrow.y);
rightDifficultyArrow.frames = leftDifficultyArrow.frames;
rightDifficultyArrow.animation.addByPrefix('idle', 'rightIdle0');
rightDifficultyArrow.animation.addByPrefix('press', 'rightConfirm0');
@@ -658,6 +659,7 @@ class StoryMenuState extends MusicBeatState
{
for (ind => prop in currentLevel.buildProps(levelProps.members))
{
prop.x += (FullScreenScaleMode.gameCutoutSize.x / 2);
prop.zIndex = 1000;
if (levelProps.members[ind] != prop) levelProps.replace(levelProps.members[ind], prop) ?? levelProps.add(prop);
}
+13 -2
View File
@@ -79,9 +79,19 @@ class AttractState extends MusicBeatState
{
vid.zIndex = 0;
vid.bitmap.onEndReached.add(onAttractEnd);
vid.bitmap.onFormatSetup.add(() -> {
vid.setGraphicSize(FlxG.initialWidth, FlxG.initialHeight);
vid.updateHitbox();
vid.screenCenter();
});
add(vid);
if (vid.load(filePath)) vid.play();
if (vid.load(filePath))
{
vid.play();
vid.updateHitbox();
vid.screenCenter();
}
}
else
{
@@ -95,7 +105,8 @@ class AttractState extends MusicBeatState
super.update(elapsed);
// If the user presses any button, skip the video.
if (FlxG.keys.justPressed.ANY && !controls.VOLUME_MUTE && !controls.VOLUME_UP && !controls.VOLUME_DOWN)
if ((FlxG.keys.justPressed.ANY && !controls.VOLUME_MUTE && !controls.VOLUME_UP && !controls.VOLUME_DOWN) #if mobile
|| funkin.mobile.util.TouchUtil.justPressed #end)
{
onAttractEnd();
}
+4 -3
View File
@@ -3,6 +3,7 @@ package funkin.ui.title;
import flixel.FlxSprite;
import flixel.group.FlxGroup;
import flixel.input.gamepad.FlxGamepad;
import flixel.system.scaleModes.FullScreenScaleMode;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
@@ -91,7 +92,7 @@ class TitleState extends MusicBeatState
bg.screenCenter();
add(bg);
logoBl = new FlxSprite(-150, -100);
logoBl = new FlxSprite(-150 + (FullScreenScaleMode.gameCutoutSize.x / 2), -100);
logoBl.frames = Paths.getSparrowAtlas('logoBumpin');
logoBl.animation.addByPrefix('bump', 'logo bumpin', 24);
logoBl.animation.play('bump');
@@ -100,7 +101,7 @@ class TitleState extends MusicBeatState
outlineShaderShit = new TitleOutline();
gfDance = new FlxSpriteOverlay(FlxG.width * 0.4, FlxG.height * 0.07);
gfDance = new FlxSpriteOverlay((FlxG.width * 0.4) + FullScreenScaleMode.gameCutoutSize.x / 2, FlxG.height * 0.07);
gfDance.frames = Paths.getSparrowAtlas('gfDanceTitle');
gfDance.animation.addByIndices('danceLeft', 'gfDance', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
gfDance.animation.addByIndices('danceRight', 'gfDance', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false);
@@ -118,7 +119,7 @@ class TitleState extends MusicBeatState
add(gfDance);
titleText = new FlxSprite(100, FlxG.height * 0.8);
titleText = new FlxSprite(100 + (FullScreenScaleMode.gameCutoutSize.x / 2), FlxG.height * 0.8);
titleText.frames = Paths.getSparrowAtlas('titleEnter');
titleText.animation.addByPrefix('idle', "Press Enter to Begin", 24);
titleText.animation.addByPrefix('press', "ENTER PRESSED", 24);
+61 -19
View File
@@ -1,5 +1,7 @@
package funkin.util;
import flixel.system.scaleModes.FullScreenScaleMode;
import flixel.FlxG;
import openfl.display.BitmapData;
import openfl.geom.Matrix;
import openfl.geom.Point;
@@ -7,34 +9,74 @@ import openfl.geom.Rectangle;
class BitmapUtil
{
public static function createResultsBar():BitmapData
{
final width:Int = Math.ceil(FlxG.width * 1.011);
final mainBitmap = new BitmapData(width, Math.ceil(width / 8.7), true, 0xFF000000);
final bitmap = new BitmapData(width, Math.ceil(width / 8.7), true, 0);
final rect = mainBitmap.rect.clone();
final matrix = new Matrix();
matrix.rotate(-3.8 * Math.PI / 180);
matrix.translate(-15, 0);
rect.width -= 15;
bitmap.draw(mainBitmap, matrix, rect, true);
return bitmap;
}
static var iiii:Int = 0;
/**
* Scales the bitmap at a specific position.
* @param bitmap The original bitmap to scale.
* @param scale The desired scale for the bitmap part (X Scale only).
* @param scalePosition The position of where it should scale the bitmap, If null it'll use the middle of the bitmap.
* @return A new BitmapData scaled at the specified position.
*/
public static function scalePart(bitmap:BitmapData, scale:Float, ?scalePosition:Float):BitmapData
{
if (scalePosition == null) scalePosition = bitmap.width / 2;
final scaledPartWidth:Int = Math.ceil(scalePosition * scale);
final finalBitmap:BitmapData = new BitmapData(Math.ceil(bitmap.width + scalePosition), bitmap.height, true, 0);
final matrix:Matrix = new Matrix();
final rect:Rectangle = bitmap.rect.clone();
matrix.scale(scale, 1);
rect.width = scaledPartWidth;
finalBitmap.draw(bitmap, matrix, rect, true);
final rect:Rectangle = bitmap.rect.clone();
rect.x = scalePosition;
finalBitmap.copyPixels(bitmap, rect, new Point(scaledPartWidth, 0));
return finalBitmap;
}
/**
* Scales the bitmap by adding a specific width at a specific position.
* @param bitmap The original bitmap to modify.
* @param additionalWidth The desired additional width for one side of the bitmap.
* @param scalePosition The position of where it should the width should be added, If null it'll use the left side of the bitmap.
* @return A new BitmapData with the specified side scaled to the additional width.
* @param additionalWidth The desired additional width to add to the bitmap.
* @param scalePosition The position of where it should scale the bitmap, If null it'll use the middle of the bitmap.
* @return A new BitmapData scaled at the specified position.
*/
public static function scalePartByWidth(bitmap:BitmapData, additionalWidth:Float, ?scalePosition:Float):BitmapData
{
if (scalePosition == null) scalePosition = bitmap.width / 2;
var addedWidth = Math.floor(additionalWidth);
var scaledPartWidth = scalePosition + addedWidth;
var scaleFactor = scaledPartWidth / scalePosition;
final scaledPartWidth:Int = Math.ceil(scalePosition + additionalWidth);
final scale:Float = scaledPartWidth / scalePosition;
final finalBitmap:BitmapData = new BitmapData(Math.ceil(bitmap.width + additionalWidth), bitmap.height, true, 0);
var matrix = new Matrix();
matrix.scale(scaleFactor, 1);
final matrix:Matrix = new Matrix();
final rect:Rectangle = bitmap.rect.clone();
matrix.scale(scale, 1);
rect.width = scaledPartWidth;
finalBitmap.draw(bitmap, matrix, rect, true);
var scaledBitmap = new BitmapData(Math.floor(bitmap.width + addedWidth), bitmap.height, true, 0);
final rect:Rectangle = bitmap.rect.clone();
rect.x = scalePosition;
finalBitmap.copyPixels(bitmap, rect, new Point(scaledPartWidth, 0));
var leftPortionRect = new Rectangle(0, 0, scalePosition, bitmap.height);
var leftBitmap = new BitmapData(Math.floor(scalePosition), bitmap.height, true, 0);
leftBitmap.copyPixels(bitmap, leftPortionRect, new Point(0, 0));
scaledBitmap.draw(leftBitmap, matrix, null, null, new Rectangle(0, 0, scaledPartWidth, bitmap.height));
var rightPortion = new Rectangle(scalePosition, 0, bitmap.width - scalePosition, bitmap.height);
scaledBitmap.copyPixels(bitmap, rightPortion, new Point(scaledPartWidth, 0));
return scaledBitmap;
return finalBitmap;
}
}