mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-03-21 17:39:20 +00:00
Work in progress on HaxeUI chart editor
This commit is contained in:
parent
f790cd8fd6
commit
eb3ad49a30
58
Project.xml
58
Project.xml
|
@ -123,63 +123,16 @@
|
||||||
<haxelib name="flixel-addons" />
|
<haxelib name="flixel-addons" />
|
||||||
<haxelib name="hscript" />
|
<haxelib name="hscript" />
|
||||||
|
|
||||||
<!--In case you want to use the ui package-->
|
|
||||||
<haxelib name="flixel-ui" />
|
<haxelib name="flixel-ui" />
|
||||||
<!--haxelib name="newgrounds" unless="switch"/> -->
|
<haxelib name="haxeui-core"/>
|
||||||
<haxelib name="faxe" if='switch' />
|
<haxelib name="haxeui-flixel"/>
|
||||||
<haxelib name="polymod" />
|
<haxelib name="polymod" />
|
||||||
<haxelib name="flxanimate" />
|
<haxelib name="flxanimate" />
|
||||||
|
|
||||||
<haxelib name="thx.semver" />
|
<haxelib name="thx.semver" />
|
||||||
|
|
||||||
<!-- <haxelib name="colyseus"/> -->
|
|
||||||
<!-- <haxelib name="colyseus-websocket" /> -->
|
|
||||||
<!-- <haxelib name="newgrounds"/> -->
|
|
||||||
<haxelib name="hxcpp-debug-server" if="desktop debug" />
|
<haxelib name="hxcpp-debug-server" if="desktop debug" />
|
||||||
|
|
||||||
<!-- swf stufffff -->
|
|
||||||
<!-- <haxelib name="swf"/> -->
|
|
||||||
<!-- <library path="assets/tanky.swf" preload="true"/> -->
|
|
||||||
<!-- <library path="assets/tankBG.swf" preload="true"/> -->
|
|
||||||
|
|
||||||
<!-- <haxelib name="flixel-animate" /> -->
|
|
||||||
<!-- <haxelib name="spinehaxe" /> -->
|
|
||||||
<!-- https://github.com/ninjamuffin99/Flixel-Animate-Atlas-Player -->
|
|
||||||
|
|
||||||
|
|
||||||
<!--<haxelib name="discord_rpc" if="cpp"/> -->
|
|
||||||
<!-- foesn't work with neko -->
|
|
||||||
<!-- <haxelib name="hxcpp-debug-server" if="desktop"/> -->
|
|
||||||
|
|
||||||
<!-- <haxelib name="markdown" /> -->
|
|
||||||
<!-- <haxelib name="HtmlParser" /> -->
|
|
||||||
|
|
||||||
<!--In case you want to use nape with flixel-->
|
|
||||||
<!--<haxelib name="nape-haxe4" />-->
|
|
||||||
|
|
||||||
<!-- ______________________________ Haxedefines _____________________________ -->
|
|
||||||
|
|
||||||
<!--Enable the Flixel core recording system-->
|
|
||||||
<!--<haxedef name="FLX_RECORD" />-->
|
|
||||||
|
|
||||||
<!--Disable the right and middle mouse buttons-->
|
|
||||||
<!-- <haxedef name="FLX_NO_MOUSE_ADVANCED" /> -->
|
|
||||||
|
|
||||||
<!--Disable the native cursor API on Flash-->
|
|
||||||
<!--<haxedef name="FLX_NO_NATIVE_CURSOR" />-->
|
|
||||||
|
|
||||||
<!--Optimise inputs, be careful you will get null errors if you don't use conditionals in your game-->
|
|
||||||
<!-- <haxedef name="FLX_NO_MOUSE" if="mobile" /> -->
|
|
||||||
<!-- <haxedef name="FLX_NO_KEYBOARD" if="mobile" /> -->
|
|
||||||
<!-- <haxedef name="FLX_NO_TOUCH" if="desktop" /> -->
|
|
||||||
<!--<haxedef name="FLX_NO_GAMEPAD" />-->
|
|
||||||
|
|
||||||
<!--Disable the Flixel core sound tray-->
|
|
||||||
<!--<haxedef name="FLX_NO_SOUND_TRAY" />-->
|
|
||||||
|
|
||||||
<!--Disable the Flixel sound management code-->
|
|
||||||
<!--<haxedef name="FLX_NO_SOUND_SYSTEM" />-->
|
|
||||||
|
|
||||||
<!--Disable the Flixel core focus lost screen-->
|
<!--Disable the Flixel core focus lost screen-->
|
||||||
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN" />
|
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN" />
|
||||||
|
|
||||||
|
@ -198,6 +151,11 @@
|
||||||
<haxeflag name="-dce no" />
|
<haxeflag name="-dce no" />
|
||||||
<haxeflag name="--macro" value="include('funkin')" />
|
<haxeflag name="--macro" value="include('funkin')" />
|
||||||
|
|
||||||
|
<!-- Ensure all UI components are available at runtime. -->
|
||||||
|
<haxeflag name="--macro" value="include('haxe.ui.components')" />
|
||||||
|
<haxeflag name="--macro" value="include('haxe.ui.containers')" />
|
||||||
|
<haxeflag name="--macro" value="include('haxe.ui.containers.menus')" />
|
||||||
|
|
||||||
<!-- Necessary to provide stack traces for HScript. -->
|
<!-- Necessary to provide stack traces for HScript. -->
|
||||||
<haxedef name="hscriptPos" />
|
<haxedef name="hscriptPos" />
|
||||||
<haxedef name="HXCPP_CHECK_POINTER" />
|
<haxedef name="HXCPP_CHECK_POINTER" />
|
||||||
|
@ -259,8 +217,6 @@
|
||||||
<haxedef name="POLYMOD_SCRIPT_LIBRARY" value="scripts" />
|
<haxedef name="POLYMOD_SCRIPT_LIBRARY" value="scripts" />
|
||||||
<!-- The base path from which scripts should be accessed. -->
|
<!-- The base path from which scripts should be accessed. -->
|
||||||
<haxedef name="POLYMOD_ROOT_PATH" value="scripts/" />
|
<haxedef name="POLYMOD_ROOT_PATH" value="scripts/" />
|
||||||
<!-- Determines the precision required for mods to be compatible. -->
|
|
||||||
<haxedef name="POLYMOD_API_VERSION_MATCH" value="MATCH_MINOR" />
|
|
||||||
<!-- Determines the subdirectory of the mod folder used for file appending. -->
|
<!-- Determines the subdirectory of the mod folder used for file appending. -->
|
||||||
<haxedef name="POLYMOD_APPEND_FOLDER" value="_append" />
|
<haxedef name="POLYMOD_APPEND_FOLDER" value="_append" />
|
||||||
<!-- Determines the subdirectory of the mod folder used for file merges. -->
|
<!-- Determines the subdirectory of the mod folder used for file merges. -->
|
||||||
|
|
29
hmm.json
29
hmm.json
|
@ -21,6 +21,13 @@
|
||||||
"ref": "a3877f0",
|
"ref": "a3877f0",
|
||||||
"url": "https://github.com/MasterEric/flixel-addons"
|
"url": "https://github.com/MasterEric/flixel-addons"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "flixel-addons",
|
||||||
|
"type": "git",
|
||||||
|
"dir": null,
|
||||||
|
"ref": "dev",
|
||||||
|
"url": "https://github.com/MasterEric/flixel-addons"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "flixel-ui",
|
"name": "flixel-ui",
|
||||||
"type": "haxelib",
|
"type": "haxelib",
|
||||||
|
@ -33,6 +40,20 @@
|
||||||
"ref": "18b2060",
|
"ref": "18b2060",
|
||||||
"url": "https://github.com/Dot-Stuff/flxanimate"
|
"url": "https://github.com/Dot-Stuff/flxanimate"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "haxeui-core",
|
||||||
|
"type": "git",
|
||||||
|
"dir": null,
|
||||||
|
"ref": "master",
|
||||||
|
"url": "https://github.com/haxeui/haxeui-core/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "haxeui-flixel",
|
||||||
|
"type": "git",
|
||||||
|
"dir": null,
|
||||||
|
"ref": "master",
|
||||||
|
"url": "https://github.com/haxeui/haxeui-flixel"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "hmm",
|
"name": "hmm",
|
||||||
"type": "haxelib",
|
"type": "haxelib",
|
||||||
|
@ -57,15 +78,15 @@
|
||||||
"name": "lime",
|
"name": "lime",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "770bf0e",
|
"ref": "develop",
|
||||||
"url": "https://github.com/openfl/lime"
|
"url": "https://github.com/openfl/lime"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "flixel-addons",
|
"name": "openfl",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "dev",
|
"ref": "develop",
|
||||||
"url": "https://github.com/MasterEric/flixel-addons"
|
"url": "https://github.com/openfl/openfl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "polymod",
|
"name": "polymod",
|
||||||
|
|
|
@ -2,8 +2,8 @@ package;
|
||||||
|
|
||||||
import flixel.FlxGame;
|
import flixel.FlxGame;
|
||||||
import flixel.FlxState;
|
import flixel.FlxState;
|
||||||
import funkin.InitState;
|
|
||||||
import funkin.MemoryCounter;
|
import funkin.MemoryCounter;
|
||||||
|
import haxe.ui.Toolkit;
|
||||||
import openfl.Lib;
|
import openfl.Lib;
|
||||||
import openfl.display.FPS;
|
import openfl.display.FPS;
|
||||||
import openfl.display.Sprite;
|
import openfl.display.Sprite;
|
||||||
|
@ -15,7 +15,7 @@ class Main extends Sprite
|
||||||
{
|
{
|
||||||
var gameWidth:Int = 1280; // Width of the game in pixels (might be less / more in actual pixels depending on your zoom).
|
var gameWidth:Int = 1280; // Width of the game in pixels (might be less / more in actual pixels depending on your zoom).
|
||||||
var gameHeight:Int = 720; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom).
|
var gameHeight:Int = 720; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom).
|
||||||
var initialState:Class<FlxState> = InitState; // The FlxState the game starts with.
|
var initialState:Class<FlxState> = funkin.InitState; // The FlxState the game starts with.
|
||||||
var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions.
|
var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions.
|
||||||
#if web
|
#if web
|
||||||
var framerate:Int = 60; // How many frames per second the game should run at.
|
var framerate:Int = 60; // How many frames per second the game should run at.
|
||||||
|
@ -69,20 +69,6 @@ class Main extends Sprite
|
||||||
|
|
||||||
private function setupGame():Void
|
private function setupGame():Void
|
||||||
{
|
{
|
||||||
// Lib.current.stage.color = null;
|
|
||||||
|
|
||||||
var stageWidth:Int = Lib.current.stage.stageWidth;
|
|
||||||
var stageHeight:Int = Lib.current.stage.stageHeight;
|
|
||||||
|
|
||||||
// if (zoom == -1)
|
|
||||||
// {
|
|
||||||
// var ratioX:Float = stageWidth / gameWidth;
|
|
||||||
// var ratioY:Float = stageHeight / gameHeight;
|
|
||||||
// zoom = Math.min(ratioX, ratioY);
|
|
||||||
// gameWidth = Math.ceil(stageWidth / zoom);
|
|
||||||
// gameHeight = Math.ceil(stageHeight / zoom);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `zoom` argument of FlxGame was removed in the dev branch of Flixel,
|
* The `zoom` argument of FlxGame was removed in the dev branch of Flixel,
|
||||||
* since it was considered confusing and unintuitive.
|
* since it was considered confusing and unintuitive.
|
||||||
|
@ -92,9 +78,11 @@ class Main extends Sprite
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !debug
|
#if !debug
|
||||||
initialState = TitleState;
|
initialState = funkin.TitleState;
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
initHaxeUI();
|
||||||
|
|
||||||
addChild(new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen));
|
addChild(new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen));
|
||||||
|
|
||||||
#if debug
|
#if debug
|
||||||
|
@ -105,53 +93,14 @@ class Main extends Sprite
|
||||||
addChild(memoryCounter);
|
addChild(memoryCounter);
|
||||||
#end
|
#end
|
||||||
#end
|
#end
|
||||||
|
|
||||||
/*
|
|
||||||
video = new Video();
|
|
||||||
addChild(video);
|
|
||||||
|
|
||||||
var netConnection = new NetConnection();
|
|
||||||
netConnection.connect(null);
|
|
||||||
|
|
||||||
netStream = new NetStream(netConnection);
|
|
||||||
netStream.client = {onMetaData: client_onMetaData};
|
|
||||||
netStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, netStream_onAsyncError);
|
|
||||||
|
|
||||||
#if (js && html5)
|
|
||||||
overlay = new Sprite();
|
|
||||||
overlay.graphics.beginFill(0, 0.5);
|
|
||||||
overlay.graphics.drawRect(0, 0, 560, 320);
|
|
||||||
overlay.addEventListener(MouseEvent.MOUSE_DOWN, overlay_onMouseDown);
|
|
||||||
overlay.buttonMode = true;
|
|
||||||
addChild(overlay);
|
|
||||||
|
|
||||||
netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnection_onNetStatus);
|
|
||||||
#else
|
|
||||||
netStream.play("assets/preload/music/dredd.mp4");
|
|
||||||
#end
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
private function client_onMetaData(metaData:Dynamic)
|
|
||||||
{
|
|
||||||
video.attachNetStream(netStream);
|
|
||||||
|
|
||||||
video.width = video.videoWidth;
|
function initHaxeUI()
|
||||||
video.height = video.videoHeight;
|
{
|
||||||
}
|
// Calling this before any HaxeUI components get used is important:
|
||||||
|
// - It initializes the theme styles.
|
||||||
private function netStream_onAsyncError(event:AsyncErrorEvent):Void
|
// - It scans the class path and registers any HaxeUI components.
|
||||||
{
|
Toolkit.init();
|
||||||
trace("Error loading video");
|
Toolkit.theme = "dark"; // don't be cringe
|
||||||
}
|
}
|
||||||
|
|
||||||
private function netConnection_onNetStatus(event:NetStatusEvent):Void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private function overlay_onMouseDown(event:MouseEvent):Void
|
|
||||||
{
|
|
||||||
netStream.play("assets/preload/music/dredd.mp4");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,17 +112,10 @@ class MainMenuState extends MusicBeatState
|
||||||
persistentUpdate = false;
|
persistentUpdate = false;
|
||||||
openSubState(new FreeplayState());
|
openSubState(new FreeplayState());
|
||||||
});
|
});
|
||||||
|
|
||||||
#if CAN_OPEN_LINKS
|
#if CAN_OPEN_LINKS
|
||||||
var hasPopupBlocker = #if web true #else false #end;
|
var hasPopupBlocker = #if web true #else false #end;
|
||||||
|
createMenuItem('donate', 'mainmenu/donate', selectDonate, hasPopupBlocker);
|
||||||
if (VideoState.seenVideo)
|
|
||||||
{
|
|
||||||
createMenuItem('kickstarter', 'mainmenu/kickstarter', selectDonate, hasPopupBlocker);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
createMenuItem('donate', 'mainmenu/donate', selectDonate, hasPopupBlocker);
|
|
||||||
}
|
|
||||||
#end
|
#end
|
||||||
|
|
||||||
createMenuItem('options', 'mainmenu/options', function()
|
createMenuItem('options', 'mainmenu/options', function()
|
||||||
|
@ -195,7 +188,7 @@ class MainMenuState extends MusicBeatState
|
||||||
#if CAN_OPEN_LINKS
|
#if CAN_OPEN_LINKS
|
||||||
function selectDonate()
|
function selectDonate()
|
||||||
{
|
{
|
||||||
WindowUtil.openURL(Constants.URL_KICKSTARTER);
|
WindowUtil.openURL(Constants.URL_ITCH);
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ import funkin.Conductor.BPMChangeEvent;
|
||||||
import funkin.modding.PolymodHandler;
|
import funkin.modding.PolymodHandler;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.modding.module.ModuleHandler;
|
import funkin.modding.module.ModuleHandler;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.ui.debug.DebugMenuSubState;
|
||||||
import funkin.play.stage.StageData.StageDataParser;
|
|
||||||
import funkin.util.SortUtil;
|
import funkin.util.SortUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +60,15 @@ class MusicBeatState extends FlxUIState
|
||||||
if (FlxG.keys.justPressed.F5)
|
if (FlxG.keys.justPressed.F5)
|
||||||
debug_refreshModules();
|
debug_refreshModules();
|
||||||
|
|
||||||
|
// ` / ~
|
||||||
|
if (FlxG.keys.justPressed.GRAVEACCENT)
|
||||||
|
{
|
||||||
|
// TODO: Does this break anything?
|
||||||
|
this.persistentUpdate = false;
|
||||||
|
this.persistentDraw = false;
|
||||||
|
FlxG.state.openSubState(new DebugMenuSubState());
|
||||||
|
}
|
||||||
|
|
||||||
// everyStep();
|
// everyStep();
|
||||||
var oldStep:Int = curStep;
|
var oldStep:Int = curStep;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package funkin;
|
package funkin;
|
||||||
|
|
||||||
import flixel.util.FlxColor;
|
|
||||||
import flixel.FlxSubState;
|
import flixel.FlxSubState;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
import funkin.Conductor.BPMChangeEvent;
|
import funkin.Conductor.BPMChangeEvent;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.modding.module.ModuleHandler;
|
import funkin.modding.module.ModuleHandler;
|
||||||
|
@ -73,6 +73,15 @@ class MusicBeatSubstate extends FlxSubState
|
||||||
ModuleHandler.callEvent(event);
|
ModuleHandler.callEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close this substate and replace it with a different one.
|
||||||
|
*/
|
||||||
|
public function switchSubState(substate:FlxSubState):Void
|
||||||
|
{
|
||||||
|
this.close();
|
||||||
|
this._parentState.openSubState(substate);
|
||||||
|
}
|
||||||
|
|
||||||
public function beatHit():Bool
|
public function beatHit():Bool
|
||||||
{
|
{
|
||||||
var event = new SongTimeScriptEvent(ScriptEvent.SONG_BEAT_HIT, curBeat, curStep);
|
var event = new SongTimeScriptEvent(ScriptEvent.SONG_BEAT_HIT, curBeat, curStep);
|
||||||
|
|
|
@ -117,6 +117,11 @@ class Paths
|
||||||
return 'assets/fonts/$key';
|
return 'assets/fonts/$key';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static public function ui(key:String, ?library:String)
|
||||||
|
{
|
||||||
|
return xml('ui/$key', library);
|
||||||
|
}
|
||||||
|
|
||||||
static public function getSparrowAtlas(key:String, ?library:String)
|
static public function getSparrowAtlas(key:String, ?library:String)
|
||||||
{
|
{
|
||||||
return FlxAtlasFrames.fromSparrow(image(key, library), file('images/$key.xml', library));
|
return FlxAtlasFrames.fromSparrow(image(key, library), file('images/$key.xml', library));
|
||||||
|
|
|
@ -866,8 +866,8 @@ class PlayState extends MusicBeatState
|
||||||
for (songNotes in section.sectionNotes)
|
for (songNotes in section.sectionNotes)
|
||||||
{
|
{
|
||||||
var daStrumTime:Float = songNotes.strumTime;
|
var daStrumTime:Float = songNotes.strumTime;
|
||||||
|
// TODO: Replace 4 with strumlineSize
|
||||||
var daNoteData:Int = Std.int(songNotes.noteData % 4);
|
var daNoteData:Int = Std.int(songNotes.noteData % 4);
|
||||||
|
|
||||||
var gottaHitNote:Bool = section.mustHitSection;
|
var gottaHitNote:Bool = section.mustHitSection;
|
||||||
|
|
||||||
if (songNotes.highStakes) // noteData > 3
|
if (songNotes.highStakes) // noteData > 3
|
||||||
|
@ -917,6 +917,7 @@ class PlayState extends MusicBeatState
|
||||||
sustainNote.x += FlxG.width / 2; // general offset
|
sustainNote.x += FlxG.width / 2; // general offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Replace 4 with strumlineSize
|
||||||
swagNote.mustPress = gottaHitNote;
|
swagNote.mustPress = gottaHitNote;
|
||||||
|
|
||||||
if (swagNote.mustPress)
|
if (swagNote.mustPress)
|
||||||
|
@ -938,7 +939,7 @@ class PlayState extends MusicBeatState
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
swagNote.x += FlxG.width / 2; // general offset
|
// swagNote.x += FlxG.width / 2; // general offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,6 +223,11 @@ class CharacterDataParser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function listCharacterIds():Array<String>
|
||||||
|
{
|
||||||
|
return [for (x in characterCache.keys()) x];
|
||||||
|
}
|
||||||
|
|
||||||
static function clearCharacterCache():Void
|
static function clearCharacterCache():Void
|
||||||
{
|
{
|
||||||
if (characterCache != null)
|
if (characterCache != null)
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package funkin.play.song;
|
package funkin.play.song;
|
||||||
|
|
||||||
|
import funkin.play.song.SongData.SongDataParser;
|
||||||
|
import funkin.play.song.SongData.SongMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a data structure managing information about the current song.
|
* This is a data structure managing information about the current song.
|
||||||
* This structure is created when the game starts, and includes all the data
|
* This structure is created when the game starts, and includes all the data
|
||||||
|
@ -9,20 +12,21 @@ package funkin.play.song;
|
||||||
* It also receives script events; scripted classes which extend this class
|
* It also receives script events; scripted classes which extend this class
|
||||||
* can be used to perform custom gameplay behaviors only on specific songs.
|
* can be used to perform custom gameplay behaviors only on specific songs.
|
||||||
*/
|
*/
|
||||||
class Song implements IPlayStateScriptedClass
|
class Song // implements IPlayStateScriptedClass
|
||||||
{
|
{
|
||||||
public var songId(default, null):String;
|
public var songId(default, null):String;
|
||||||
|
|
||||||
public var songName(get, null):String;
|
public var songName(get, null):String;
|
||||||
|
|
||||||
final _metadata:SongMetadata;
|
final _metadata:SongMetadata;
|
||||||
final _chartData:SongChartData;
|
|
||||||
|
// final _chartData:SongChartData;
|
||||||
|
|
||||||
public function new(id:String)
|
public function new(id:String)
|
||||||
{
|
{
|
||||||
this.songId = songId;
|
this.songId = id;
|
||||||
|
|
||||||
_metadata = SongDataParser.parseSongMetadata(this.songId);
|
_metadata = SongDataParser.parseSongMetadata(songId);
|
||||||
if (_metadata == null)
|
if (_metadata == null)
|
||||||
{
|
{
|
||||||
throw 'Could not find song data for songId: $songId';
|
throw 'Could not find song data for songId: $songId';
|
||||||
|
@ -35,4 +39,9 @@ class Song implements IPlayStateScriptedClass
|
||||||
return null;
|
return null;
|
||||||
return _metadata.name;
|
return _metadata.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function toString():String
|
||||||
|
{
|
||||||
|
return 'Song($songId)';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
package funkin.play.song;
|
package funkin.play.song;
|
||||||
|
|
||||||
|
import funkin.util.assets.DataAssets;
|
||||||
|
import openfl.utils.Assets;
|
||||||
|
import thx.semver.Version;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains utilities for loading and parsing stage data.
|
* Contains utilities for loading and parsing stage data.
|
||||||
*/
|
*/
|
||||||
|
@ -15,7 +21,7 @@ class SongDataParser
|
||||||
/**
|
/**
|
||||||
* A list containing all the songs available to the game.
|
* A list containing all the songs available to the game.
|
||||||
*/
|
*/
|
||||||
static final songCache:Map<String, Stage> = new Map<String, Stage>();
|
static final songCache:Map<String, Song> = new Map<String, Song>();
|
||||||
|
|
||||||
static final DEFAULT_SONG_ID = 'UNKNOWN';
|
static final DEFAULT_SONG_ID = 'UNKNOWN';
|
||||||
|
|
||||||
|
@ -59,11 +65,10 @@ class SongDataParser
|
||||||
trace(' Instantiating ${unscriptedSongIds.length} non-scripted songs...');
|
trace(' Instantiating ${unscriptedSongIds.length} non-scripted songs...');
|
||||||
for (songId in unscriptedSongIds)
|
for (songId in unscriptedSongIds)
|
||||||
{
|
{
|
||||||
var song:Song;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
stage = new Song(songId);
|
var song = new Song(songId);
|
||||||
if (stage != null)
|
if (song != null)
|
||||||
{
|
{
|
||||||
trace(' Loaded song data: ${song.songId}');
|
trace(' Loaded song data: ${song.songId}');
|
||||||
songCache.set(song.songId, song);
|
songCache.set(song.songId, song);
|
||||||
|
@ -83,7 +88,7 @@ class SongDataParser
|
||||||
/**
|
/**
|
||||||
* Retrieves a particular song from the cache.
|
* Retrieves a particular song from the cache.
|
||||||
*/
|
*/
|
||||||
public static function fetchStage(songId:String):Null<Song>
|
public static function fetchSong(songId:String):Null<Song>
|
||||||
{
|
{
|
||||||
if (songCache.exists(songId))
|
if (songCache.exists(songId))
|
||||||
{
|
{
|
||||||
|
@ -102,22 +107,20 @@ class SongDataParser
|
||||||
{
|
{
|
||||||
if (songCache != null)
|
if (songCache != null)
|
||||||
{
|
{
|
||||||
for (song in songCache)
|
|
||||||
{
|
|
||||||
song.destroy();
|
|
||||||
}
|
|
||||||
songCache.clear();
|
songCache.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function parseSongMetadata(songId:String):Null<SongMetadata>
|
public static function parseSongMetadata(songId:String):Null<SongMetadata>
|
||||||
{
|
{
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function loadSongMetadataFile(songPath:String, variant:String = ''):String
|
static function loadSongMetadataFile(songPath:String, variant:String = ''):String
|
||||||
{
|
{
|
||||||
var songMetadataFilePath:String = Paths.json('stages/${stagePath}');
|
var songMetadataFilePath:String = (variant != '') ? Paths.json('songs/${songPath}') : Paths.json('songs/${songPath}');
|
||||||
var rawJson = Assets.getText(stageFilePath).trim();
|
|
||||||
|
var rawJson:String = Assets.getText(songMetadataFilePath).trim();
|
||||||
|
|
||||||
while (!rawJson.endsWith("}"))
|
while (!rawJson.endsWith("}"))
|
||||||
{
|
{
|
||||||
|
@ -127,3 +130,25 @@ class SongDataParser
|
||||||
return rawJson;
|
return rawJson;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef SongMetadata =
|
||||||
|
{
|
||||||
|
var version:Version;
|
||||||
|
|
||||||
|
var songName:String;
|
||||||
|
var artist:String;
|
||||||
|
var timeFormat:SongTimeFormat;
|
||||||
|
var divisions:Int;
|
||||||
|
var timeChanges:Array<SongTimeChange>;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef SongChartData =
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
enum abstract SongTimeFormat(String) from String to String
|
||||||
|
{
|
||||||
|
var TICKS = "ticks";
|
||||||
|
var FLOAT = "float";
|
||||||
|
var MILLISECONDS = "ms";
|
||||||
|
}
|
||||||
|
|
|
@ -375,8 +375,11 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
|
|
||||||
// Add the character to the scene.
|
// Add the character to the scene.
|
||||||
this.add(character);
|
this.add(character);
|
||||||
|
|
||||||
|
#if debug
|
||||||
debugIconGroup.add(debugIcon);
|
debugIconGroup.add(debugIcon);
|
||||||
debugIconGroup.add(debugIcon2);
|
debugIconGroup.add(debugIcon2);
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function getGirlfriendPosition():FlxPoint
|
public inline function getGirlfriendPosition():FlxPoint
|
||||||
|
|
|
@ -141,6 +141,11 @@ class StageDataParser
|
||||||
return validateStageData(stageId, stageData);
|
return validateStageData(stageId, stageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function listStageIds():Array<String>
|
||||||
|
{
|
||||||
|
return [for (x in stageCache.keys()) x];
|
||||||
|
}
|
||||||
|
|
||||||
static function loadStageFile(stagePath:String):String
|
static function loadStageFile(stagePath:String):String
|
||||||
{
|
{
|
||||||
var stageFilePath:String = Paths.json('stages/${stagePath}');
|
var stageFilePath:String = Paths.json('stages/${stagePath}');
|
||||||
|
|
|
@ -27,7 +27,7 @@ class OptionsState extends MusicBeatState
|
||||||
menuBG.scrollFactor.set(0, 0);
|
menuBG.scrollFactor.set(0, 0);
|
||||||
add(menuBG);
|
add(menuBG);
|
||||||
|
|
||||||
var options = addPage(Options, new OptionsMenu(false));
|
var options = addPage(Options, new OptionsMenu());
|
||||||
var preferences = addPage(Preferences, new PreferencesMenu());
|
var preferences = addPage(Preferences, new PreferencesMenu());
|
||||||
var controls = addPage(Controls, new ControlsMenu());
|
var controls = addPage(Controls, new ControlsMenu());
|
||||||
|
|
||||||
|
@ -167,22 +167,14 @@ class OptionsMenu extends Page
|
||||||
{
|
{
|
||||||
var items:TextMenuList;
|
var items:TextMenuList;
|
||||||
|
|
||||||
public function new(showDonate:Bool)
|
public function new()
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
|
||||||
add(items = new TextMenuList());
|
add(items = new TextMenuList());
|
||||||
createItem("PREFERENCES", function() switchPage(Preferences));
|
createItem("PREFERENCES", function() switchPage(Preferences));
|
||||||
createItem("CONTROLS", function() switchPage(Controls));
|
createItem("CONTROLS", function() switchPage(Controls));
|
||||||
// createItem("COLORS", function() switchPage(Colors));
|
|
||||||
|
|
||||||
#if CAN_OPEN_LINKS
|
|
||||||
if (showDonate)
|
|
||||||
{
|
|
||||||
var hasPopupBlocker = #if web true #else false #end;
|
|
||||||
createItem("DONATE", selectDonate, hasPopupBlocker);
|
|
||||||
}
|
|
||||||
#end
|
|
||||||
#if newgrounds
|
#if newgrounds
|
||||||
if (NGio.isLoggedIn)
|
if (NGio.isLoggedIn)
|
||||||
createItem("LOGOUT", selectLogout);
|
createItem("LOGOUT", selectLogout);
|
||||||
|
@ -215,13 +207,6 @@ class OptionsMenu extends Page
|
||||||
return items.length > 2;
|
return items.length > 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CAN_OPEN_LINKS
|
|
||||||
function selectDonate()
|
|
||||||
{
|
|
||||||
WindowUtil.openURL(Constants.URL_ITCH);
|
|
||||||
}
|
|
||||||
#end
|
|
||||||
|
|
||||||
#if newgrounds
|
#if newgrounds
|
||||||
function selectLogin()
|
function selectLogin()
|
||||||
{
|
{
|
||||||
|
|
95
source/funkin/ui/debug/DebugMenuSubState.hx
Normal file
95
source/funkin/ui/debug/DebugMenuSubState.hx
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package funkin.ui.debug;
|
||||||
|
|
||||||
|
import flixel.FlxObject;
|
||||||
|
import flixel.FlxSprite;
|
||||||
|
import funkin.MusicBeatSubstate;
|
||||||
|
import funkin.ui.TextMenuList;
|
||||||
|
import funkin.ui.debug.charting.ChartEditorState;
|
||||||
|
|
||||||
|
class DebugMenuSubState extends MusicBeatSubstate
|
||||||
|
{
|
||||||
|
var items:TextMenuList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Camera focus point
|
||||||
|
*/
|
||||||
|
var camFocusPoint:FlxObject;
|
||||||
|
|
||||||
|
override function create()
|
||||||
|
{
|
||||||
|
super.create();
|
||||||
|
|
||||||
|
// Create an object for the camera to track.
|
||||||
|
camFocusPoint = new FlxObject(0, 0);
|
||||||
|
add(camFocusPoint);
|
||||||
|
|
||||||
|
// Follow the camera focus as we scroll.
|
||||||
|
FlxG.camera.follow(camFocusPoint, null, 0.06);
|
||||||
|
|
||||||
|
// Create the green background.
|
||||||
|
var menuBG = new FlxSprite().loadGraphic(Paths.image('menuDesat'));
|
||||||
|
menuBG.color = 0xFF4CAF50;
|
||||||
|
menuBG.setGraphicSize(Std.int(menuBG.width * 1.1));
|
||||||
|
menuBG.updateHitbox();
|
||||||
|
menuBG.screenCenter();
|
||||||
|
menuBG.scrollFactor.set(0, 0);
|
||||||
|
add(menuBG);
|
||||||
|
|
||||||
|
// Create the list for menu items.
|
||||||
|
items = new TextMenuList();
|
||||||
|
// Move the camera when the menu is scrolled.
|
||||||
|
items.onChange.add(onMenuChange);
|
||||||
|
add(items);
|
||||||
|
|
||||||
|
// Create each menu item.
|
||||||
|
// Call onMenuChange when the first item is created to move the camera .
|
||||||
|
onMenuChange(createItem("CHART EDITOR", openChartEditor));
|
||||||
|
createItem("ANIMATION EDITOR", openAnimationEditor);
|
||||||
|
createItem("STAGE EDITOR", openStageEditor);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMenuChange(selected:TextMenuItem)
|
||||||
|
{
|
||||||
|
camFocusPoint.setPosition(selected.x + selected.width / 2, selected.y + selected.height / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function update(elapsed:Float)
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
if (controls.BACK)
|
||||||
|
{
|
||||||
|
FlxG.sound.play(Paths.sound('cancelMenu'));
|
||||||
|
exitDebugMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openChartEditor()
|
||||||
|
{
|
||||||
|
FlxG.switchState(new ChartEditorState());
|
||||||
|
}
|
||||||
|
|
||||||
|
function openAnimationEditor()
|
||||||
|
{
|
||||||
|
trace('Animation Editor');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openStageEditor()
|
||||||
|
{
|
||||||
|
trace('Stage Editor');
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitDebugMenu()
|
||||||
|
{
|
||||||
|
// TODO: Add a transition?
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
}
|
237
source/funkin/ui/debug/charting/ChartEditorState.hx
Normal file
237
source/funkin/ui/debug/charting/ChartEditorState.hx
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
package funkin.ui.debug.charting;
|
||||||
|
|
||||||
|
import flixel.FlxSprite;
|
||||||
|
import flixel.addons.display.FlxGridOverlay;
|
||||||
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import funkin.ui.haxeui.HaxeUIState;
|
||||||
|
import haxe.ui.containers.dialogs.Dialog;
|
||||||
|
import haxe.ui.containers.menus.MenuItem;
|
||||||
|
import haxe.ui.core.Component;
|
||||||
|
import haxe.ui.events.MouseEvent;
|
||||||
|
import openfl.display.BitmapData;
|
||||||
|
|
||||||
|
class ChartEditorState extends HaxeUIState
|
||||||
|
{
|
||||||
|
static final CHART_EDITOR_LAYOUT = Paths.ui('chart-editor/main-view');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of notes on each character's strumline.
|
||||||
|
* TODO: Refactor this logic for larger strumlines in the future.
|
||||||
|
*/
|
||||||
|
static final STRUMLINE_SIZE = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height of the menu bar in pixels. Used for positioning UI components.
|
||||||
|
*/
|
||||||
|
static final MENU_BAR_HEIGHT = 32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width (and height) of each grid square, in pixels.
|
||||||
|
*/
|
||||||
|
static final GRID_SIZE:Int = 40;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pixel distance between the menu bar and the start of the chart grid.
|
||||||
|
*/
|
||||||
|
static final GRID_TOP_PAD:Int = 8;
|
||||||
|
|
||||||
|
static final GRID_ALTERNATE:Bool = true;
|
||||||
|
static final GRID_COLOR_1:FlxColor = 0xFFE7E6E6;
|
||||||
|
static final GRID_COLOR_2:FlxColor = 0xFFD9D5D5;
|
||||||
|
|
||||||
|
var gridBitmap:BitmapData;
|
||||||
|
var gridSprites:FlxSpriteGroup;
|
||||||
|
var gridDividerA:FlxSprite;
|
||||||
|
var gridDividerB:FlxSprite;
|
||||||
|
|
||||||
|
var menuBG:FlxSprite;
|
||||||
|
|
||||||
|
// TODO: Make the unit of measurement for this non-arbitrary
|
||||||
|
// to assist with logic later.
|
||||||
|
var scrollPosition(default, set):Float = -1.0;
|
||||||
|
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super(CHART_EDITOR_LAYOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function create()
|
||||||
|
{
|
||||||
|
FlxG.sound.music.stop();
|
||||||
|
|
||||||
|
buildBackground();
|
||||||
|
buildGrid();
|
||||||
|
|
||||||
|
super.create();
|
||||||
|
|
||||||
|
setupMenuListeners();
|
||||||
|
|
||||||
|
scrollPosition = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildBackground()
|
||||||
|
{
|
||||||
|
menuBG = new FlxSprite().loadGraphic(Paths.image('menuDesat'));
|
||||||
|
add(menuBG);
|
||||||
|
menuBG.color = 0xFF673ab7;
|
||||||
|
menuBG.setGraphicSize(Std.int(menuBG.width * 1.1));
|
||||||
|
menuBG.updateHitbox();
|
||||||
|
menuBG.screenCenter();
|
||||||
|
menuBG.scrollFactor.set(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildGrid()
|
||||||
|
{
|
||||||
|
// The checkerboard background image of the chart.
|
||||||
|
// 2 * (Strumline Size) + 1 grid squares wide, by 2 grid squares tall.
|
||||||
|
// This gets reused to fill the screen.
|
||||||
|
gridBitmap = FlxGridOverlay.createGrid(GRID_SIZE, GRID_SIZE, GRID_SIZE * (STRUMLINE_SIZE * 2 + 1), GRID_SIZE * 2, GRID_ALTERNATE, GRID_COLOR_1,
|
||||||
|
GRID_COLOR_2);
|
||||||
|
|
||||||
|
gridSprites = new FlxSpriteGroup();
|
||||||
|
add(gridSprites);
|
||||||
|
|
||||||
|
for (i in 0...10)
|
||||||
|
{
|
||||||
|
var gridSprite = new FlxSprite().loadGraphic(gridBitmap);
|
||||||
|
gridSprite.x = FlxG.width / 2 - GRID_SIZE * STRUMLINE_SIZE; // Center the grid.
|
||||||
|
gridSprite.y = MENU_BAR_HEIGHT + GRID_TOP_PAD + (i * gridSprite.height); // Push down to account for the menu bar.
|
||||||
|
gridSprites.add(gridSprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The black divider between the two halves of the chart.
|
||||||
|
gridDividerA = new FlxSprite(gridSprites.members[0].x + GRID_SIZE * STRUMLINE_SIZE,
|
||||||
|
MENU_BAR_HEIGHT).makeGraphic(2, FlxG.height - MENU_BAR_HEIGHT, FlxColor.BLACK);
|
||||||
|
add(gridDividerA);
|
||||||
|
gridDividerB = new FlxSprite(gridSprites.members[0].x + GRID_SIZE * STRUMLINE_SIZE * 2,
|
||||||
|
MENU_BAR_HEIGHT).makeGraphic(2, FlxG.height - MENU_BAR_HEIGHT, FlxColor.BLACK);
|
||||||
|
add(gridDividerB);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function update(elapsed:Float)
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
FlxG.mouse.visible = true;
|
||||||
|
|
||||||
|
handleScroll();
|
||||||
|
|
||||||
|
if (FlxG.keys.justPressed.B)
|
||||||
|
toggleSidebar();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleScroll()
|
||||||
|
{
|
||||||
|
var scrollAmount:Float = 0;
|
||||||
|
|
||||||
|
if (FlxG.keys.justPressed.UP)
|
||||||
|
{
|
||||||
|
scrollAmount = -10;
|
||||||
|
}
|
||||||
|
if (FlxG.keys.justPressed.DOWN)
|
||||||
|
{
|
||||||
|
scrollAmount = 10;
|
||||||
|
}
|
||||||
|
if (FlxG.mouse.wheel != 0)
|
||||||
|
{
|
||||||
|
scrollAmount = -10 * FlxG.mouse.wheel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FlxG.keys.pressed.SHIFT)
|
||||||
|
{
|
||||||
|
scrollAmount *= 10;
|
||||||
|
}
|
||||||
|
if (FlxG.keys.pressed.CONTROL)
|
||||||
|
{
|
||||||
|
scrollAmount /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scrollPosition += scrollAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_scrollPosition(value:Float):Float
|
||||||
|
{
|
||||||
|
// TODO: Calculate this.
|
||||||
|
var MAX_SCROLL = 10000;
|
||||||
|
if (value == scrollPosition || value < 0 || value > MAX_SCROLL)
|
||||||
|
return scrollPosition;
|
||||||
|
|
||||||
|
this.scrollPosition = value;
|
||||||
|
|
||||||
|
trace('SCROLL: $scrollPosition');
|
||||||
|
|
||||||
|
// Move the grid sprites to the correct position.
|
||||||
|
gridSprites.y = -scrollPosition;
|
||||||
|
|
||||||
|
// Nudge the grid dividers down if needed.
|
||||||
|
if (-gridSprites.y < GRID_TOP_PAD)
|
||||||
|
{
|
||||||
|
gridDividerA.y = MENU_BAR_HEIGHT + GRID_TOP_PAD + gridSprites.y;
|
||||||
|
gridDividerB.y = MENU_BAR_HEIGHT + GRID_TOP_PAD + gridSprites.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gridDividerA.y = MENU_BAR_HEIGHT;
|
||||||
|
gridDividerB.y = MENU_BAR_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rearrange grid sprites so they stay on screen.
|
||||||
|
gridSprites.forEachAlive(function(sprite:FlxSprite)
|
||||||
|
{
|
||||||
|
// If this grid sprite is off the top of the screen...
|
||||||
|
if (sprite.y + sprite.height < MENU_BAR_HEIGHT)
|
||||||
|
{
|
||||||
|
// Move it to the bottom of the screen.
|
||||||
|
sprite.y += sprite.height * gridSprites.length;
|
||||||
|
}
|
||||||
|
// If this grid sprite is off the bottom of the screen...
|
||||||
|
if (sprite.y > FlxG.height)
|
||||||
|
{
|
||||||
|
// Move it to the top of the screen.
|
||||||
|
sprite.y -= sprite.height * gridSprites.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Add a clip rectangle to the FlxSpriteGroup to hide the grid sprites that got moved up,
|
||||||
|
// when we scroll back to the top of the chart.
|
||||||
|
// Note that clip rectangles on sprite groups are borken right now, so we'll have to wait for that to be fixed.
|
||||||
|
|
||||||
|
return this.scrollPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSidebar()
|
||||||
|
{
|
||||||
|
var sidebar:Component = this.component.findComponent('sidebar', Component);
|
||||||
|
|
||||||
|
sidebar.visible = !sidebar.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openDialog(key:String, modal:Bool = true)
|
||||||
|
{
|
||||||
|
var dialog:Dialog = cast buildComponent(Paths.ui(key));
|
||||||
|
|
||||||
|
// modal = true makes the background unclickable
|
||||||
|
dialog.showDialog(modal);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupMenuListeners()
|
||||||
|
{
|
||||||
|
addMenuListener('menubarItemToggleSidebar', (event:MouseEvent) -> toggleSidebar());
|
||||||
|
addMenuListener('menubarItemAbout', (event:MouseEvent) -> openDialog('chart-editor/dialogs/about'));
|
||||||
|
addMenuListener('menubarItemUserGuide', (event:MouseEvent) -> openDialog('chart-editor/dialogs/user-guide'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMenuListener(key:String, callback:MouseEvent->Void)
|
||||||
|
{
|
||||||
|
var menuItem:MenuItem = this.component.findComponent(key, MenuItem);
|
||||||
|
if (menuItem == null)
|
||||||
|
{
|
||||||
|
trace('WARN: Could not locate menu item: $key');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
menuItem.onClick = callback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
source/funkin/ui/haxeui/HaxeUIState.hx
Normal file
48
source/funkin/ui/haxeui/HaxeUIState.hx
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package funkin.ui.haxeui;
|
||||||
|
|
||||||
|
import haxe.ui.RuntimeComponentBuilder;
|
||||||
|
import haxe.ui.core.Component;
|
||||||
|
|
||||||
|
class HaxeUIState extends MusicBeatState
|
||||||
|
{
|
||||||
|
public var component:Component;
|
||||||
|
|
||||||
|
var _componentKey:String;
|
||||||
|
|
||||||
|
public function new(key:String)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
_componentKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
override function create()
|
||||||
|
{
|
||||||
|
super.create();
|
||||||
|
|
||||||
|
if (component == null)
|
||||||
|
component = buildComponent(_componentKey);
|
||||||
|
if (component != null)
|
||||||
|
add(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildComponent(assetPath:String)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return RuntimeComponentBuilder.fromAsset(assetPath);
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
trace('[ERROR] Failed to build component from asset: ' + assetPath);
|
||||||
|
trace(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override function destroy()
|
||||||
|
{
|
||||||
|
if (component != null)
|
||||||
|
remove(component);
|
||||||
|
component = null;
|
||||||
|
}
|
||||||
|
}
|
93
source/funkin/ui/haxeui/HaxeUISubState.hx
Normal file
93
source/funkin/ui/haxeui/HaxeUISubState.hx
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package funkin.ui.haxeui;
|
||||||
|
|
||||||
|
import haxe.ui.RuntimeComponentBuilder;
|
||||||
|
import haxe.ui.core.Component;
|
||||||
|
|
||||||
|
class HaxeUISubState extends MusicBeatSubstate
|
||||||
|
{
|
||||||
|
// The component representing the main UI.
|
||||||
|
public var component:Component;
|
||||||
|
|
||||||
|
var _componentKey:String;
|
||||||
|
|
||||||
|
public function new(key:String)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
_componentKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
override function create()
|
||||||
|
{
|
||||||
|
super.create();
|
||||||
|
|
||||||
|
refreshComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a component from a given XML file.
|
||||||
|
* Call this in your code to load additional components at runtime.
|
||||||
|
*/
|
||||||
|
public function buildComponent(assetPath:String)
|
||||||
|
{
|
||||||
|
trace('Building component $assetPath');
|
||||||
|
return RuntimeComponentBuilder.fromAsset(assetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function update(elapsed:Float)
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
// Force quit.
|
||||||
|
if (FlxG.keys.justPressed.F4)
|
||||||
|
FlxG.switchState(new MainMenuState());
|
||||||
|
|
||||||
|
// Refresh the component.
|
||||||
|
if (FlxG.keys.justPressed.F5)
|
||||||
|
{
|
||||||
|
refreshComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshComponent()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (component != null)
|
||||||
|
{
|
||||||
|
remove(component);
|
||||||
|
component = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component != null)
|
||||||
|
{
|
||||||
|
trace('Success!');
|
||||||
|
add(component);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace('Failed to build component $_componentKey');
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (component == null)
|
||||||
|
{
|
||||||
|
component = buildComponent(_componentKey);
|
||||||
|
add(component);
|
||||||
|
trace(component);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var component2 = buildComponent(_componentKey);
|
||||||
|
component2.x += 100;
|
||||||
|
add(component2);
|
||||||
|
trace(component2);
|
||||||
|
remove(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override function destroy()
|
||||||
|
{
|
||||||
|
if (component != null)
|
||||||
|
remove(component);
|
||||||
|
component = null;
|
||||||
|
}
|
||||||
|
}
|
101
source/funkin/ui/haxeui/components/TabSideBar.hx
Normal file
101
source/funkin/ui/haxeui/components/TabSideBar.hx
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
package funkin.ui.haxeui.components;
|
||||||
|
|
||||||
|
import haxe.ui.Toolkit;
|
||||||
|
import haxe.ui.containers.SideBar;
|
||||||
|
import haxe.ui.core.Component;
|
||||||
|
import haxe.ui.core.Screen;
|
||||||
|
import haxe.ui.styles.elements.AnimationKeyFrame;
|
||||||
|
import haxe.ui.styles.elements.AnimationKeyFrames;
|
||||||
|
import haxe.ui.styles.elements.Directive;
|
||||||
|
|
||||||
|
class TabSideBar extends SideBar
|
||||||
|
{
|
||||||
|
var closeButton:Component;
|
||||||
|
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function getCloseButton()
|
||||||
|
{
|
||||||
|
if (closeButton == null)
|
||||||
|
{
|
||||||
|
closeButton = findComponent("closeSideBar", Component);
|
||||||
|
}
|
||||||
|
return closeButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function hide()
|
||||||
|
{
|
||||||
|
var animation = Toolkit.styleSheet.findAnimation("sideBarRestoreContent");
|
||||||
|
var first:AnimationKeyFrame = animation.keyFrames[0];
|
||||||
|
var last:AnimationKeyFrame = animation.keyFrames[animation.keyFrames.length - 1];
|
||||||
|
var rootComponent = Screen.instance.rootComponents[0];
|
||||||
|
|
||||||
|
first.set(new Directive("left", Value.VDimension(Dimension.PX(rootComponent.left))));
|
||||||
|
first.set(new Directive("top", Value.VDimension(Dimension.PX(rootComponent.top))));
|
||||||
|
first.set(new Directive("width", Value.VDimension(Dimension.PX(rootComponent.width))));
|
||||||
|
first.set(new Directive("height", Value.VDimension(Dimension.PX(rootComponent.height))));
|
||||||
|
|
||||||
|
last.set(new Directive("left", Value.VDimension(Dimension.PX(0))));
|
||||||
|
last.set(new Directive("top", Value.VDimension(Dimension.PX(0))));
|
||||||
|
last.set(new Directive("width", Value.VDimension(Dimension.PX(Screen.instance.width))));
|
||||||
|
last.set(new Directive("height", Value.VDimension(Dimension.PX(Screen.instance.height))));
|
||||||
|
|
||||||
|
for (r in Screen.instance.rootComponents)
|
||||||
|
{
|
||||||
|
if (r.classes.indexOf("sidebar") == -1)
|
||||||
|
{
|
||||||
|
r.swapClass("sideBarRestoreContent", "sideBarModifyContent");
|
||||||
|
r.onAnimationEnd = function(_)
|
||||||
|
{
|
||||||
|
r.restorePercentSizes();
|
||||||
|
r.onAnimationEnd = null;
|
||||||
|
rootComponent.removeClass("sideBarRestoreContent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideSideBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
private override function hideSideBar()
|
||||||
|
{
|
||||||
|
var showSideBarClass = null;
|
||||||
|
var hideSideBarClass = null;
|
||||||
|
if (position == "left")
|
||||||
|
{
|
||||||
|
showSideBarClass = "showSideBarLeft";
|
||||||
|
hideSideBarClass = "hideSideBarLeft";
|
||||||
|
}
|
||||||
|
else if (position == "right")
|
||||||
|
{
|
||||||
|
showSideBarClass = "showSideBarRight";
|
||||||
|
hideSideBarClass = "hideSideBarRight";
|
||||||
|
}
|
||||||
|
else if (position == "top")
|
||||||
|
{
|
||||||
|
showSideBarClass = "showSideBarTop";
|
||||||
|
hideSideBarClass = "hideSideBarTop";
|
||||||
|
}
|
||||||
|
else if (position == "bottom")
|
||||||
|
{
|
||||||
|
showSideBarClass = "showSideBarBottom";
|
||||||
|
hideSideBarClass = "hideSideBarBottom";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onAnimationEnd = function(_)
|
||||||
|
{
|
||||||
|
this.removeClass(hideSideBarClass);
|
||||||
|
// onHideAnimationEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.swapClass(hideSideBarClass, showSideBarClass);
|
||||||
|
|
||||||
|
if (modal == true)
|
||||||
|
{
|
||||||
|
hideModalOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,9 @@ class Constants
|
||||||
|
|
||||||
public static final FREAKY_MENU_BPM = 102;
|
public static final FREAKY_MENU_BPM = 102;
|
||||||
|
|
||||||
|
// Change this if you're making an engine.
|
||||||
|
public static final TITLE = "Friday Night Funkin'";
|
||||||
|
|
||||||
#if debug
|
#if debug
|
||||||
public static final GIT_HASH = funkin.util.macro.GitCommit.getGitCommitHash();
|
public static final GIT_HASH = funkin.util.macro.GitCommit.getGitCommitHash();
|
||||||
|
|
||||||
|
@ -35,5 +38,5 @@ class Constants
|
||||||
#end
|
#end
|
||||||
|
|
||||||
public static final URL_KICKSTARTER:String = "https://www.kickstarter.com/projects/funkin/friday-night-funkin-the-full-ass-game/";
|
public static final URL_KICKSTARTER:String = "https://www.kickstarter.com/projects/funkin/friday-night-funkin-the-full-ass-game/";
|
||||||
public static final URL_ITCH:String = "https://ninja-muffin24.itch.io/funkin";
|
public static final URL_ITCH:String = "https://ninja-muffin24.itch.io/funkin/purchase";
|
||||||
}
|
}
|
||||||
|
|
22
source/module.xml
Normal file
22
source/module.xml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<module>
|
||||||
|
<!-- A module provides additional behavior and configuration for HaxeUI. -->
|
||||||
|
<components>
|
||||||
|
<!--
|
||||||
|
Ensure all components get included at compilation time.
|
||||||
|
This needs to be done HERE and not via the `include` macro because `Toolkit.init()`
|
||||||
|
reads this to build the component registry.
|
||||||
|
-->
|
||||||
|
<class package="haxe.ui.core" loadAll="true" />
|
||||||
|
|
||||||
|
<class package="haxe.ui.components" loadAll="true" />
|
||||||
|
|
||||||
|
<class package="haxe.ui.containers" loadAll="true" />
|
||||||
|
<class package="haxe.ui.containers.menus" loadAll="true" />
|
||||||
|
<class package="haxe.ui.containers.dialogs" loadAll="true" />
|
||||||
|
<class package="haxe.ui.containers.properties" loadAll="true" />
|
||||||
|
|
||||||
|
<!-- Custom components. -->
|
||||||
|
<class package="funkin.ui.haxeui.components" loadAll="true" />
|
||||||
|
</components>
|
||||||
|
</module>
|
Loading…
Reference in a new issue