mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-03-21 09:29:41 +00:00
First implementation of credits state.
This commit is contained in:
parent
99ea7bbe84
commit
1e888658f7
|
@ -175,6 +175,7 @@
|
||||||
<haxedef name="haxeui_focus_out_on_click" />
|
<haxedef name="haxeui_focus_out_on_click" />
|
||||||
<!-- Required to use haxe.ui.backend.flixel.UIState with build macros. -->
|
<!-- Required to use haxe.ui.backend.flixel.UIState with build macros. -->
|
||||||
<haxedef name="haxeui_dont_impose_base_class" />
|
<haxedef name="haxeui_dont_impose_base_class" />
|
||||||
|
<haxedef name="HARDCODED_CREDITS" />
|
||||||
|
|
||||||
<!-- Skip the Intro -->
|
<!-- Skip the Intro -->
|
||||||
<section if="debug">
|
<section if="debug">
|
||||||
|
|
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit 5f1726f1b0c11fc747b7473708cf4e5f28be05f1
|
Subproject commit edccf04217c49c730b11c80736e2b2d98a25ee95
|
|
@ -325,12 +325,3 @@ abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A pair of a file name and its contents.
|
|
||||||
*/
|
|
||||||
typedef JsonFile =
|
|
||||||
{
|
|
||||||
fileName:String,
|
|
||||||
contents:String
|
|
||||||
};
|
|
||||||
|
|
10
source/funkin/data/JsonFile.hx
Normal file
10
source/funkin/data/JsonFile.hx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package funkin.data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pair of a file name and its contents.
|
||||||
|
*/
|
||||||
|
typedef JsonFile =
|
||||||
|
{
|
||||||
|
fileName:String,
|
||||||
|
contents:String
|
||||||
|
};
|
|
@ -427,7 +427,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
return ScriptedSong.listScriptClasses();
|
return ScriptedSong.listScriptClasses();
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadEntryMetadataFile(id:String, ?variation:String):Null<BaseRegistry.JsonFile>
|
function loadEntryMetadataFile(id:String, ?variation:String):Null<JsonFile>
|
||||||
{
|
{
|
||||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||||
var entryFilePath:String = Paths.json('$dataFilePath/$id/$id-metadata${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}');
|
var entryFilePath:String = Paths.json('$dataFilePath/$id/$id-metadata${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}');
|
||||||
|
@ -438,7 +438,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
return {fileName: entryFilePath, contents: rawJson};
|
return {fileName: entryFilePath, contents: rawJson};
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMusicDataFile(id:String, ?variation:String):Null<BaseRegistry.JsonFile>
|
function loadMusicDataFile(id:String, ?variation:String):Null<JsonFile>
|
||||||
{
|
{
|
||||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||||
var entryFilePath:String = Paths.file('music/$id/$id-metadata${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.json');
|
var entryFilePath:String = Paths.file('music/$id/$id-metadata${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.json');
|
||||||
|
@ -456,7 +456,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
return openfl.Assets.exists(entryFilePath);
|
return openfl.Assets.exists(entryFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadEntryChartFile(id:String, ?variation:String):Null<BaseRegistry.JsonFile>
|
function loadEntryChartFile(id:String, ?variation:String):Null<JsonFile>
|
||||||
{
|
{
|
||||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||||
var entryFilePath:String = Paths.json('$dataFilePath/$id/$id-chart${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}');
|
var entryFilePath:String = Paths.json('$dataFilePath/$id/$id-chart${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}');
|
||||||
|
|
26
source/funkin/ui/credits/CreditsData.hx
Normal file
26
source/funkin/ui/credits/CreditsData.hx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package funkin.ui.credits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The members of the Funkin' Crew, organized by their roles.
|
||||||
|
*/
|
||||||
|
typedef CreditsData =
|
||||||
|
{
|
||||||
|
var roles:Array<CreditsDataRole>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The members of a specific role on the Funkin' Crew.
|
||||||
|
*/
|
||||||
|
typedef CreditsDataRole =
|
||||||
|
{
|
||||||
|
var roleName:String;
|
||||||
|
var members:Array<CreditsDataMember>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A member of a specific person on the Funkin' Crew.
|
||||||
|
*/
|
||||||
|
typedef CreditsDataMember =
|
||||||
|
{
|
||||||
|
var fullName:String;
|
||||||
|
}
|
130
source/funkin/ui/credits/CreditsDataHandler.hx
Normal file
130
source/funkin/ui/credits/CreditsDataHandler.hx
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
package funkin.ui.credits;
|
||||||
|
|
||||||
|
import funkin.data.JsonFile;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
|
@:nullSafety
|
||||||
|
class CreditsDataHandler
|
||||||
|
{
|
||||||
|
public static final BACKER_PUBLIC_URL:String = 'https://funkin.me/backers';
|
||||||
|
|
||||||
|
#if HARDCODED_CREDITS
|
||||||
|
static final CREDITS_DATA_PATH:String = "assets/exclude/data/credits.json";
|
||||||
|
#else
|
||||||
|
static final CREDITS_DATA_PATH:String = "assets/data/credits.json";
|
||||||
|
#end
|
||||||
|
|
||||||
|
public static function debugPrint(data:Null<CreditsData>):Void
|
||||||
|
{
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
trace('CreditsData(NULL)');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var roleCount = data.roles.length;
|
||||||
|
var memberCount = 0;
|
||||||
|
for (role in data.roles)
|
||||||
|
{
|
||||||
|
memberCount += role.members.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace('CreditsData($roleCount roles with $memberCount members)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If for some reason the full credits won't load,
|
||||||
|
* use this hardcoded data for the original Funkin' Crew.
|
||||||
|
*
|
||||||
|
* @return `CreditsData`
|
||||||
|
*/
|
||||||
|
public static inline function getFallback():CreditsData
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
roleName: 'Founders',
|
||||||
|
members: [
|
||||||
|
{fullName: 'ninjamuffin99'},
|
||||||
|
{fullName: 'PhantomArcade'},
|
||||||
|
{fullName: 'KawaiSprite'},
|
||||||
|
{fullName: 'evilsk8r'},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fetchBackerEntries():Array<String>
|
||||||
|
{
|
||||||
|
// TODO: Replace this with a web request.
|
||||||
|
// We can't just grab the current Kickstarter data and include it in builds,
|
||||||
|
// because we don't want to deadname people who haven't logged into the portal yet.
|
||||||
|
// It can be async and paginated for performance!
|
||||||
|
return ['See the list of backers at $BACKER_PUBLIC_URL.'];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HARDCODED_CREDITS
|
||||||
|
/**
|
||||||
|
* The data for the credits.
|
||||||
|
* Hardcoded into game via a macro at compile time.
|
||||||
|
*/
|
||||||
|
public static final CREDITS_DATA:Null<CreditsData> = #if macro null #else CreditsDataMacro.loadCreditsData() #end;
|
||||||
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data for the credits.
|
||||||
|
* Loaded dynamically from the game folder when needed.
|
||||||
|
* Nullable because data may fail to parse.
|
||||||
|
*/
|
||||||
|
public static var CREDITS_DATA(get, default):Null<CreditsData> = null;
|
||||||
|
|
||||||
|
static function get_CREDITS_DATA():Null<CreditsData>
|
||||||
|
{
|
||||||
|
if (CREDITS_DATA == null) CREDITS_DATA = parseCreditsData(fetchCreditsData());
|
||||||
|
|
||||||
|
return CREDITS_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function fetchCreditsData():funkin.data.JsonFile
|
||||||
|
{
|
||||||
|
var rawJson:String = openfl.Assets.getText(CREDITS_DATA_PATH).trim();
|
||||||
|
|
||||||
|
return {
|
||||||
|
fileName: CREDITS_DATA_PATH,
|
||||||
|
contents: rawJson
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static function parseCreditsData(file:JsonFile):Null<CreditsData>
|
||||||
|
{
|
||||||
|
#if !macro
|
||||||
|
if (file.contents == null) return null;
|
||||||
|
|
||||||
|
var parser = new json2object.JsonParser<CreditsData>();
|
||||||
|
parser.ignoreUnknownVariables = false;
|
||||||
|
trace('[CREDITS] Parsing credits data from ${CREDITS_DATA_PATH}');
|
||||||
|
parser.fromJson(file.contents, file.fileName);
|
||||||
|
|
||||||
|
if (parser.errors.length > 0)
|
||||||
|
{
|
||||||
|
printErrors(parser.errors, file.fileName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parser.value;
|
||||||
|
#else
|
||||||
|
return null;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
static function printErrors(errors:Array<json2object.Error>, id:String = ''):Void
|
||||||
|
{
|
||||||
|
trace('[CREDITS] Failed to parse credits data: ${id}');
|
||||||
|
|
||||||
|
for (error in errors)
|
||||||
|
funkin.data.DataError.printError(error);
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}
|
67
source/funkin/ui/credits/CreditsDataMacro.hx
Normal file
67
source/funkin/ui/credits/CreditsDataMacro.hx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
package funkin.ui.credits;
|
||||||
|
|
||||||
|
#if macro
|
||||||
|
import haxe.macro.Context;
|
||||||
|
#end
|
||||||
|
|
||||||
|
@:access(funkin.ui.credits.CreditsDataHandler)
|
||||||
|
class CreditsDataMacro
|
||||||
|
{
|
||||||
|
public static macro function loadCreditsData():haxe.macro.Expr.ExprOf<CreditsData>
|
||||||
|
{
|
||||||
|
#if !display
|
||||||
|
trace('Hardcoding credits data...');
|
||||||
|
var json = CreditsDataMacro.fetchJSON();
|
||||||
|
|
||||||
|
if (json == null)
|
||||||
|
{
|
||||||
|
Context.info('[WARN] Could not fetch JSON data for credits.', Context.currentPos());
|
||||||
|
return macro $v{CreditsDataHandler.getFallback()};
|
||||||
|
}
|
||||||
|
|
||||||
|
var creditsData = CreditsDataMacro.parseJSON(json);
|
||||||
|
|
||||||
|
if (creditsData == null)
|
||||||
|
{
|
||||||
|
Context.info('[WARN] Could not parse JSON data for credits.', Context.currentPos());
|
||||||
|
return macro $v{CreditsDataHandler.getFallback()};
|
||||||
|
}
|
||||||
|
|
||||||
|
CreditsDataHandler.debugPrint(creditsData);
|
||||||
|
return macro $v{creditsData};
|
||||||
|
// return macro $v{null};
|
||||||
|
#else
|
||||||
|
// `#if display` is used for code completion. In this case we return
|
||||||
|
// a minimal value to keep code completion fast.
|
||||||
|
return macro $v{CreditsDataHandler.getFallback()};
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
#if macro
|
||||||
|
static function fetchJSON():Null<String>
|
||||||
|
{
|
||||||
|
return sys.io.File.getContent(CreditsDataHandler.CREDITS_DATA_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the JSON data for the credits.
|
||||||
|
*
|
||||||
|
* @param json The string data to parse.
|
||||||
|
* @return The parsed data.
|
||||||
|
*/
|
||||||
|
static function parseJSON(json:String):Null<CreditsData>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// TODO: Use something with better validation but that still works at macro time.
|
||||||
|
return haxe.Json.parse(json);
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
trace('[ERROR] Failed to parse JSON data for credits.');
|
||||||
|
trace(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}
|
200
source/funkin/ui/credits/CreditsState.hx
Normal file
200
source/funkin/ui/credits/CreditsState.hx
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
package funkin.ui.credits;
|
||||||
|
|
||||||
|
import flixel.text.FlxText;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import funkin.audio.FunkinSound;
|
||||||
|
import flixel.FlxSprite;
|
||||||
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state used to display the credits scroll.
|
||||||
|
* AAA studios often fail to credit properly, and we're better than them!
|
||||||
|
*/
|
||||||
|
class CreditsState extends MusicBeatState
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The height the credits should start at.
|
||||||
|
* Make this an instanced variable so it gets set by the constructor.
|
||||||
|
*/
|
||||||
|
final STARTING_HEIGHT = FlxG.height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The padding on each side of the screen.
|
||||||
|
*/
|
||||||
|
static final SCREEN_PAD = 24;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width of the screen the credits should maximally fill up.
|
||||||
|
* Make this an instanced variable so it gets set by the constructor.
|
||||||
|
*/
|
||||||
|
final FULL_WIDTH = FlxG.width - (SCREEN_PAD * 2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The font to use to display the text.
|
||||||
|
* To use a font from the `assets` folder, use `Paths.font(...)`.
|
||||||
|
* Choose something that will render Unicode properly.
|
||||||
|
*/
|
||||||
|
static final CREDITS_FONT = 'Arial';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the font.
|
||||||
|
*/
|
||||||
|
static final CREDITS_FONT_SIZE = 48;
|
||||||
|
|
||||||
|
static final CREDITS_HEADER_FONT_SIZE = 72;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color of the text itself.
|
||||||
|
*/
|
||||||
|
static final CREDITS_FONT_COLOR = FlxColor.WHITE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color of the text's outline.
|
||||||
|
*/
|
||||||
|
static final CREDITS_FONT_STROKE_COLOR = FlxColor.BLACK;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The speed the credits scroll at, in pixels per second.
|
||||||
|
*/
|
||||||
|
static final CREDITS_SCROLL_BASE_SPEED = 25.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The speed the credits scroll at while the button is held, in pixels per second.
|
||||||
|
*/
|
||||||
|
static final CREDITS_SCROLL_FAST_SPEED = CREDITS_SCROLL_BASE_SPEED * 4.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The actual sprites and text used to display the credits.
|
||||||
|
*/
|
||||||
|
var creditsGroup:FlxSpriteGroup;
|
||||||
|
|
||||||
|
var scrollPaused:Bool = false;
|
||||||
|
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function create():Void
|
||||||
|
{
|
||||||
|
super.create();
|
||||||
|
|
||||||
|
// Background
|
||||||
|
var bg = new FlxSprite(Paths.image('menuDesat'));
|
||||||
|
bg.scrollFactor.x = 0;
|
||||||
|
bg.scrollFactor.y = 0;
|
||||||
|
bg.setGraphicSize(Std.int(FlxG.width));
|
||||||
|
bg.updateHitbox();
|
||||||
|
bg.x = 0;
|
||||||
|
bg.y = 0;
|
||||||
|
bg.visible = true;
|
||||||
|
bg.color = 0xFFB57EDC; // Lavender
|
||||||
|
add(bg);
|
||||||
|
|
||||||
|
// TODO: Once we need to display Kickstarter backers,
|
||||||
|
// make this use a recycled pool so we don't kill peformance.
|
||||||
|
creditsGroup = new FlxSpriteGroup();
|
||||||
|
creditsGroup.x = SCREEN_PAD;
|
||||||
|
creditsGroup.y = STARTING_HEIGHT;
|
||||||
|
|
||||||
|
buildCreditsGroup();
|
||||||
|
|
||||||
|
add(creditsGroup);
|
||||||
|
|
||||||
|
// Music
|
||||||
|
FunkinSound.playMusic('freeplayRandom',
|
||||||
|
{
|
||||||
|
startingVolume: 0.0,
|
||||||
|
overrideExisting: true,
|
||||||
|
restartTrack: true,
|
||||||
|
loop: true
|
||||||
|
});
|
||||||
|
FlxG.sound.music.fadeIn(2, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCreditsGroup():Void
|
||||||
|
{
|
||||||
|
var y = 0;
|
||||||
|
|
||||||
|
for (role in CreditsDataHandler.CREDITS_DATA.roles)
|
||||||
|
{
|
||||||
|
creditsGroup.add(buildCreditsLine(role.roleName, y, true, CreditsSide.Center));
|
||||||
|
y += CREDITS_HEADER_FONT_SIZE;
|
||||||
|
|
||||||
|
for (member in role.members)
|
||||||
|
{
|
||||||
|
creditsGroup.add(buildCreditsLine(member.fullName, y, false, CreditsSide.Center));
|
||||||
|
y += CREDITS_FONT_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Padding between each role.
|
||||||
|
y += CREDITS_FONT_SIZE * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCreditsLine(text:String, yPos:Float, header:Bool, side:CreditsSide = CreditsSide.Center):FlxText
|
||||||
|
{
|
||||||
|
// CreditsSide.Center: Full screen width
|
||||||
|
// CreditsSide.Left: Left half of screen
|
||||||
|
// CreditsSide.Right: Right half of screen
|
||||||
|
var xPos = (side == CreditsSide.Right) ? (FULL_WIDTH / 2) : 0;
|
||||||
|
var width = (side == CreditsSide.Center) ? FULL_WIDTH : (FULL_WIDTH / 2);
|
||||||
|
var size = header ? CREDITS_HEADER_FONT_SIZE : CREDITS_FONT_SIZE;
|
||||||
|
|
||||||
|
var creditsLine:FlxText = new FlxText(xPos, yPos, width, text);
|
||||||
|
creditsLine.setFormat(CREDITS_FONT, size, CREDITS_FONT_COLOR, FlxTextAlign.CENTER, FlxTextBorderStyle.OUTLINE, CREDITS_FONT_STROKE_COLOR, true);
|
||||||
|
|
||||||
|
return creditsLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function update(elapsed:Float):Void
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
if (!scrollPaused)
|
||||||
|
{
|
||||||
|
// TODO: Replace with whatever the special note button is.
|
||||||
|
if (controls.ACCEPT || FlxG.keys.pressed.SPACE)
|
||||||
|
{
|
||||||
|
// Move the whole group.
|
||||||
|
creditsGroup.y -= CREDITS_SCROLL_FAST_SPEED * elapsed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Move the whole group.
|
||||||
|
creditsGroup.y -= CREDITS_SCROLL_BASE_SPEED * elapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controls.BACK || hasEnded())
|
||||||
|
{
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
else if (controls.PAUSE)
|
||||||
|
{
|
||||||
|
scrollPaused = !scrollPaused;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasEnded():Bool
|
||||||
|
{
|
||||||
|
return creditsGroup.y < -creditsGroup.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exit():Void
|
||||||
|
{
|
||||||
|
FlxG.switchState(new funkin.ui.mainmenu.MainMenuState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function destroy():Void
|
||||||
|
{
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CreditsSide
|
||||||
|
{
|
||||||
|
Left;
|
||||||
|
Center;
|
||||||
|
Right;
|
||||||
|
}
|
|
@ -117,6 +117,10 @@ class MainMenuState extends MusicBeatState
|
||||||
startExitState(() -> new funkin.ui.options.OptionsState());
|
startExitState(() -> new funkin.ui.options.OptionsState());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
createMenuItem('options', 'mainmenu/options', function() {
|
||||||
|
startExitState(() -> new funkin.ui.credits.CreditsState());
|
||||||
|
});
|
||||||
|
|
||||||
// Reset position of menu items.
|
// Reset position of menu items.
|
||||||
var spacing = 160;
|
var spacing = 160;
|
||||||
var top = (FlxG.height - (spacing * (menuItems.length - 1))) / 2;
|
var top = (FlxG.height - (spacing * (menuItems.length - 1))) / 2;
|
||||||
|
@ -125,6 +129,9 @@ class MainMenuState extends MusicBeatState
|
||||||
var menuItem = menuItems.members[i];
|
var menuItem = menuItems.members[i];
|
||||||
menuItem.x = FlxG.width / 2;
|
menuItem.x = FlxG.width / 2;
|
||||||
menuItem.y = top + spacing * i;
|
menuItem.y = top + spacing * i;
|
||||||
|
menuItem.scrollFactor.x = 0.0;
|
||||||
|
// This one affects how much the menu items move when you scroll between them.
|
||||||
|
menuItem.scrollFactor.y = 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetCamStuff();
|
resetCamStuff();
|
||||||
|
|
Loading…
Reference in a new issue