diff --git a/source/Main.hx b/source/Main.hx index dbc4fe90e..c19d73f3e 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -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 } } } diff --git a/source/flixel/system/scaleModes/FullScreenScaleMode.hx b/source/flixel/system/scaleModes/FullScreenScaleMode.hx index e010b5f03..4148cf73e 100644 --- a/source/flixel/system/scaleModes/FullScreenScaleMode.hx +++ b/source/flixel/system/scaleModes/FullScreenScaleMode.hx @@ -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); } } diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index f4efd19e4..3da8f9395 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -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 // diff --git a/source/funkin/mobile/ui/options/MobileControlsSchemeMenu.hx b/source/funkin/mobile/ui/options/MobileControlsSchemeMenu.hx index deff43a96..be4137b83 100644 --- a/source/funkin/mobile/ui/options/MobileControlsSchemeMenu.hx +++ b/source/funkin/mobile/ui/options/MobileControlsSchemeMenu.hx @@ -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); diff --git a/source/funkin/mobile/util/ScreenUtil.hx b/source/funkin/mobile/util/ScreenUtil.hx new file mode 100644 index 000000000..4ca46848e --- /dev/null +++ b/source/funkin/mobile/util/ScreenUtil.hx @@ -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> = [[], [], [], []]; + 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; + } +} diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 6ca7b1e00..a3d91096f 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -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 diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index 03dcc6e68..75f43e5b3 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -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, _ -> { diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx index ab22119d3..1165a6044 100644 --- a/source/funkin/play/cutscene/VideoCutscene.hx +++ b/source/funkin/play/cutscene/VideoCutscene.hx @@ -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); }); diff --git a/source/funkin/ui/charSelect/IntroSubState.hx b/source/funkin/ui/charSelect/IntroSubState.hx index 51a4a52a7..f9b1233a0 100644 --- a/source/funkin/ui/charSelect/IntroSubState.hx +++ b/source/funkin/ui/charSelect/IntroSubState.hx @@ -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(); diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 37e220cc8..b268626c6 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -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 = 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, }; diff --git a/source/funkin/ui/options/OptionsState.hx b/source/funkin/ui/options/OptionsState.hx index 83c4083e7..e7e8702b8 100644 --- a/source/funkin/ui/options/OptionsState.hx +++ b/source/funkin/ui/options/OptionsState.hx @@ -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 -{ - 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 + { + 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"; + } diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx index 8d7529871..70ac4bd1d 100644 --- a/source/funkin/ui/story/StoryMenuState.hx +++ b/source/funkin/ui/story/StoryMenuState.hx @@ -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); } diff --git a/source/funkin/ui/title/AttractState.hx b/source/funkin/ui/title/AttractState.hx index 443feaceb..401ec006e 100644 --- a/source/funkin/ui/title/AttractState.hx +++ b/source/funkin/ui/title/AttractState.hx @@ -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(); } diff --git a/source/funkin/ui/title/TitleState.hx b/source/funkin/ui/title/TitleState.hx index d046fc159..1c8f5d82c 100644 --- a/source/funkin/ui/title/TitleState.hx +++ b/source/funkin/ui/title/TitleState.hx @@ -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); diff --git a/source/funkin/util/BitmapUtil.hx b/source/funkin/util/BitmapUtil.hx index fd36bf1dd..a380b9f49 100644 --- a/source/funkin/util/BitmapUtil.hx +++ b/source/funkin/util/BitmapUtil.hx @@ -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; } }