2021-02-15 17:43:51 +00:00
|
|
|
package ui;
|
|
|
|
|
|
|
|
import flixel.util.typeLimit.OneOfTwo;
|
|
|
|
import flixel.math.FlxPoint;
|
|
|
|
import flixel.FlxG;
|
|
|
|
import flixel.effects.FlxFlicker;
|
|
|
|
import flixel.graphics.frames.FlxAtlasFrames;
|
|
|
|
import flixel.group.FlxGroup;
|
|
|
|
import flixel.tweens.FlxEase;
|
|
|
|
import flixel.tweens.FlxTween;
|
|
|
|
import flixel.util.FlxSignal;
|
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
typedef AtlasAsset = OneOfTwo<String, FlxAtlasFrames>;
|
2021-02-15 17:43:51 +00:00
|
|
|
|
|
|
|
class MenuItemList extends MenuTypedItemList<MenuItem>
|
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
public var atlas:FlxAtlasFrames;
|
|
|
|
|
|
|
|
public function new (atlas, navControls:NavControls = Vertical)
|
2021-02-15 17:43:51 +00:00
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
super(navControls);
|
2021-02-15 17:43:51 +00:00
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
if (Std.is(atlas, String))
|
|
|
|
this.atlas = Paths.getSparrowAtlas(cast atlas);
|
|
|
|
else
|
|
|
|
this.atlas = cast atlas;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function createItem(x = 0.0, y = 0.0, name, callback, fireInstantly = false)
|
|
|
|
{
|
|
|
|
var item = new MenuItem(x, y, name, atlas, callback);
|
|
|
|
item.fireInstantly = fireInstantly;
|
|
|
|
return addItem(name, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
override function destroy()
|
|
|
|
{
|
|
|
|
super.destroy();
|
|
|
|
atlas = null;
|
2021-02-15 17:43:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class MenuTypedItemList<T:MenuItem> extends FlxTypedGroup<T>
|
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
public var selectedIndex(default, null) = 0;
|
|
|
|
/** Called when a new item is highlighted */
|
2021-02-15 17:43:51 +00:00
|
|
|
public var onChange(default, null) = new FlxTypedSignal<T->Void>();
|
2021-02-18 19:58:16 +00:00
|
|
|
/** Called when an item is accepted */
|
2021-02-15 17:43:51 +00:00
|
|
|
public var onAcceptPress(default, null) = new FlxTypedSignal<T->Void>();
|
2021-02-18 19:58:16 +00:00
|
|
|
/** The navigation control scheme to use */
|
|
|
|
public var navControls:NavControls;
|
|
|
|
/** Set to false to disable nav control */
|
|
|
|
public var enabled:Bool = true;
|
2021-02-15 17:43:51 +00:00
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
var byName = new Map<String, T>();
|
|
|
|
/** Set to true, internally to disable controls, without affecting vars like `enabled` */
|
|
|
|
var busy:Bool = false;
|
|
|
|
|
|
|
|
public function new (navControls:NavControls = Vertical)
|
2021-02-15 17:43:51 +00:00
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
this.navControls = navControls;
|
2021-02-15 17:43:51 +00:00
|
|
|
super();
|
2021-02-18 19:58:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function addItem(name:String, item:T):T
|
|
|
|
{
|
|
|
|
if (length == selectedIndex)
|
|
|
|
item.select();
|
2021-02-15 17:43:51 +00:00
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
byName[name] = item;
|
|
|
|
return add(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function resetItem(oldName:String, newName:String, ?callback:Void->Void):T
|
|
|
|
{
|
|
|
|
if (!byName.exists(oldName))
|
|
|
|
throw "No item named:" + oldName;
|
|
|
|
|
|
|
|
var item = byName[oldName];
|
|
|
|
byName.remove(oldName);
|
|
|
|
byName[newName] = item;
|
|
|
|
item.setItem(newName, callback);
|
|
|
|
|
|
|
|
return item;
|
2021-02-15 17:43:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override function update(elapsed:Float)
|
|
|
|
{
|
|
|
|
super.update(elapsed);
|
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
if (enabled && !busy)
|
|
|
|
updateControls();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline function updateControls()
|
|
|
|
{
|
2021-02-15 17:43:51 +00:00
|
|
|
var controls = PlayerSettings.player1.controls;
|
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
switch(navControls)
|
|
|
|
{
|
|
|
|
case Vertical:
|
|
|
|
{
|
|
|
|
if (controls.UP_P ) prev();
|
|
|
|
if (controls.DOWN_P) next();
|
|
|
|
}
|
|
|
|
case Horizontal:
|
|
|
|
{
|
|
|
|
if (controls.LEFT_P ) prev();
|
|
|
|
if (controls.RIGHT_P) next();
|
|
|
|
}
|
|
|
|
case Both:
|
|
|
|
{
|
|
|
|
if (controls.LEFT_P || controls.UP_P ) prev();
|
|
|
|
if (controls.RIGHT_P || controls.DOWN_P) next();
|
|
|
|
}
|
|
|
|
}
|
2021-02-20 02:11:33 +00:00
|
|
|
|
|
|
|
//Todo: bypass popup blocker on firefox
|
2021-02-15 17:43:51 +00:00
|
|
|
if (controls.ACCEPT)
|
|
|
|
accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function accept()
|
|
|
|
{
|
|
|
|
var selected = members[selectedIndex];
|
2021-02-15 22:04:08 +00:00
|
|
|
onAcceptPress.dispatch(selected);
|
|
|
|
|
2021-02-15 17:43:51 +00:00
|
|
|
if (selected.fireInstantly)
|
|
|
|
selected.callback();
|
|
|
|
else
|
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
busy = true;
|
2021-02-15 17:43:51 +00:00
|
|
|
FlxG.sound.play(Paths.sound('confirmMenu'));
|
|
|
|
FlxFlicker.flicker(selected, 1, 0.06, true, false, function(_)
|
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
busy = false;
|
2021-02-15 17:43:51 +00:00
|
|
|
selected.callback();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline function prev() changeItem(-1);
|
|
|
|
inline function next() changeItem(1);
|
|
|
|
|
|
|
|
function changeItem(amount:Int)
|
|
|
|
{
|
|
|
|
FlxG.sound.play(Paths.sound('scrollMenu'));
|
2021-02-18 19:58:16 +00:00
|
|
|
var index = selectedIndex + amount;
|
|
|
|
if (index >= length)
|
|
|
|
index = 0;
|
|
|
|
else if (index < 0)
|
|
|
|
index = length - 1;
|
|
|
|
|
|
|
|
selectItem(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function selectItem(index:Int)
|
|
|
|
{
|
2021-02-15 17:43:51 +00:00
|
|
|
members[selectedIndex].idle();
|
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
selectedIndex = index;
|
2021-02-15 17:43:51 +00:00
|
|
|
|
|
|
|
var selected = members[selectedIndex];
|
|
|
|
selected.select();
|
|
|
|
onChange.dispatch(selected);
|
|
|
|
}
|
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
public function getItem(name:String)
|
|
|
|
{
|
|
|
|
return byName[name];
|
|
|
|
}
|
|
|
|
|
2021-02-15 17:43:51 +00:00
|
|
|
override function destroy()
|
|
|
|
{
|
|
|
|
super.destroy();
|
2021-02-18 19:58:16 +00:00
|
|
|
byName.clear();
|
2021-02-15 17:43:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class MenuItem extends flixel.FlxSprite
|
|
|
|
{
|
|
|
|
public var callback:Void->Void;
|
|
|
|
/**
|
|
|
|
* Set to true for things like opening URLs otherwise, it may it get blocked.
|
|
|
|
*/
|
|
|
|
public var fireInstantly = false;
|
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
public function new (x = 0.0, y = 0.0, name, tex, callback)
|
2021-02-15 17:43:51 +00:00
|
|
|
{
|
|
|
|
super(x, y);
|
|
|
|
|
|
|
|
frames = tex;
|
|
|
|
setItem(name, callback);
|
2021-02-18 19:58:16 +00:00
|
|
|
antialiasing = true;
|
2021-02-15 17:43:51 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
public function setItem(name:String, ?callback:Void->Void)
|
2021-02-15 17:43:51 +00:00
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
if (callback != null)
|
|
|
|
this.callback = callback;
|
|
|
|
|
|
|
|
var selected = animation.curAnim != null && animation.curAnim.name == "selected";
|
2021-02-15 17:43:51 +00:00
|
|
|
|
|
|
|
animation.addByPrefix('idle', '$name basic', 24);
|
|
|
|
animation.addByPrefix('selected', '$name white', 24);
|
|
|
|
idle();
|
2021-02-18 19:58:16 +00:00
|
|
|
if (selected)
|
|
|
|
select();
|
2021-02-15 17:43:51 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 19:58:16 +00:00
|
|
|
function changeAnim(anim:String)
|
2021-02-15 17:43:51 +00:00
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
animation.play(anim);
|
2021-02-15 17:43:51 +00:00
|
|
|
updateHitbox();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function idle()
|
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
changeAnim('idle');
|
2021-02-15 17:43:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function select()
|
|
|
|
{
|
2021-02-18 19:58:16 +00:00
|
|
|
changeAnim('selected');
|
2021-02-15 17:43:51 +00:00
|
|
|
}
|
2021-02-18 19:58:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enum NavControls
|
|
|
|
{
|
|
|
|
Horizontal;
|
|
|
|
Vertical;
|
|
|
|
Both;
|
2021-02-15 17:43:51 +00:00
|
|
|
}
|