[client] add ControlBus
This commit is contained in:
30
src/client/haxe/ru/m/control/ControlBus.hx
Normal file
30
src/client/haxe/ru/m/control/ControlBus.hx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package ru.m.control;
|
||||||
|
|
||||||
|
import ru.m.control.IControlBus;
|
||||||
|
import haxework.signal.Signal;
|
||||||
|
|
||||||
|
class ControlBus implements IControlBus {
|
||||||
|
|
||||||
|
public var signal(default, null):Signal3<DeviceType, DeviceAction, Bool>;
|
||||||
|
private var connections:Map<DeviceType, DeviceAction->Bool->Void>;
|
||||||
|
|
||||||
|
public function new() {
|
||||||
|
signal = new Signal3();
|
||||||
|
connections = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connect(device:IControlDevice):Void {
|
||||||
|
var connector = function(action:DeviceAction, on:Bool):Void {
|
||||||
|
signal.emit(device.type, action, on);
|
||||||
|
}
|
||||||
|
connections.set(device.type, connector);
|
||||||
|
device.signal.connect(connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disconnect(device:IControlDevice):Void {
|
||||||
|
if (connections.exists(device.type)) {
|
||||||
|
device.signal.disconnect(connections.get(device.type));
|
||||||
|
connections.remove(device.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/client/haxe/ru/m/control/DeviceAction.hx
Normal file
8
src/client/haxe/ru/m/control/DeviceAction.hx
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.m.control;
|
||||||
|
|
||||||
|
import ru.m.geom.Direction;
|
||||||
|
|
||||||
|
enum DeviceAction {
|
||||||
|
DIRECTION(direction:Direction);
|
||||||
|
KEY(code:Int);
|
||||||
|
}
|
||||||
7
src/client/haxe/ru/m/control/DeviceType.hx
Normal file
7
src/client/haxe/ru/m/control/DeviceType.hx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package ru.m.control;
|
||||||
|
|
||||||
|
enum DeviceType {
|
||||||
|
NONE;
|
||||||
|
KEYBOARD;
|
||||||
|
GAMEPAD(id:Int);
|
||||||
|
}
|
||||||
10
src/client/haxe/ru/m/control/IControlBus.hx
Normal file
10
src/client/haxe/ru/m/control/IControlBus.hx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package ru.m.control;
|
||||||
|
|
||||||
|
import haxework.signal.Signal;
|
||||||
|
|
||||||
|
interface IControlBus {
|
||||||
|
public var signal(default, null):Signal3<DeviceType, DeviceAction, Bool>;
|
||||||
|
|
||||||
|
public function connect(device:IControlDevice):Void;
|
||||||
|
public function disconnect(device:IControlDevice):Void;
|
||||||
|
}
|
||||||
10
src/client/haxe/ru/m/control/IControlDevice.hx
Normal file
10
src/client/haxe/ru/m/control/IControlDevice.hx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package ru.m.control;
|
||||||
|
|
||||||
|
import haxework.signal.Signal;
|
||||||
|
|
||||||
|
interface IControlDevice {
|
||||||
|
public var type(default, null):DeviceType;
|
||||||
|
public var signal(default, null):Signal2<DeviceAction, Bool>;
|
||||||
|
|
||||||
|
public function dispose():Void;
|
||||||
|
}
|
||||||
38
src/client/haxe/ru/m/control/KeyboardDevice.hx
Normal file
38
src/client/haxe/ru/m/control/KeyboardDevice.hx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package ru.m.control;
|
||||||
|
|
||||||
|
import flash.display.Stage;
|
||||||
|
import flash.events.KeyboardEvent;
|
||||||
|
import haxework.signal.Signal;
|
||||||
|
import ru.m.control.DeviceAction;
|
||||||
|
|
||||||
|
class KeyboardDevice implements IControlDevice {
|
||||||
|
|
||||||
|
public var type(default, null):DeviceType;
|
||||||
|
public var signal(default, null):Signal2<DeviceAction, Bool>;
|
||||||
|
|
||||||
|
private var stage:Stage;
|
||||||
|
|
||||||
|
public function new(stage:Stage) {
|
||||||
|
this.stage = stage;
|
||||||
|
type = DeviceType.KEYBOARD;
|
||||||
|
signal = new Signal2();
|
||||||
|
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
|
||||||
|
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onKeyDown(event:KeyboardEvent):Void {
|
||||||
|
signal.emit(KEY(event.keyCode), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onKeyUp(event:KeyboardEvent):Void {
|
||||||
|
signal.emit(KEY(event.keyCode), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dispose():Void {
|
||||||
|
if (stage != null) {
|
||||||
|
stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
|
||||||
|
stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
||||||
|
stage = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
package ru.m.tankz;
|
package ru.m.tankz;
|
||||||
|
|
||||||
|
import flash.Lib;
|
||||||
|
import ru.m.control.KeyboardDevice;
|
||||||
|
import ru.m.control.ControlBus;
|
||||||
|
import ru.m.control.IControlBus;
|
||||||
import lime.ui.Joystick;
|
import lime.ui.Joystick;
|
||||||
import lime.ui.Gamepad;
|
import lime.ui.Gamepad;
|
||||||
import haxework.animate.FadeAnimate;
|
import haxework.animate.FadeAnimate;
|
||||||
@@ -34,6 +38,7 @@ class Init {
|
|||||||
@:provide static var networkManager:NetworkManager;
|
@:provide static var networkManager:NetworkManager;
|
||||||
@:provide static var popupManager:PopupManager;
|
@:provide static var popupManager:PopupManager;
|
||||||
@:provide static var connection:IConnection<Request, Response>;
|
@:provide static var connection:IConnection<Request, Response>;
|
||||||
|
@:provide static var bus:IControlBus;
|
||||||
|
|
||||||
private static function buildConnection():IConnection<Request, Response> {
|
private static function buildConnection():IConnection<Request, Response> {
|
||||||
var host:String = CompilationOption.get("host");
|
var host:String = CompilationOption.get("host");
|
||||||
@@ -65,6 +70,9 @@ class Init {
|
|||||||
connection = buildConnection();
|
connection = buildConnection();
|
||||||
networkManager = new NetworkManager();
|
networkManager = new NetworkManager();
|
||||||
|
|
||||||
|
bus = new ControlBus();
|
||||||
|
bus.connect(new KeyboardDevice(Lib.current.stage));
|
||||||
|
|
||||||
for (device in Gamepad.devices) {
|
for (device in Gamepad.devices) {
|
||||||
trace('gamepad', device);
|
trace('gamepad', device);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,18 @@
|
|||||||
package ru.m.tankz.control;
|
package ru.m.tankz.control;
|
||||||
|
|
||||||
import ru.m.tankz.control.Control.TankAction;
|
import ru.m.control.DeviceAction;
|
||||||
|
import ru.m.control.DeviceType;
|
||||||
|
import ru.m.tankz.control.Control;
|
||||||
|
|
||||||
typedef ActionItem = {
|
typedef Binding = Map<DeviceAction, TankAction>;
|
||||||
public var action:TankAction;
|
|
||||||
public var key:Int;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef KeyBinding = Map<Int, TankAction>;
|
|
||||||
|
|
||||||
class ActionConfig {
|
class ActionConfig {
|
||||||
|
|
||||||
public var data(default, null):Array<ActionItem>;
|
public var device(default, null):DeviceType;
|
||||||
|
public var binding(default, null):Binding;
|
||||||
|
|
||||||
public function new(data:Array<ActionItem>) {
|
public function new(device:DeviceType = null, binding:Binding = null) {
|
||||||
this.data = data;
|
this.device = device != null ? device : NONE;
|
||||||
}
|
this.binding = binding != null ? binding : new Map();
|
||||||
|
|
||||||
public function asKeyBinding():KeyBinding {
|
|
||||||
var result = new KeyBinding();
|
|
||||||
for (item in data) {
|
|
||||||
result[item.key] = item.action;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,54 @@
|
|||||||
package ru.m.tankz.control;
|
package ru.m.tankz.control;
|
||||||
|
|
||||||
|
import haxe.EnumTools.EnumValueTools;
|
||||||
import flash.events.FocusEvent;
|
import flash.events.FocusEvent;
|
||||||
import flash.events.KeyboardEvent;
|
|
||||||
import flash.Lib;
|
|
||||||
import haxe.Timer;
|
import haxe.Timer;
|
||||||
|
import ru.m.control.DeviceAction;
|
||||||
|
import ru.m.control.DeviceType;
|
||||||
|
import ru.m.control.IControlBus;
|
||||||
import ru.m.geom.Direction;
|
import ru.m.geom.Direction;
|
||||||
import ru.m.tankz.control.ActionConfig;
|
|
||||||
import ru.m.tankz.control.Control;
|
import ru.m.tankz.control.Control;
|
||||||
import ru.m.tankz.storage.SettingsStorage;
|
import ru.m.tankz.storage.SettingsStorage;
|
||||||
import ru.m.tankz.Type;
|
import ru.m.tankz.Type;
|
||||||
|
|
||||||
class HumanControl extends Control {
|
class HumanControl extends Control {
|
||||||
|
|
||||||
@:provide var storage:SettingsStorage;
|
@:provide static var storage:SettingsStorage;
|
||||||
|
@:provide static var bus:IControlBus;
|
||||||
|
|
||||||
|
private var config:ActionConfig;
|
||||||
|
|
||||||
private var keyBinding:KeyBinding;
|
|
||||||
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);
|
||||||
this.keyBinding = storage.getActionConfig(controlIndex).asKeyBinding();
|
config = storage.getActionConfig(controlIndex);
|
||||||
|
trace(controlIndex, config.device, config.binding);
|
||||||
moveQueue = [];
|
moveQueue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function onDeviceAction(device:DeviceType, action:DeviceAction, on:Bool):Void {
|
||||||
|
if (EnumValueTools.equals(config.device, device)) {
|
||||||
|
switch action {
|
||||||
|
case DIRECTION(direction):
|
||||||
|
toggleAction(MOVE(direction), on);
|
||||||
|
case any:
|
||||||
|
if (config.binding.exists(any)) {
|
||||||
|
toggleAction(config.binding.get(any), on);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override public function start():Void {
|
override public function start():Void {
|
||||||
super.start();
|
super.start();
|
||||||
Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
|
bus.signal.connect(onDeviceAction);
|
||||||
Lib.current.stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override public function stop():Void {
|
override public function stop():Void {
|
||||||
super.stop();
|
super.stop();
|
||||||
Lib.current.stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
|
bus.signal.disconnect(onDeviceAction);
|
||||||
Lib.current.stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
|
||||||
moveQueue = [];
|
moveQueue = [];
|
||||||
if (shotTimer != null) {
|
if (shotTimer != null) {
|
||||||
shotTimer.stop();
|
shotTimer.stop();
|
||||||
@@ -69,18 +84,6 @@ class HumanControl extends Control {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function onKeyDown(event:KeyboardEvent):Void {
|
|
||||||
if (keyBinding.exists(event.keyCode)) {
|
|
||||||
toggleAction(keyBinding.get(event.keyCode), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function onKeyUp(event:KeyboardEvent):Void {
|
|
||||||
if (keyBinding.exists(event.keyCode)) {
|
|
||||||
toggleAction(keyBinding.get(event.keyCode), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function onFocusOut(event:FocusEvent):Void {
|
private function onFocusOut(event:FocusEvent):Void {
|
||||||
moveQueue = [];
|
moveQueue = [];
|
||||||
updateMove();
|
updateMove();
|
||||||
@@ -88,13 +91,13 @@ class HumanControl extends Control {
|
|||||||
|
|
||||||
private function updateMove():Void {
|
private function updateMove():Void {
|
||||||
if (moveQueue.length == 0) {
|
if (moveQueue.length == 0) {
|
||||||
action(TankAction.STOP);
|
action(STOP);
|
||||||
} else {
|
} else {
|
||||||
action(TankAction.MOVE(moveQueue[0]));
|
action(MOVE(moveQueue[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function shot():Void {
|
private function shot():Void {
|
||||||
action(TankAction.SHOT);
|
action(SHOT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package ru.m.tankz.storage;
|
|||||||
import flash.ui.Keyboard;
|
import flash.ui.Keyboard;
|
||||||
import haxework.storage.SharedObjectStorage;
|
import haxework.storage.SharedObjectStorage;
|
||||||
import haxework.utils.ObjectUtil;
|
import haxework.utils.ObjectUtil;
|
||||||
|
import ru.m.control.DeviceAction;
|
||||||
|
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.ActionConfig;
|
||||||
import ru.m.tankz.control.Control.TankAction;
|
import ru.m.tankz.control.Control.TankAction;
|
||||||
@@ -12,7 +14,7 @@ class SettingsStorage extends SharedObjectStorage {
|
|||||||
public var screenGamepad(get, set):Bool;
|
public var screenGamepad(get, set):Bool;
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
super("settings");
|
super("settings-2");
|
||||||
}
|
}
|
||||||
|
|
||||||
private function get_screenGamepad():Bool {
|
private function get_screenGamepad():Bool {
|
||||||
@@ -37,27 +39,37 @@ class SettingsStorage extends SharedObjectStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static var defaults:Map<Int, ActionConfig> = [
|
private static var defaults:Map<Int, ActionConfig> = [
|
||||||
0 => new ActionConfig([
|
0 => new ActionConfig(KEYBOARD, [
|
||||||
{action:TankAction.MOVE(Direction.TOP), key:Keyboard.W},
|
KEY(Keyboard.W) => MOVE(Direction.TOP),
|
||||||
{action:TankAction.MOVE(Direction.LEFT), key:Keyboard.A},
|
KEY(Keyboard.A) => MOVE(Direction.LEFT),
|
||||||
{action:TankAction.MOVE(Direction.BOTTOM), key:Keyboard.S},
|
KEY(Keyboard.S) => MOVE(Direction.BOTTOM),
|
||||||
{action:TankAction.MOVE(Direction.RIGHT), key:Keyboard.D},
|
KEY(Keyboard.D) => MOVE(Direction.RIGHT),
|
||||||
{action:TankAction.SHOT, key:Keyboard.SPACE},
|
KEY(Keyboard.SPACE) => SHOT,
|
||||||
]),
|
]),
|
||||||
1 => new ActionConfig([
|
1 => new ActionConfig(KEYBOARD, [
|
||||||
{action:TankAction.MOVE(Direction.TOP), key:Keyboard.UP},
|
KEY(Keyboard.UP) => MOVE(Direction.TOP),
|
||||||
{action:TankAction.MOVE(Direction.LEFT), key:Keyboard.LEFT},
|
KEY(Keyboard.LEFT) => MOVE(Direction.LEFT),
|
||||||
{action:TankAction.MOVE(Direction.BOTTOM), key:Keyboard.DOWN},
|
KEY(Keyboard.DOWN) => MOVE(Direction.BOTTOM),
|
||||||
{action:TankAction.MOVE(Direction.RIGHT), key:Keyboard.RIGHT},
|
KEY(Keyboard.RIGHT) => MOVE(Direction.RIGHT),
|
||||||
{action:TankAction.SHOT, key:Keyboard.NUMPAD_0},
|
KEY(Keyboard.NUMPAD_0) => SHOT,
|
||||||
]),
|
]),
|
||||||
];
|
];
|
||||||
|
|
||||||
private static var empty:ActionConfig = new ActionConfig([
|
private static var empty:ActionConfig = new ActionConfig(NONE, [
|
||||||
{action:TankAction.MOVE(Direction.TOP), key:-1},
|
KEY(-1) => MOVE(Direction.TOP),
|
||||||
{action:TankAction.MOVE(Direction.LEFT), key:-1},
|
KEY(-1) => MOVE(Direction.LEFT),
|
||||||
{action:TankAction.MOVE(Direction.BOTTOM), key:-1},
|
KEY(-1) => MOVE(Direction.BOTTOM),
|
||||||
{action:TankAction.MOVE(Direction.RIGHT), key:-1},
|
KEY(-1) => MOVE(Direction.RIGHT),
|
||||||
{action:TankAction.SHOT, key:-1},
|
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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
package ru.m.tankz.view;
|
package ru.m.tankz.view;
|
||||||
|
|
||||||
import ru.m.tankz.storage.SettingsStorage;
|
|
||||||
import ru.m.tankz.control.Control.TankAction;
|
|
||||||
import ru.m.geom.Direction;
|
|
||||||
import ru.m.tankz.control.HumanControl;
|
|
||||||
import haxework.view.frame.FrameSwitcher;
|
import haxework.view.frame.FrameSwitcher;
|
||||||
import haxework.view.VGroupView;
|
import haxework.view.VGroupView;
|
||||||
|
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;
|
||||||
import ru.m.tankz.game.IGame;
|
import ru.m.tankz.game.IGame;
|
||||||
@@ -13,6 +10,7 @@ import ru.m.tankz.game.record.GameRecord;
|
|||||||
import ru.m.tankz.network.NetworkManager;
|
import ru.m.tankz.network.NetworkManager;
|
||||||
import ru.m.tankz.sound.SoundManager;
|
import ru.m.tankz.sound.SoundManager;
|
||||||
import ru.m.tankz.storage.GameStorage;
|
import ru.m.tankz.storage.GameStorage;
|
||||||
|
import ru.m.tankz.storage.SettingsStorage;
|
||||||
import ru.m.tankz.view.game.GameView;
|
import ru.m.tankz.view.game.GameView;
|
||||||
import ru.m.tankz.view.GamepadView;
|
import ru.m.tankz.view.GamepadView;
|
||||||
|
|
||||||
@@ -33,9 +31,11 @@ import ru.m.tankz.view.GamepadView;
|
|||||||
@:provide var settings:SettingsStorage;
|
@:provide var settings:SettingsStorage;
|
||||||
|
|
||||||
@:provide var game:IGame;
|
@:provide var game:IGame;
|
||||||
|
@:provide static var bus:IControlBus;
|
||||||
|
|
||||||
public function onShow():Void {
|
public function onShow():Void {
|
||||||
gamepad.visible = settings.screenGamepad;
|
gamepad.visible = settings.screenGamepad;
|
||||||
|
bus.connect(gamepad);
|
||||||
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;
|
||||||
@@ -58,7 +58,7 @@ import ru.m.tankz.view.GamepadView;
|
|||||||
|
|
||||||
public function onGameEvent(event:GameEvent):Void {
|
public function onGameEvent(event:GameEvent):Void {
|
||||||
switch event {
|
switch event {
|
||||||
case GameEvent.COMPLETE(state, winner):
|
case COMPLETE(state, winner):
|
||||||
this.state = state;
|
this.state = state;
|
||||||
stop();
|
stop();
|
||||||
switcher.change(ResultFrame.ID);
|
switcher.change(ResultFrame.ID);
|
||||||
@@ -67,6 +67,7 @@ import ru.m.tankz.view.GamepadView;
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onHide():Void {
|
public function onHide():Void {
|
||||||
|
bus.disconnect(gamepad);
|
||||||
stop();
|
stop();
|
||||||
soundManager.stopAll();
|
soundManager.stopAll();
|
||||||
}
|
}
|
||||||
@@ -74,21 +75,4 @@ import ru.m.tankz.view.GamepadView;
|
|||||||
public function close():Void {
|
public function close():Void {
|
||||||
switcher.change(LevelFrame.ID);
|
switcher.change(LevelFrame.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function onGamepadAction(action:GamepadAction, on:Bool):Void {
|
|
||||||
// ToDo:
|
|
||||||
for (control in game.controls) {
|
|
||||||
if (Std.is(control, HumanControl)) {
|
|
||||||
var tankAction:TankAction = switch action {
|
|
||||||
case UP: MOVE(Direction.TOP);
|
|
||||||
case LEFT: MOVE(Direction.LEFT);
|
|
||||||
case DOWN: MOVE(Direction.BOTTOM);
|
|
||||||
case RIGHT: MOVE(Direction.RIGHT);
|
|
||||||
case BUTTON_1: SHOT;
|
|
||||||
}
|
|
||||||
cast(control, HumanControl).toggleAction(tankAction, on);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,5 +10,4 @@ views:
|
|||||||
$type: ru.m.tankz.view.GamepadView
|
$type: ru.m.tankz.view.GamepadView
|
||||||
geometry.position: absolute
|
geometry.position: absolute
|
||||||
geometry.size.stretch: true
|
geometry.size.stretch: true
|
||||||
+actionSignal: $this:onGamepadAction
|
|
||||||
visible: false
|
visible: false
|
||||||
|
|||||||
@@ -1,23 +1,20 @@
|
|||||||
package ru.m.tankz.view;
|
package ru.m.tankz.view;
|
||||||
|
|
||||||
|
import flash.events.MouseEvent;
|
||||||
import flash.display.Graphics;
|
import flash.display.Graphics;
|
||||||
import flash.events.TouchEvent;
|
import flash.events.TouchEvent;
|
||||||
import haxework.signal.Signal;
|
import haxework.signal.Signal;
|
||||||
import haxework.view.skin.ISkin;
|
import haxework.view.skin.ISkin;
|
||||||
import haxework.view.SpriteView;
|
import haxework.view.SpriteView;
|
||||||
|
import ru.m.control.DeviceAction;
|
||||||
|
import ru.m.control.DeviceType;
|
||||||
|
import ru.m.control.IControlDevice;
|
||||||
|
import ru.m.geom.Direction;
|
||||||
import ru.m.geom.Point;
|
import ru.m.geom.Point;
|
||||||
import ru.m.geom.Rectangle;
|
import ru.m.geom.Rectangle;
|
||||||
|
|
||||||
enum GamepadAction {
|
|
||||||
UP;
|
|
||||||
LEFT;
|
|
||||||
DOWN;
|
|
||||||
RIGHT;
|
|
||||||
BUTTON_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef ActionArea = {
|
typedef ActionArea = {
|
||||||
var action:GamepadAction;
|
var action:DeviceAction;
|
||||||
var rect:Rectangle;
|
var rect:Rectangle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,22 +41,47 @@ class GamepadSkin implements ISkin<GamepadView> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GamepadView extends SpriteView {
|
class GamepadView extends SpriteView implements IControlDevice {
|
||||||
|
public static var ID:Int = -128;
|
||||||
|
|
||||||
public var actionSignal(default, null):Signal2<GamepadAction, Bool>;
|
public var type(default, null):DeviceType;
|
||||||
|
public var signal(default, null):Signal2<DeviceAction, Bool>;
|
||||||
|
|
||||||
public var areas(default, null):Array<ActionArea>;
|
public var areas(default, null):Array<ActionArea>;
|
||||||
public var currentAreas(default, null):Map<Int, ActionArea>;
|
public var currentAreas(default, null):Map<Int, ActionArea>;
|
||||||
|
|
||||||
|
private static function touchSupport():Bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
super();
|
super();
|
||||||
|
type = GAMEPAD(ID);
|
||||||
|
signal = new Signal2();
|
||||||
areas = [];
|
areas = [];
|
||||||
currentAreas = new Map();
|
currentAreas = new Map();
|
||||||
actionSignal = new Signal2();
|
|
||||||
skin = [new GamepadSkin(0x00ff00)];
|
skin = [new GamepadSkin(0x00ff00)];
|
||||||
|
content.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
|
||||||
content.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
|
content.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function onMouseDown(event:MouseEvent):Void {
|
||||||
|
onMouseMove(event);
|
||||||
|
content.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
|
||||||
|
content.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onMouseMove(event:MouseEvent):Void {
|
||||||
|
var point = new Point(event.localX, event.localY);
|
||||||
|
updateTouch(-1, point);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function onMouseUp(event:MouseEvent):Void {
|
||||||
|
endTouch(-1);
|
||||||
|
content.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
|
||||||
|
content.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
private function onTouchBegin(event:TouchEvent):Void {
|
private function onTouchBegin(event:TouchEvent):Void {
|
||||||
onTouchMove(event);
|
onTouchMove(event);
|
||||||
content.stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
|
content.stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
|
||||||
@@ -68,30 +90,38 @@ class GamepadView extends SpriteView {
|
|||||||
|
|
||||||
private function onTouchMove(event:TouchEvent):Void {
|
private function onTouchMove(event:TouchEvent):Void {
|
||||||
var point = new Point(event.localX, event.localY);
|
var point = new Point(event.localX, event.localY);
|
||||||
if (currentAreas.exists(event.touchPointID)) {
|
updateTouch(event.touchPointID, point);
|
||||||
var area = currentAreas[event.touchPointID];
|
}
|
||||||
|
|
||||||
|
private function onTouchEnd(event:TouchEvent):Void {
|
||||||
|
endTouch(event.touchPointID);
|
||||||
|
if (Lambda.count(currentAreas) == 0) {
|
||||||
|
content.stage.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
|
||||||
|
content.stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateTouch(pointID:Int, point:Point):Void {
|
||||||
|
if (currentAreas.exists(pointID)) {
|
||||||
|
var area = currentAreas[pointID];
|
||||||
if (!area.rect.contain(point)) {
|
if (!area.rect.contain(point)) {
|
||||||
currentAreas.remove(event.touchPointID);
|
currentAreas.remove(pointID);
|
||||||
actionSignal.emit(area.action, false);
|
signal.emit(area.action, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (area in areas) {
|
for (area in areas) {
|
||||||
if (area.rect.contain(point)) {
|
if (area.rect.contain(point)) {
|
||||||
currentAreas[event.touchPointID] = area;
|
currentAreas[pointID] = area;
|
||||||
actionSignal.emit(area.action, true);
|
signal.emit(area.action, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function onTouchEnd(event:TouchEvent):Void {
|
private function endTouch(pointID:Int):Void {
|
||||||
if (currentAreas.exists(event.touchPointID)) {
|
if (currentAreas.exists(pointID)) {
|
||||||
actionSignal.emit(currentAreas[event.touchPointID].action, false);
|
signal.emit(currentAreas[pointID].action, false);
|
||||||
currentAreas.remove(event.touchPointID);
|
currentAreas.remove(pointID);
|
||||||
}
|
|
||||||
if (Lambda.count(currentAreas) == 0) {
|
|
||||||
content.stage.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
|
|
||||||
content.stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,24 +131,26 @@ class GamepadView extends SpriteView {
|
|||||||
var size = Math.min(width, height) / 7;
|
var size = Math.min(width, height) / 7;
|
||||||
var padding = size / 2;
|
var padding = size / 2;
|
||||||
areas.push({
|
areas.push({
|
||||||
action: GamepadAction.UP,
|
action: DIRECTION(Direction.TOP),
|
||||||
rect: new Rectangle(padding + size, height - size * 3 - padding, size, size)
|
rect: new Rectangle(padding + size, height - size * 3 - padding, size, size)
|
||||||
});
|
});
|
||||||
areas.push({
|
areas.push({
|
||||||
action: GamepadAction.LEFT,
|
action: DIRECTION(Direction.LEFT),
|
||||||
rect: new Rectangle(padding, height - size * 2 - padding, size, size)
|
rect: new Rectangle(padding, height - size * 2 - padding, size, size)
|
||||||
});
|
});
|
||||||
areas.push({
|
areas.push({
|
||||||
action: GamepadAction.DOWN,
|
action: DIRECTION(Direction.BOTTOM),
|
||||||
rect: new Rectangle(padding + size, height - size - padding, size, size)
|
rect: new Rectangle(padding + size, height - size - padding, size, size)
|
||||||
});
|
});
|
||||||
areas.push({
|
areas.push({
|
||||||
action: GamepadAction.RIGHT,
|
action: DIRECTION(Direction.RIGHT),
|
||||||
rect: new Rectangle(padding + size * 2, height - size * 2 - padding, size, size)
|
rect: new Rectangle(padding + size * 2, height - size * 2 - padding, size, size)
|
||||||
});
|
});
|
||||||
areas.push({
|
areas.push({
|
||||||
action: GamepadAction.BUTTON_1,
|
action: KEY(0),
|
||||||
rect: new Rectangle(width - size * 1.5 - padding, height - size * 2 - padding, size, size)
|
rect: new Rectangle(width - size * 1.5 - padding, height - size * 2 - padding, size, size)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function dispose():Void {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,5 +17,10 @@ import ru.m.tankz.storage.SettingsStorage;
|
|||||||
|
|
||||||
private function toggleGamepad():Void {
|
private function toggleGamepad():Void {
|
||||||
gamepadButton.on = settings.screenGamepad = !settings.screenGamepad;
|
gamepadButton.on = settings.screenGamepad = !settings.screenGamepad;
|
||||||
|
if (settings.screenGamepad) {
|
||||||
|
settings.setActionConffig(0, SettingsStorage.gamepadConfig(GamepadView.ID));
|
||||||
|
} else {
|
||||||
|
settings.setActionConffig(0, SettingsStorage.getDefaultActionConfig(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,19 @@ package ru.m.tankz.view.settings;
|
|||||||
|
|
||||||
import haxework.view.HGroupView;
|
import haxework.view.HGroupView;
|
||||||
import haxework.view.LabelView;
|
import haxework.view.LabelView;
|
||||||
import haxework.view.list.ListView.IListItemView;
|
import haxework.view.list.ListView;
|
||||||
import openfl.Assets;
|
import openfl.Assets;
|
||||||
import openfl.events.KeyboardEvent;
|
import openfl.events.KeyboardEvent;
|
||||||
import promhx.Deferred;
|
import promhx.Deferred;
|
||||||
import promhx.Promise;
|
import promhx.Promise;
|
||||||
import ru.m.tankz.control.ActionConfig;
|
import ru.m.control.DeviceAction;
|
||||||
import ru.m.tankz.control.Control;
|
import ru.m.tankz.control.Control;
|
||||||
|
|
||||||
|
typedef ActionItem = {
|
||||||
|
var tankAction:TankAction;
|
||||||
|
var deviceAction:DeviceAction;
|
||||||
|
}
|
||||||
|
|
||||||
class KeyboardMap {
|
class KeyboardMap {
|
||||||
|
|
||||||
private var data:Map<Int, String>;
|
private var data:Map<Int, String>;
|
||||||
@@ -26,9 +31,9 @@ class KeyboardMap {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var instance: KeyboardMap;
|
private static var instance:KeyboardMap;
|
||||||
|
|
||||||
public static function getName(key: Int): String {
|
public static function getName(key:Int):String {
|
||||||
if (instance == null) instance = new KeyboardMap();
|
if (instance == null) instance = new KeyboardMap();
|
||||||
return key == -1 ? "(NONE)" : instance.data.exists(key) ? instance.data.get(key) : Std.string(key);
|
return key == -1 ? "(NONE)" : instance.data.exists(key) ? instance.data.get(key) : Std.string(key);
|
||||||
}
|
}
|
||||||
@@ -42,9 +47,9 @@ class KeyboardMap {
|
|||||||
@: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<Int>;
|
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";
|
||||||
case TankAction.MOVE(d): 'MOVE_$d';
|
case TankAction.MOVE(d): 'MOVE_$d';
|
||||||
@@ -52,18 +57,21 @@ class KeyboardMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function keyLabel(key: Int): String {
|
private static function keyLabel(action:DeviceAction):String {
|
||||||
return KeyboardMap.getName(key);
|
return switch action {
|
||||||
|
case KEY(code): KeyboardMap.getName(code);
|
||||||
|
case DIRECTION(direction): Std.string(direction);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private function set_data(value:ActionItem):ActionItem {
|
private function set_data(value:ActionItem):ActionItem {
|
||||||
data = value;
|
data = value;
|
||||||
action.text = actionLabel(data.action);
|
action.text = actionLabel(data.tankAction);
|
||||||
key.text = keyLabel(data.key);
|
key.text = keyLabel(data.deviceAction);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function edit():Promise<Int> {
|
public function edit():Promise<DeviceAction> {
|
||||||
action.skinId = key.skinId = "text.box.active";
|
action.skinId = key.skinId = "text.box.active";
|
||||||
toRedraw();
|
toRedraw();
|
||||||
editDeferred = new Deferred();
|
editDeferred = new Deferred();
|
||||||
@@ -71,13 +79,13 @@ class KeyboardMap {
|
|||||||
return editDeferred.promise();
|
return editDeferred.promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function onKeyDown(event: KeyboardEvent):Void {
|
private function onKeyDown(event:KeyboardEvent):Void {
|
||||||
content.stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
|
content.stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
|
||||||
action.skinId = key.skinId = "text.box";
|
action.skinId = key.skinId = "text.box";
|
||||||
toRedraw();
|
toRedraw();
|
||||||
data.key = event.keyCode;
|
data.deviceAction = KEY(event.keyCode);
|
||||||
key.text = keyLabel(data.key);
|
key.text = keyLabel(data.deviceAction);
|
||||||
editDeferred.resolve(data.key);
|
editDeferred.resolve(data.deviceAction);
|
||||||
editDeferred = null;
|
editDeferred = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ import haxework.view.DataView;
|
|||||||
import haxework.view.LabelView;
|
import haxework.view.LabelView;
|
||||||
import haxework.view.VGroupView;
|
import haxework.view.VGroupView;
|
||||||
import promhx.Promise;
|
import promhx.Promise;
|
||||||
|
import ru.m.control.DeviceAction;
|
||||||
|
import ru.m.control.DeviceType;
|
||||||
import ru.m.tankz.control.ActionConfig;
|
import ru.m.tankz.control.ActionConfig;
|
||||||
import ru.m.tankz.storage.SettingsStorage;
|
import ru.m.tankz.storage.SettingsStorage;
|
||||||
|
import ru.m.tankz.view.settings.ActionView;
|
||||||
|
|
||||||
@:template class SettingsEditor extends VGroupView {
|
@:template class SettingsEditor extends VGroupView {
|
||||||
|
|
||||||
@@ -14,12 +17,12 @@ import ru.m.tankz.storage.SettingsStorage;
|
|||||||
@:view var label:LabelView;
|
@:view var label:LabelView;
|
||||||
@:view var list:DataView<ActionItem, ActionView>;
|
@:view var list:DataView<ActionItem, ActionView>;
|
||||||
|
|
||||||
@:provide var storage:SettingsStorage;
|
@:provide static var storage:SettingsStorage;
|
||||||
|
|
||||||
private function set_controlIndex(value: Int): Int {
|
private function set_controlIndex(value: Int): Int {
|
||||||
this.controlIndex = value;
|
this.controlIndex = value;
|
||||||
label.text = 'Player ${controlIndex+1}';
|
label.text = 'Player ${controlIndex+1}';
|
||||||
list.data = storage.getActionConfig(controlIndex).data;
|
list.data = bindingToArray(storage.getActionConfig(controlIndex).binding);
|
||||||
return this.controlIndex;
|
return this.controlIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,21 +34,21 @@ import ru.m.tankz.storage.SettingsStorage;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function onItemSelect(index:Int, value:ActionItem, view:ActionView):Void {
|
private function onItemSelect(index:Int, value:ActionItem, view:ActionView):Void {
|
||||||
view.edit();
|
view.edit().then(function(_) save());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function change():Void {
|
private function change():Void {
|
||||||
var p: Promise<Int> = Promise.promise(0);
|
var p:Promise<DeviceAction> = Promise.promise(null);
|
||||||
for (view in list.views) {
|
for (view in list.views) {
|
||||||
var v: ActionView = cast view;
|
var v: ActionView = cast view;
|
||||||
p = p.pipe(function(_):Promise<Int> return v.edit());
|
p = p.pipe(function(_) return v.edit());
|
||||||
}
|
}
|
||||||
p.then(function(_) save());
|
p.then(function(_) save());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function clear():Void {
|
private function clear():Void {
|
||||||
for (item in list.data) {
|
for (item in list.data) {
|
||||||
item.key = -1;
|
item.deviceAction = KEY(-1);
|
||||||
}
|
}
|
||||||
list.data = list.data;
|
list.data = list.data;
|
||||||
list.toUpdate();
|
list.toUpdate();
|
||||||
@@ -53,12 +56,28 @@ import ru.m.tankz.storage.SettingsStorage;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function reset():Void {
|
private function reset():Void {
|
||||||
list.data = SettingsStorage.getDefaultActionConfig(controlIndex).data;
|
list.data = bindingToArray(SettingsStorage.getDefaultActionConfig(controlIndex).binding);
|
||||||
list.toUpdate();
|
list.toUpdate();
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function save():Void {
|
private function save():Void {
|
||||||
storage.setActionConffig(controlIndex, new ActionConfig(list.data));
|
storage.setActionConffig(controlIndex, new ActionConfig(KEYBOARD, arrayToBinding(list.data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function bindingToArray(binding:Binding):Array<ActionItem> {
|
||||||
|
var result:Array<ActionItem> = [];
|
||||||
|
for (deviceAction in binding.keys()) {
|
||||||
|
result.push({deviceAction: deviceAction, tankAction: binding.get(deviceAction)});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function arrayToBinding(array:Array<ActionItem>):Binding {
|
||||||
|
var result = new Binding();
|
||||||
|
for (item in array) {
|
||||||
|
result.set(item.deviceAction, item.tankAction);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user