From e0fe7cb1ebed863111b7fffca389e9e603b47e3c Mon Sep 17 00:00:00 2001 From: lemz Date: Sat, 25 May 2024 01:11:34 +0200 Subject: [PATCH] add fps option --- source/Main.hx | 9 +- source/funkin/Preferences.hx | 29 +++ source/funkin/save/Save.hx | 10 +- source/funkin/ui/options/PreferencesMenu.hx | 211 ++++++++++++++++---- 4 files changed, 207 insertions(+), 52 deletions(-) diff --git a/source/Main.hx b/source/Main.hx index add5bbc67..8105e6c4f 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -2,6 +2,7 @@ package; import flixel.FlxGame; import flixel.FlxState; +import funkin.Preferences; import funkin.util.logging.CrashHandler; import funkin.ui.debug.MemoryCounter; import funkin.save.Save; @@ -22,12 +23,6 @@ class Main extends Sprite var gameHeight:Int = 720; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom). var initialState:Class = funkin.InitState; // The FlxState the game starts with. var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions. - #if web - var framerate:Int = 60; // How many frames per second the game should run at. - #else - // TODO: This should probably be in the options menu? - var framerate:Int = 144; // How many frames per second the game should run at. - #end var skipSplash:Bool = true; // Whether to skip the flixel splash screen that appears in release mode. var startFullscreen:Bool = false; // Whether to start the game in fullscreen on desktop targets @@ -103,7 +98,7 @@ class Main extends Sprite // George recommends binding the save before FlxGame is created. Save.load(); - var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen); + var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, Preferences.framerate, Preferences.framerate, skipSplash, startFullscreen); // FlxG.game._customSoundTray wants just the class, it calls new from // create() in there, which gets called when it's added to stage diff --git a/source/funkin/Preferences.hx b/source/funkin/Preferences.hx index b2050c6a2..7a322283d 100644 --- a/source/funkin/Preferences.hx +++ b/source/funkin/Preferences.hx @@ -7,6 +7,35 @@ import funkin.save.Save; */ class Preferences { + /** + * FPS + * @default `60` + */ + public static var framerate(get, set):Int; + + static function get_framerate():Int + { + #if web + return 60; + #else + return Save?.instance?.options?.framerate ?? 60; + #end + } + + static function set_framerate(value:Int):Int + { + #if web + return 60; + #else + var save:Save = Save.instance; + save.options.framerate = value; + save.flush(); + FlxG.updateFramerate = value; + FlxG.drawFramerate = value; + return value; + #end + } + /** * Whether some particularly fowl language is displayed. * @default `true` diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index acbe59edd..3600e9741 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -53,7 +53,8 @@ class Save public function new(?data:RawSaveData) { if (data == null) this.data = Save.getDefault(); - else this.data = data; + else + this.data = data; } public static function getDefault():RawSaveData @@ -80,6 +81,7 @@ class Save options: { // Reasonable defaults. + framerate: 60, naughtyness: true, downscroll: false, flashingLights: true, @@ -835,6 +837,12 @@ typedef SaveScoreTallyData = */ typedef SaveDataOptions = { + /** + * FPS + * @default `60` + */ + var framerate:Int; + /** * Whether some particularly fowl language is displayed. * @default `true` diff --git a/source/funkin/ui/options/PreferencesMenu.hx b/source/funkin/ui/options/PreferencesMenu.hx index 783aef0ba..cf7296584 100644 --- a/source/funkin/ui/options/PreferencesMenu.hx +++ b/source/funkin/ui/options/PreferencesMenu.hx @@ -3,16 +3,16 @@ package funkin.ui.options; import flixel.FlxCamera; import flixel.FlxObject; import flixel.FlxSprite; +import flixel.math.FlxMath; import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import funkin.ui.AtlasText.AtlasFont; import funkin.ui.options.OptionsState.Page; import funkin.graphics.FunkinCamera; -import funkin.ui.TextMenuList.TextMenuItem; class PreferencesMenu extends Page { - var items:TextMenuList; - var preferenceItems:FlxTypedSpriteGroup; + var curSelected:Int = 0; + var prefs:FlxTypedSpriteGroup; var menuCamera:FlxCamera; var camFollow:FlxObject; @@ -26,22 +26,27 @@ class PreferencesMenu extends Page menuCamera.bgColor = 0x0; camera = menuCamera; - add(items = new TextMenuList()); - add(preferenceItems = new FlxTypedSpriteGroup()); + prefs = new FlxTypedSpriteGroup(); + add(prefs); createPrefItems(); camFollow = new FlxObject(FlxG.width / 2, 0, 140, 70); - if (items != null) camFollow.y = items.selectedItem.y; menuCamera.follow(camFollow, null, 0.06); var margin = 160; menuCamera.deadzone.set(0, margin, menuCamera.width, 40); menuCamera.minScrollY = 0; - items.onChange.add(function(selected) { - camFollow.y = selected.y; - }); + changeSelection(0); + } + + function addPref(pref:PreferenceItem):Void + { + pref.x = 0; + pref.y = 120 * prefs.length; + pref.ID = prefs.length; + prefs.add(pref); } /** @@ -49,50 +54,168 @@ class PreferencesMenu extends Page */ function createPrefItems():Void { - createPrefItemCheckbox('Naughtyness', 'Toggle displaying raunchy content', function(value:Bool):Void { - Preferences.naughtyness = value; - }, Preferences.naughtyness); - createPrefItemCheckbox('Downscroll', 'Enable to make notes move downwards', function(value:Bool):Void { - Preferences.downscroll = value; - }, Preferences.downscroll); - createPrefItemCheckbox('Flashing Lights', 'Disable to dampen flashing effects', function(value:Bool):Void { - Preferences.flashingLights = value; - }, Preferences.flashingLights); - createPrefItemCheckbox('Camera Zooming on Beat', 'Disable to stop the camera bouncing to the song', function(value:Bool):Void { - Preferences.zoomCamera = value; - }, Preferences.zoomCamera); - createPrefItemCheckbox('Debug Display', 'Enable to show FPS and other debug stats', function(value:Bool):Void { - Preferences.debugDisplay = value; - }, Preferences.debugDisplay); - createPrefItemCheckbox('Auto Pause', 'Automatically pause the game when it loses focus', function(value:Bool):Void { - Preferences.autoPause = value; - }, Preferences.autoPause); + #if !web + var pref:NumberedPreferenceItem = new NumberedPreferenceItem("FPS", "The framerate that the game is running on", Preferences.framerate, + function(value:Float):Void { + Preferences.framerate = Std.int(value); + }); + pref.minValue = 60; + pref.maxValue = 360; + pref.changeRate = 1; + pref.changeSpeed = 0.05; + addPref(pref); + #end + + // TODO: add these back + // createPrefItemCheckbox('Naughtyness', 'Toggle displaying raunchy content', function(value:Bool):Void { + // Preferences.naughtyness = value; + // }, Preferences.naughtyness); + // createPrefItemCheckbox('Downscroll', 'Enable to make notes move downwards', function(value:Bool):Void { + // Preferences.downscroll = value; + // }, Preferences.downscroll); + // createPrefItemCheckbox('Flashing Lights', 'Disable to dampen flashing effects', function(value:Bool):Void { + // Preferences.flashingLights = value; + // }, Preferences.flashingLights); + // createPrefItemCheckbox('Camera Zooming on Beat', 'Disable to stop the camera bouncing to the song', function(value:Bool):Void { + // Preferences.zoomCamera = value; + // }, Preferences.zoomCamera); + // createPrefItemCheckbox('Debug Display', 'Enable to show FPS and other debug stats', function(value:Bool):Void { + // Preferences.debugDisplay = value; + // }, Preferences.debugDisplay); + // createPrefItemCheckbox('Auto Pause', 'Automatically pause the game when it loses focus', function(value:Bool):Void { + // Preferences.autoPause = value; + // }, Preferences.autoPause); } - function createPrefItemCheckbox(prefName:String, prefDesc:String, onChange:Bool->Void, defaultValue:Bool):Void + function changeSelection(change:Int):Void { - var checkbox:CheckboxPreferenceItem = new CheckboxPreferenceItem(0, 120 * (items.length - 1 + 1), defaultValue); + curSelected += change; + if (curSelected < 0) + { + curSelected = prefs.length - 1; + } + else if (curSelected >= prefs.length) + { + curSelected = 0; + } - items.createItem(120, (120 * items.length) + 30, prefName, AtlasFont.BOLD, function() { - var value = !checkbox.currentValue; - onChange(value); - checkbox.currentValue = value; - }); - - preferenceItems.add(checkbox); + for (pref in prefs) + { + pref.x = 0; + if (pref.ID == curSelected) + { + pref.x = 20; + camFollow.y = pref.y; + } + } } - override function update(elapsed:Float) + override function update(elapsed:Float):Void { super.update(elapsed); - // Indent the selected item. - // TODO: Only do this on menu change? - items.forEach(function(daItem:TextMenuItem) { - if (items.selectedItem == daItem) daItem.x = 150; - else - daItem.x = 120; - }); + if (controls.UI_DOWN_P) + { + changeSelection(1); + } + else if (controls.UI_UP_P) + { + changeSelection(-1); + } + + var selectedPref:PreferenceItem = prefs.members[curSelected]; + selectedPref.handleInput(elapsed); + } +} + +class PreferenceItem extends FlxTypedSpriteGroup +{ + public var name:String = ""; + public var description:String = ""; + + public function handleInput(deltaTime:Float):Void {} +} + +class NumberedPreferenceItem extends PreferenceItem +{ + public var onChange:Float->Void; + public var changeRate:Float = 1.0; + public var changeSpeed:Float = 0.1; + + public var minValue(default, set):Null; + + function set_minValue(value:Float):Float + { + minValue = value; + currentValue = currentValue; + return value; + } + + public var maxValue(default, set):Null; + + function set_maxValue(value:Float):Float + { + maxValue = value; + currentValue = currentValue; + return value; + } + + public var currentValue(default, set):Float; + + function set_currentValue(value:Float):Float + { + currentValue = FlxMath.bound(value, minValue, maxValue); + onChange(currentValue); + updateText(); + return currentValue; + } + + var valueText:AtlasText; + var preferenceText:AtlasText; + + public function new(name:String, description:String, defaultValue:Float, onChange:Float->Void) + { + super(); + + this.valueText = new AtlasText(0, 0, '$defaultValue', AtlasFont.DEFAULT); + add(this.valueText); + + this.preferenceText = new AtlasText(this.valueText.width + 30, 0, '$name', AtlasFont.BOLD); + add(this.preferenceText); + + this.name = name; + this.description = description; + this.onChange = onChange; + this.currentValue = defaultValue; + } + + var timeToWait:Float = 0; + + public override function handleInput(deltaTime:Float):Void + { + timeToWait -= deltaTime; + + if (timeToWait > 0) + { + return; + } + + if (PlayerSettings.player1.controls.UI_RIGHT) + { + currentValue += changeRate; + timeToWait = changeSpeed; + } + else if (PlayerSettings.player1.controls.UI_LEFT) + { + currentValue -= changeRate; + timeToWait = changeSpeed; + } + } + + function updateText():Void + { + valueText.text = '$currentValue'; + preferenceText.x = valueText.width + 30; } }