[client] control settings rework

This commit is contained in:
2019-06-19 22:35:11 +03:00
parent 948648b313
commit db0adbac30
10 changed files with 179 additions and 170 deletions

View File

@@ -1,18 +0,0 @@
package ru.m.tankz.control;
import ru.m.control.DeviceAction;
import ru.m.control.DeviceType;
import ru.m.tankz.control.Control;
typedef Binding = Map<DeviceAction, TankAction>;
class ActionConfig {
public var device(default, null):DeviceType;
public var binding(default, null):Binding;
public function new(device:DeviceType = null, binding:Binding = null) {
this.device = device != null ? device : NONE;
this.binding = binding != null ? binding : new Map();
}
}

View File

@@ -0,0 +1,12 @@
package ru.m.tankz.control;
import ru.m.control.DeviceAction;
import ru.m.control.DeviceType;
import ru.m.tankz.control.Control;
typedef BindAction = {
var device:DeviceType;
var action:DeviceAction;
}
typedef Binding = Map<TankAction, BindAction>;

View File

@@ -1,6 +1,5 @@
package ru.m.tankz.control; package ru.m.tankz.control;
import haxe.EnumTools.EnumValueTools;
import flash.events.FocusEvent; import flash.events.FocusEvent;
import haxe.Timer; import haxe.Timer;
import ru.m.control.DeviceAction; import ru.m.control.DeviceAction;
@@ -16,27 +15,28 @@ class HumanControl extends Control {
@:provide static var storage:SettingsStorage; @:provide static var storage:SettingsStorage;
@:provide static var bus:IControlBus; @:provide static var bus:IControlBus;
private var config:ActionConfig; private var binding:Map<DeviceType, Map<DeviceAction, TankAction>>;
private var moveQueue:Array<Direction>; private var moveQueue:Array<Direction>;
private var shotTimer:Timer; private var shotTimer:Timer;
public function new(playerId:PlayerId, controlIndex:Int) { public function new(playerId:PlayerId, controlIndex:Int) {
super(playerId); super(playerId);
config = storage.getActionConfig(controlIndex); var config = storage.getBinding(controlIndex);
binding = new Map();
for (action in config.keys()) {
var bind = config.get(action);
if (!binding.exists(bind.device)) {
binding.set(bind.device, new Map());
}
binding.get(bind.device).set(bind.action, action);
}
moveQueue = []; moveQueue = [];
} }
private function onDeviceAction(device:DeviceType, action:DeviceAction, on:Bool):Void { private function onDeviceAction(device:DeviceType, action:DeviceAction, on:Bool):Void {
if (EnumValueTools.equals(config.device, device)) { if (binding.exists(device) && binding[device].exists(action)) {
switch action { toggleAction(binding[device][action], on);
case DIRECTION(direction):
toggleAction(MOVE(direction), on);
case any:
if (config.binding.exists(any)) {
toggleAction(config.binding.get(any), on);
}
}
} }
} }

View File

@@ -6,59 +6,59 @@ import haxework.utils.ObjectUtil;
import ru.m.control.DeviceAction; import ru.m.control.DeviceAction;
import ru.m.control.DeviceType; import ru.m.control.DeviceType;
import ru.m.geom.Direction; import ru.m.geom.Direction;
import ru.m.tankz.control.ActionConfig; import ru.m.tankz.control.Binding;
import ru.m.tankz.control.Control.TankAction; import ru.m.tankz.control.Control;
class SettingsStorage extends SharedObjectStorage { class SettingsStorage extends SharedObjectStorage {
public function new() { public function new() {
super("settings-2"); super("settings-3");
} }
public function getActionConfig(index:Int):ActionConfig { public function getBinding(index:Int):Binding {
return exists('action:$index') ? read('action:$index') : getDefaultActionConfig(index); return exists('action:$index') ? read('action:$index') : getDefaultBinding(index);
} }
public function setActionConffig(index:Int, value:ActionConfig) { public function saveBinding(index:Int, value:Binding) {
write('action:$index', value); write('action:$index', value);
} }
public static function getDefaultActionConfig(index:Int):ActionConfig { public static function getDefaultBinding(index:Int):Binding {
return ObjectUtil.clone(defaults.exists(index) ? defaults.get(index) : empty); return ObjectUtil.clone(defaults.exists(index) ? defaults.get(index) : defaults.get(-1));
} }
private static var defaults:Map<Int, ActionConfig> = [ public static function buildGamepadBinding(id:Int):Binding {
0 => new ActionConfig(KEYBOARD, [ var device = GAMEPAD(id);
KEY(Keyboard.W) => MOVE(Direction.TOP), return [
KEY(Keyboard.A) => MOVE(Direction.LEFT), MOVE(Direction.TOP) => {device: device, action: DIRECTION(Direction.TOP)},
KEY(Keyboard.S) => MOVE(Direction.BOTTOM), MOVE(Direction.LEFT) => {device: device, action: DIRECTION(Direction.LEFT)},
KEY(Keyboard.D) => MOVE(Direction.RIGHT), MOVE(Direction.BOTTOM) => {device: device, action: DIRECTION(Direction.BOTTOM)},
KEY(Keyboard.SPACE) => SHOT, MOVE(Direction.RIGHT) => {device: device, action: DIRECTION(Direction.RIGHT)},
]), SHOT => {device: device, action: KEY(0)},
1 => new ActionConfig(KEYBOARD, [
KEY(Keyboard.UP) => MOVE(Direction.TOP),
KEY(Keyboard.LEFT) => MOVE(Direction.LEFT),
KEY(Keyboard.DOWN) => MOVE(Direction.BOTTOM),
KEY(Keyboard.RIGHT) => MOVE(Direction.RIGHT),
KEY(Keyboard.NUMPAD_0) => SHOT,
]),
]; ];
private static var empty:ActionConfig = new ActionConfig(NONE, [
KEY(-1) => MOVE(Direction.TOP),
KEY(-1) => MOVE(Direction.LEFT),
KEY(-1) => MOVE(Direction.BOTTOM),
KEY(-1) => MOVE(Direction.RIGHT),
KEY(-1) => SHOT,
]);
public static function gamepadConfig(id:Int):ActionConfig {
return new ActionConfig(GAMEPAD(id), [
DIRECTION(Direction.TOP) => MOVE(Direction.TOP),
DIRECTION(Direction.LEFT) => MOVE(Direction.LEFT),
DIRECTION(Direction.BOTTOM) => MOVE(Direction.BOTTOM),
DIRECTION(Direction.RIGHT) => MOVE(Direction.RIGHT),
KEY(0) => SHOT,
]);
} }
private static var defaults:Map<Int, Binding> = [
-1 => [
MOVE(Direction.TOP) => null,
MOVE(Direction.LEFT) => null,
MOVE(Direction.BOTTOM) => null,
MOVE(Direction.RIGHT) => null,
SHOT => null,
],
0 => [
MOVE(Direction.TOP) => {device: KEYBOARD, action: KEY(Keyboard.W)},
MOVE(Direction.LEFT) => {device: KEYBOARD, action: KEY(Keyboard.A)},
MOVE(Direction.BOTTOM) => {device: KEYBOARD, action: KEY(Keyboard.S)},
MOVE(Direction.RIGHT) => {device: KEYBOARD, action: KEY(Keyboard.D)},
SHOT => {device: KEYBOARD, action: KEY(Keyboard.SPACE)},
],
1 => [
MOVE(Direction.TOP) => {device: KEYBOARD, action: KEY(Keyboard.UP)},
MOVE(Direction.LEFT) => {device: KEYBOARD, action: KEY(Keyboard.LEFT)},
MOVE(Direction.BOTTOM) => {device: KEYBOARD, action: KEY(Keyboard.DOWN)},
MOVE(Direction.RIGHT) => {device: KEYBOARD, action: KEY(Keyboard.RIGHT)},
SHOT => {device: KEYBOARD, action: KEY(Keyboard.NUMPAD_0)},
],
];
} }

View File

@@ -1,8 +1,8 @@
package ru.m.tankz.view; package ru.m.tankz.view;
import ru.m.control.DeviceType;
import haxework.view.frame.FrameSwitcher; import haxework.view.frame.FrameSwitcher;
import haxework.view.VGroupView; import haxework.view.VGroupView;
import ru.m.control.DeviceType;
import ru.m.control.IControlBus; import ru.m.control.IControlBus;
import ru.m.tankz.game.GameEvent; import ru.m.tankz.game.GameEvent;
import ru.m.tankz.game.GameState; import ru.m.tankz.game.GameState;
@@ -42,13 +42,15 @@ import ru.m.tankz.view.GamepadView;
gamepad.visible = false; gamepad.visible = false;
// ToDo: // ToDo:
for (i in 0...1) { for (i in 0...1) {
switch settings.getActionConfig(i).device { for (bind in settings.getBinding(i)) {
switch bind.device {
case GAMEPAD(GamepadView.ID): case GAMEPAD(GamepadView.ID):
gamepad.visible = true; gamepad.visible = true;
break; break;
case _: case _:
} }
} }
}
gameView.type = game.type; gameView.type = game.type;
soundManager.config = game.config; soundManager.config = game.config;
gameView.render.config = game.config; gameView.render.config = game.config;

View File

@@ -66,7 +66,7 @@ class GamepadView extends SpriteView implements IControlDevice {
private function onMouseDown(event:MouseEvent):Void { private function onMouseDown(event:MouseEvent):Void {
onMouseMove(event); onMouseMove(event);
stage = event.relatedObject.stage; stage = content.stage;
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
} }
@@ -84,7 +84,7 @@ class GamepadView extends SpriteView implements IControlDevice {
private function onTouchBegin(event:TouchEvent):Void { private function onTouchBegin(event:TouchEvent):Void {
onTouchMove(event); onTouchMove(event);
stage = event.relatedObject.stage; stage = content.stage;
stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove); stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd); stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
} }

View File

@@ -4,15 +4,13 @@ import haxework.view.HGroupView;
import haxework.view.LabelView; import haxework.view.LabelView;
import haxework.view.list.ListView; import haxework.view.list.ListView;
import openfl.Assets; import openfl.Assets;
import openfl.events.KeyboardEvent;
import promhx.Deferred;
import promhx.Promise;
import ru.m.control.DeviceAction; import ru.m.control.DeviceAction;
import ru.m.tankz.control.Binding;
import ru.m.tankz.control.Control; import ru.m.tankz.control.Control;
typedef ActionItem = { typedef ActionItem = {
var tankAction:TankAction; var action:TankAction;
var deviceAction:DeviceAction; var bind:BindAction;
} }
class KeyboardMap { class KeyboardMap {
@@ -44,11 +42,11 @@ class KeyboardMap {
public var item_index(default, default):Int; public var item_index(default, default):Int;
public var data(default, set):ActionItem; public var data(default, set):ActionItem;
public var edit(default, set):Bool;
@:view var action(default, null):LabelView; @:view var action(default, null):LabelView;
@:view var key(default, null):LabelView; @:view var key(default, null):LabelView;
private var editDeferred:Deferred<DeviceAction>;
private static function actionLabel(action:TankAction):String { private static function actionLabel(action:TankAction):String {
return switch (action) { return switch (action) {
case TankAction.SHOT: "SHOT"; case TankAction.SHOT: "SHOT";
@@ -57,8 +55,8 @@ class KeyboardMap {
} }
} }
private static function keyLabel(action:DeviceAction):String { private static function bindLabel(bind:BindAction):String {
return switch action { return bind == null ? "(NONE)" : Std.string(bind.device) + " " + switch bind.action {
case KEY(code): KeyboardMap.getName(code); case KEY(code): KeyboardMap.getName(code);
case DIRECTION(direction): Std.string(direction); case DIRECTION(direction): Std.string(direction);
}; };
@@ -66,26 +64,16 @@ class KeyboardMap {
private function set_data(value:ActionItem):ActionItem { private function set_data(value:ActionItem):ActionItem {
data = value; data = value;
action.text = actionLabel(data.tankAction); action.text = actionLabel(data.action);
key.text = keyLabel(data.deviceAction); key.text = bindLabel(data.bind);
return data; return data;
} }
public function edit():Promise<DeviceAction> { private function set_edit(value:Bool):Bool {
action.skinId = key.skinId = "text.box.active"; if (edit != value) {
toRedraw(); edit = value;
editDeferred = new Deferred(); action.skinId = key.skinId = edit ? "text.box.active" : "text.box";
content.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
return editDeferred.promise();
} }
return edit;
private function onKeyDown(event:KeyboardEvent):Void {
content.stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
action.skinId = key.skinId = "text.box";
toRedraw();
data.deviceAction = KEY(event.keyCode);
key.text = keyLabel(data.deviceAction);
editDeferred.resolve(data.deviceAction);
editDeferred = null;
} }
} }

View File

@@ -4,9 +4,9 @@ layout.margin: 5
views: views:
- id: action - id: action
$type: haxework.view.LabelView $type: haxework.view.LabelView
geometry.size.fixed: [200, 38] geometry.size.fixed: [180, 38]
skinId: text.box skinId: text.box
- id: key - id: key
$type: haxework.view.LabelView $type: haxework.view.LabelView
geometry.size.fixed: [200, 38] geometry.size.fixed: [250, 38]
skinId: text.box skinId: text.box

View File

@@ -1,19 +1,67 @@
package ru.m.tankz.view.settings; package ru.m.tankz.view.settings;
import haxe.EnumTools.EnumValueTools;
import haxework.view.ButtonGroup;
import haxework.view.DataView; import haxework.view.DataView;
import haxework.view.GroupView; import haxework.view.GroupView;
import haxework.view.LabelView; import haxework.view.LabelView;
import haxework.view.VGroupView; import haxework.view.VGroupView;
import promhx.Deferred;
import promhx.Promise; import promhx.Promise;
import ru.m.control.DeviceAction; import ru.m.control.DeviceAction;
import ru.m.control.DeviceType; import ru.m.control.DeviceType;
import ru.m.control.IControlBus; import ru.m.control.IControlBus;
import ru.m.tankz.control.ActionConfig; import ru.m.tankz.control.Binding;
import ru.m.tankz.storage.SettingsStorage; import ru.m.tankz.storage.SettingsStorage;
import ru.m.tankz.view.settings.ActionView; import ru.m.tankz.view.settings.ActionView;
class BindEditor {
private var editViews:Array<ActionView>;
@:provide static var bus:IControlBus;
private var def:Deferred<Bool>;
public function new() {
editViews = [];
bus.signal.connect(onBusAction);
}
private function onBusAction(device:DeviceType, action:DeviceAction, on:Bool):Void {
if (on && editViews.length > 0) {
var view = editViews.shift();
view.edit = false;
view.data.bind = {device: device, action: action};
view.data = view.data;
if (editViews.length > 0) {
editViews[0].edit = true;
} else {
def.resolve(true);
}
}
}
public function push(views:Array<ActionView>):Promise<Bool> {
for (view in editViews) {
view.edit = false;
}
editViews = views.slice(0);
if (editViews.length > 0) {
editViews[0].edit = true;
}
def = new Deferred();
return def.promise();
}
public static var i(get, null):BindEditor;
private static function get_i():BindEditor {
if (i == null) {
i = new BindEditor();
}
return i;
}
}
@:template class SettingsEditor extends VGroupView { @:template class SettingsEditor extends VGroupView {
public var controlIndex(default, set): Int; public var controlIndex(default, set): Int;
@@ -21,22 +69,14 @@ import ru.m.tankz.view.settings.ActionView;
@:view var label:LabelView; @:view var label:LabelView;
@:view var list:DataView<ActionItem, ActionView>; @:view var list:DataView<ActionItem, ActionView>;
@:view var panel:GroupView; @:view var panel:GroupView;
@:view var device:ButtonGroup<DeviceType>;
@:provide static var storage:SettingsStorage; @:provide static var storage:SettingsStorage;
@:provide static var bus:IControlBus; @:provide static var bus:IControlBus;
public function init() {
bus.devicesSignal.connect(function(devices) refresh());
}
private function refresh():Void { private function refresh():Void {
label.text = 'Player ${controlIndex+1}'; label.text = 'Player ${controlIndex+1}';
var config = storage.getActionConfig(controlIndex); var binding = storage.getBinding(controlIndex);
list.data = bindingToArray(config.binding); list.data = bindingToArray(binding);
device.data = bus.devices.map(function(device) return device.type);
device.selected = config.device;
panel.visible = list.visible = EnumValueTools.equals(config.device, KEYBOARD);
} }
private function set_controlIndex(value: Int): Int { private function set_controlIndex(value: Int): Int {
@@ -45,16 +85,6 @@ import ru.m.tankz.view.settings.ActionView;
return this.controlIndex; return this.controlIndex;
} }
private function onDeviceSelect(value:DeviceType):Void {
var config = switch value {
case GAMEPAD(id): SettingsStorage.gamepadConfig(id);
case KEYBOARD | NONE: SettingsStorage.getDefaultActionConfig(controlIndex);
}
panel.visible = list.visible = EnumValueTools.equals(config.device, KEYBOARD);
storage.setActionConffig(controlIndex, config);
refresh();
}
private function viewFactory(index:Int, value:ActionItem) { private function viewFactory(index:Int, value:ActionItem) {
var view = new ActionView(); var view = new ActionView();
view.item_index = index; view.item_index = index;
@@ -63,41 +93,39 @@ import ru.m.tankz.view.settings.ActionView;
} }
private function onItemSelect(index:Int, value:ActionItem, view:ActionView):Void { private function onItemSelect(index:Int, value:ActionItem, view:ActionView):Void {
view.edit().then(function(_) save()); BindEditor.i.push([view]).then(function(_) save());
} }
private function change():Void { private function screen():Void {
var p:Promise<DeviceAction> = Promise.promise(null); list.data = bindingToArray(SettingsStorage.buildGamepadBinding(GamepadView.ID));
for (view in list.views) {
var v: ActionView = cast view;
p = p.pipe(function(_) return v.edit());
}
p.then(function(_) save());
}
private function clear():Void {
for (item in list.data) {
item.deviceAction = KEY(-1);
}
list.data = list.data;
list.toUpdate(); list.toUpdate();
save(); save();
} }
private function reset():Void { private function change():Void {
list.data = bindingToArray(SettingsStorage.getDefaultActionConfig(controlIndex).binding); BindEditor.i.push(list.dataViews).then(function(_) save());
}
private function clear():Void {
list.data = bindingToArray(SettingsStorage.getDefaultBinding(-1));
list.toUpdate();
save();
}
private function default_():Void {
list.data = bindingToArray(SettingsStorage.getDefaultBinding(controlIndex));
list.toUpdate(); list.toUpdate();
save(); save();
} }
private function save():Void { private function save():Void {
storage.setActionConffig(controlIndex, new ActionConfig(KEYBOARD, arrayToBinding(list.data))); storage.saveBinding(controlIndex, arrayToBinding(list.data));
} }
private static function bindingToArray(binding:Binding):Array<ActionItem> { private static function bindingToArray(binding:Binding):Array<ActionItem> {
var result:Array<ActionItem> = []; var result:Array<ActionItem> = [];
for (deviceAction in binding.keys()) { for (action in binding.keys()) {
result.push({deviceAction: deviceAction, tankAction: binding.get(deviceAction)}); result.push({action: action, bind: binding.get(action)});
} }
return result; return result;
} }
@@ -105,7 +133,7 @@ import ru.m.tankz.view.settings.ActionView;
private static function arrayToBinding(array:Array<ActionItem>):Binding { private static function arrayToBinding(array:Array<ActionItem>):Binding {
var result = new Binding(); var result = new Binding();
for (item in array) { for (item in array) {
result.set(item.deviceAction, item.tankAction); result.set(item.action, item.bind);
} }
return result; return result;
} }

View File

@@ -5,33 +5,30 @@ views:
- id: label - id: label
$type: haxework.view.LabelView $type: haxework.view.LabelView
skinId: text skinId: text
- id: device - id: panel
$type: haxework.view.ButtonGroup $type: haxework.view.GroupView
geometry.size.width: 100%
layout: layout:
$type: haxework.view.layout.TailLayout $type: haxework.view.layout.TailLayout
margin: 3 rowSize: 2
buttonSkinId: button.simple margin: 10
+onDataSelect: $this:onDeviceSelect geometry.size.width: 100%
- id: panel
$type: haxework.view.HGroupView
layout.margin: 10
views: views:
- id: change - $type: haxework.view.ButtonView
$type: haxework.view.ButtonView +onPress: $code:screen()
skinId: button.simple
text: Screen
- $type: haxework.view.ButtonView
+onPress: $code:change() +onPress: $code:change()
skinId: button.simple skinId: button.simple
text: Change text: Change
- id: clear - $type: haxework.view.ButtonView
$type: haxework.view.ButtonView
+onPress: $code:clear() +onPress: $code:clear()
skinId: button.simple skinId: button.simple
text: Clear text: Clear
- id: reset - $type: haxework.view.ButtonView
$type: haxework.view.ButtonView +onPress: $code:default_()
+onPress: $code:reset()
skinId: button.simple skinId: button.simple
text: Reset text: Default
- id: list - id: list
$type: haxework.view.DataView $type: haxework.view.DataView
layout: layout: