mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-27 01:55:52 -05:00
add rebind key prompt
This commit is contained in:
parent
9ffa28dd21
commit
9c1866dbdb
7 changed files with 200 additions and 49 deletions
|
@ -11,6 +11,30 @@ import flixel.input.gamepad.FlxGamepadButton;
|
|||
import flixel.input.gamepad.FlxGamepadInputID;
|
||||
import flixel.input.keyboard.FlxKey;
|
||||
|
||||
/**
|
||||
* Since, in many cases multiple actions should use similar keys, we don't want the
|
||||
* rebinding UI to list every action. ActionBinders are what the user percieves as
|
||||
* an input so, for instance, they can't set jump-press and jump-release to different keys.
|
||||
*/
|
||||
enum Control
|
||||
{
|
||||
NOTE_UP;
|
||||
NOTE_LEFT;
|
||||
NOTE_RIGHT;
|
||||
NOTE_DOWN;
|
||||
UI_UP;
|
||||
UI_LEFT;
|
||||
UI_RIGHT;
|
||||
UI_DOWN;
|
||||
RESET;
|
||||
ACCEPT;
|
||||
BACK;
|
||||
PAUSE;
|
||||
#if CAN_CHEAT
|
||||
CHEAT;
|
||||
#end
|
||||
}
|
||||
|
||||
@:enum
|
||||
abstract Action(String) to String from String
|
||||
{
|
||||
|
@ -53,30 +77,6 @@ enum Device
|
|||
Gamepad(id:Int);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since, in many cases multiple actions should use similar keys, we don't want the
|
||||
* rebinding UI to list every action. ActionBinders are what the user percieves as
|
||||
* an input so, for instance, they can't set jump-press and jump-release to different keys.
|
||||
*/
|
||||
enum Control
|
||||
{
|
||||
UI_UP;
|
||||
UI_LEFT;
|
||||
UI_RIGHT;
|
||||
UI_DOWN;
|
||||
NOTE_UP;
|
||||
NOTE_LEFT;
|
||||
NOTE_RIGHT;
|
||||
NOTE_DOWN;
|
||||
RESET;
|
||||
ACCEPT;
|
||||
BACK;
|
||||
PAUSE;
|
||||
#if CAN_CHEAT
|
||||
CHEAT;
|
||||
#end
|
||||
}
|
||||
|
||||
enum KeyboardScheme
|
||||
{
|
||||
Solo;
|
||||
|
@ -450,7 +450,7 @@ class Controls extends FlxActionSet
|
|||
bindKeys(Control.NOTE_LEFT, [A, FlxKey.LEFT]);
|
||||
bindKeys(Control.NOTE_RIGHT, [D, FlxKey.RIGHT]);
|
||||
bindKeys(Control.ACCEPT, [Z, SPACE, ENTER]);
|
||||
bindKeys(Control.BACK, [BACKSPACE, ESCAPE]);
|
||||
bindKeys(Control.BACK, [X, BACKSPACE, ESCAPE]);
|
||||
bindKeys(Control.PAUSE, [P, ENTER, ESCAPE]);
|
||||
bindKeys(Control.RESET, [R]);
|
||||
case Duo(true):
|
||||
|
|
|
@ -148,6 +148,7 @@ class AtlasText extends FlxTypedSpriteGroup<AtlasChar>
|
|||
}
|
||||
charSprite.x = xPos;
|
||||
charSprite.y = yPos + maxHeight - charSprite.height;
|
||||
charSprite.alpha = 1;//gets multiplied when added
|
||||
add(charSprite);
|
||||
|
||||
xPos += charSprite.width;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ui;
|
||||
|
||||
import ui.MenuList;
|
||||
import flixel.FlxG;
|
||||
import flixel.FlxCamera;
|
||||
import flixel.FlxObject;
|
||||
|
@ -13,9 +14,23 @@ import ui.TextMenuList;
|
|||
|
||||
class ControlsMenu extends ui.OptionsState.Page
|
||||
{
|
||||
var controlGrid:TextMenuList;
|
||||
static var controlList = Control.createAll();
|
||||
/*
|
||||
* Defines groups of controls that cannot share inputs, like left and right. Say, if ACCEPT is Z, Back is X,
|
||||
* if the player sets Back to Z it also set ACCEPT to X. This prevents the player from setting the controls in
|
||||
* a way the prevents them from changing more controls or exiting the menu.
|
||||
*/
|
||||
static var controlGroups:Array<Array<Control>> =
|
||||
[ [ NOTE_UP, NOTE_DOWN, NOTE_LEFT, NOTE_RIGHT ]
|
||||
, [ UI_UP, UI_DOWN, UI_LEFT, UI_RIGHT, ACCEPT, BACK ]
|
||||
];
|
||||
|
||||
var itemGroups:Array<Array<InputItem>> = [for (i in 0...controlGroups.length) []];
|
||||
|
||||
var controlGrid:MenuTypedList<InputItem>;
|
||||
var labels:FlxTypedGroup<AtlasText>;
|
||||
var menuCamera:FlxCamera;
|
||||
var prompt:Prompt;
|
||||
|
||||
public function new()
|
||||
{
|
||||
|
@ -29,54 +44,135 @@ class ControlsMenu extends ui.OptionsState.Page
|
|||
FlxCamera.defaultCameras.remove(menuCamera);
|
||||
}
|
||||
menuCamera.bgColor = 0x0;
|
||||
camera = menuCamera;
|
||||
|
||||
add(labels = new FlxTypedGroup<AtlasText>());
|
||||
labels.camera = menuCamera;
|
||||
|
||||
add(controlGrid = new TextMenuList(Columns(2)));
|
||||
controlGrid.camera = menuCamera;
|
||||
add(controlGrid = new MenuTypedList(Columns(2)));
|
||||
|
||||
// FlxG.debugger.drawDebug = true;
|
||||
var controlList = Control.createAll();
|
||||
var y = 30;
|
||||
var spacer = 70;
|
||||
var currentHeader:String = null;
|
||||
// list order is determined by enum order
|
||||
for (i in 0...controlList.length)
|
||||
{
|
||||
var control = controlList[i];
|
||||
var name = control.getName();
|
||||
var y = (70 * i) + 30;
|
||||
var label = labels.add(new BoldText(0, y, name));
|
||||
label.x += 250;
|
||||
if (currentHeader != "UI_" && name.indexOf("UI_") == 0)
|
||||
{
|
||||
currentHeader = "UI_";
|
||||
labels.add(new BoldText(0, y, "UI")).screenCenter(X);
|
||||
y += spacer;
|
||||
}
|
||||
else if (currentHeader != "NOTE_" && name.indexOf("NOTE_") == 0)
|
||||
{
|
||||
currentHeader = "NOTE_";
|
||||
labels.add(new BoldText(0, y, "NOTES")).screenCenter(X);
|
||||
y += spacer;
|
||||
}
|
||||
|
||||
if (currentHeader != null && name.indexOf(currentHeader) == 0)
|
||||
name = name.substr(currentHeader.length);
|
||||
|
||||
var label = labels.add(new BoldText(250, y, name));
|
||||
createItem(label.x + 400, y, control, 0);
|
||||
createItem(label.x + 600, y, control, 1);
|
||||
y += spacer;
|
||||
}
|
||||
|
||||
trace(itemGroups.map((group)->group.map((item)->item.label.text)));
|
||||
|
||||
var selected = controlGrid.members[0];
|
||||
var camFollow = new FlxObject(FlxG.width / 2, selected.y, 70, 70);
|
||||
menuCamera.follow(camFollow, null, 0.06);
|
||||
var margin = 100;
|
||||
menuCamera.deadzone.set(0, margin, menuCamera.width, menuCamera.height - margin * 2);
|
||||
controlGrid.onChange.add(function (selected) camFollow.y = selected.y);
|
||||
|
||||
prompt = new Prompt("Press any key to rebind\n\n\n\n Escape to cancel", None);
|
||||
prompt.create();
|
||||
prompt.createBgFromMargin();
|
||||
prompt.back.scrollFactor.set(0, 0);
|
||||
prompt.exists = false;
|
||||
add(prompt);
|
||||
}
|
||||
|
||||
function createItem(x = 0.0, y = 0.0, control:Control, index:Int)
|
||||
{
|
||||
var list = PlayerSettings.player1.controls.getInputsFor(control, Keys);
|
||||
var name = "---";
|
||||
if (list.length > index)
|
||||
var item = new InputItem(x, y, control, index, onSelect);
|
||||
for (i in 0...controlGroups.length)
|
||||
{
|
||||
if (list[index] == FlxKey.ESCAPE)
|
||||
return createItem(x, y, control, 2);
|
||||
|
||||
name = InputFormatter.format(list[index], Keys);
|
||||
if (controlGroups[i].contains(control))
|
||||
itemGroups[i].push(item);
|
||||
}
|
||||
|
||||
trace(control.getName() + " " + index + ": " + name);
|
||||
return controlGrid.createItem(x, y, name, Default, onSelect.bind(name, control, index));
|
||||
return controlGrid.addItem(item.name, item);
|
||||
}
|
||||
|
||||
function onSelect(name:String, control:Control, index:Int):Void
|
||||
function onSelect():Void
|
||||
{
|
||||
controlGrid.enabled = false;
|
||||
// var prompt = new Prompt();
|
||||
canExit = false;
|
||||
prompt.exists = true;
|
||||
}
|
||||
|
||||
override function update(elapsed:Float)
|
||||
{
|
||||
super.update(elapsed);
|
||||
|
||||
if (prompt.exists)
|
||||
{
|
||||
var key = FlxG.keys.firstJustPressed();
|
||||
if (key != NONE)
|
||||
{
|
||||
if (key != ESCAPE)
|
||||
onKeySelect(key);
|
||||
closePrompt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onKeySelect(key:Int)
|
||||
{
|
||||
var item = controlGrid.selectedItem;
|
||||
for (group in itemGroups)
|
||||
{
|
||||
if (group.contains(item))
|
||||
{
|
||||
for (otherItem in group)
|
||||
{
|
||||
// Check if items in the same group have the new input
|
||||
if (otherItem != item && otherItem.input == key)
|
||||
{
|
||||
// replace that input with this items old input.
|
||||
PlayerSettings.player1.controls.replaceBinding(otherItem.control, Keys, item.input, otherItem.input);
|
||||
// Don't use resetItem() since items share names/labels
|
||||
otherItem.input = item.input;
|
||||
otherItem.label.text = item.label.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlayerSettings.player1.controls.replaceBinding(item.control, Keys, key, item.input);
|
||||
// Don't use resetItem() since items share names/labels
|
||||
item.input = key;
|
||||
item.label.text = item.getLabel(key);
|
||||
}
|
||||
|
||||
function closePrompt()
|
||||
{
|
||||
controlGrid.enabled = true;
|
||||
canExit = true;
|
||||
prompt.exists = false;
|
||||
}
|
||||
|
||||
override function destroy()
|
||||
{
|
||||
super.destroy();
|
||||
|
||||
if (FlxG.cameras.list.contains(menuCamera))
|
||||
FlxG.cameras.remove(menuCamera);
|
||||
}
|
||||
|
||||
override function set_enabled(value:Bool)
|
||||
|
@ -84,4 +180,33 @@ class ControlsMenu extends ui.OptionsState.Page
|
|||
controlGrid.enabled = value;
|
||||
return super.set_enabled(value);
|
||||
}
|
||||
}
|
||||
|
||||
class InputItem extends TextMenuItem
|
||||
{
|
||||
public var control:Control;
|
||||
public var input:Int = -1;
|
||||
|
||||
public function new (x = 0.0, y = 0.0, control, index, ?callback)
|
||||
{
|
||||
this.control = control;
|
||||
|
||||
var list = PlayerSettings.player1.controls.getInputsFor(control, Keys);
|
||||
if (list.length > index)
|
||||
{
|
||||
if (list[index] != FlxKey.ESCAPE)
|
||||
input = list[index];
|
||||
else if (list.length > 2)
|
||||
// Escape isn't mappable, show a third option, instead.
|
||||
input = list[2];
|
||||
}
|
||||
|
||||
;
|
||||
super(x, y, getLabel(input), Default, callback);
|
||||
}
|
||||
|
||||
public function getLabel(input:Int)
|
||||
{
|
||||
return input == -1 ? "---" : InputFormatter.format(input, Keys);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import flixel.util.FlxSignal;
|
|||
class MenuTypedList<T:MenuItem> extends FlxTypedGroup<T>
|
||||
{
|
||||
public var selectedIndex(default, null) = 0;
|
||||
public var selectedItem(get, never):T;
|
||||
/** Called when a new item is highlighted */
|
||||
public var onChange(default, null) = new FlxTypedSignal<T->Void>();
|
||||
/** Called when an item is accepted */
|
||||
|
@ -189,6 +190,11 @@ class MenuTypedList<T:MenuItem> extends FlxTypedGroup<T>
|
|||
onChange.removeAll();
|
||||
onAcceptPress.removeAll();
|
||||
}
|
||||
|
||||
inline function get_selectedItem():T
|
||||
{
|
||||
return members[selectedIndex];
|
||||
}
|
||||
}
|
||||
|
||||
class MenuItem extends FlxSprite
|
||||
|
@ -221,8 +227,8 @@ class MenuItem extends FlxSprite
|
|||
|
||||
/**
|
||||
* Calls setData and resets/redraws the state of the item
|
||||
* @param name
|
||||
* @param callback
|
||||
* @param name the label.
|
||||
* @param callback Unchanged if null.
|
||||
*/
|
||||
public function setItem(name:String, ?callback:Void->Void)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@ class OptionsState extends MusicBeatState
|
|||
menuBG.setGraphicSize(Std.int(menuBG.width * 1.1));
|
||||
menuBG.updateHitbox();
|
||||
menuBG.screenCenter();
|
||||
menuBG.scrollFactor.set(0, 0);
|
||||
add(menuBG);
|
||||
|
||||
var options = addPage(Options, new OptionsMenu(false));
|
||||
|
@ -94,6 +95,7 @@ class Page extends FlxGroup
|
|||
public var onExit(default, null) = new FlxSignal();
|
||||
|
||||
public var enabled(default, set) = true;
|
||||
public var canExit = true;
|
||||
|
||||
var controls(get, never):Controls;
|
||||
inline function get_controls() return PlayerSettings.player1.controls;
|
||||
|
@ -120,7 +122,7 @@ class Page extends FlxGroup
|
|||
|
||||
function updateEnabled(elapsed:Float)
|
||||
{
|
||||
if (controls.BACK)
|
||||
if (canExit && controls.BACK)
|
||||
exit();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,13 +17,14 @@ class Prompt extends flixel.FlxSubState
|
|||
public var onNo:Void->Void;
|
||||
public var buttons:TextMenuList;
|
||||
public var field:AtlasText;
|
||||
public var back:FlxSprite;
|
||||
|
||||
var style:ButtonStyle;
|
||||
|
||||
public function new (text:String, style:ButtonStyle = Ok)
|
||||
{
|
||||
this.style = style;
|
||||
super(0xA0000000);
|
||||
super(0x80000000);
|
||||
|
||||
buttons = new TextMenuList(Horizontal);
|
||||
|
||||
|
@ -43,6 +44,21 @@ class Prompt extends flixel.FlxSubState
|
|||
add(buttons);
|
||||
}
|
||||
|
||||
public function createBg(width:Int, height:Int, color = 0xFF808080)
|
||||
{
|
||||
back = new FlxSprite();
|
||||
back.makeGraphic(width, height, color, false, "prompt-bg");
|
||||
back.screenCenter(XY);
|
||||
add(back);
|
||||
members.unshift(members.pop());// bring to front
|
||||
}
|
||||
|
||||
|
||||
public function createBgFromMargin(margin = MARGIN, color = 0xFF808080)
|
||||
{
|
||||
createBg(Std.int(FlxG.width - margin * 2), Std.int(FlxG.height - margin * 2), color);
|
||||
}
|
||||
|
||||
public function setButtons(style:ButtonStyle)
|
||||
{
|
||||
if (this.style != style)
|
||||
|
|
|
@ -39,6 +39,7 @@ class TextTypedMenuItem<T:AtlasText> extends MenuTypedItem<T>
|
|||
if (label != null)
|
||||
{
|
||||
label.text = name;
|
||||
label.alpha = alpha;
|
||||
width = label.width;
|
||||
height = label.height;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue