add rebind key prompt

This commit is contained in:
George FunBook 2021-03-16 09:56:08 -05:00
parent 9ffa28dd21
commit 9c1866dbdb
7 changed files with 200 additions and 49 deletions

View file

@ -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):

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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)
{

View file

@ -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();
}

View file

@ -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)

View file

@ -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;
}