[client] add screen gamepad
This commit is contained in:
19
WORK.md
19
WORK.md
@@ -1,8 +1,11 @@
|
||||
* [feature] **shovel** bonus with armor bricks
|
||||
* [feature] bonuses in dota/death mod
|
||||
* [feature] tanks and bullets speed balancing
|
||||
* [feature] result frame update (next game select, only human player info)
|
||||
* [feature] network game series
|
||||
* [feature] map packs (create in editor, import in game, save imported in local storage)
|
||||
* [feature] update bots
|
||||
* [feature] improve bonuses system
|
||||
* **shovel** bonus with armor bricks
|
||||
* bonuses in dota/death mod
|
||||
* tanks and bullets speed balancing
|
||||
* result frame update (next game select, only human player info)
|
||||
* network game series
|
||||
* map packs (create in editor, import in game, save imported in local storage)
|
||||
* update bots
|
||||
* improve bonuses system
|
||||
* gamepad support
|
||||
* screen gamepad on mobiles
|
||||
* resize render on mobiles
|
||||
|
||||
@@ -4,6 +4,7 @@ import flash.events.FocusEvent;
|
||||
import flash.events.KeyboardEvent;
|
||||
import flash.Lib;
|
||||
import haxe.Timer;
|
||||
import ru.m.geom.Direction;
|
||||
import ru.m.tankz.control.ActionConfig;
|
||||
import ru.m.tankz.control.Control;
|
||||
import ru.m.tankz.storage.SettingsStorage;
|
||||
@@ -14,7 +15,7 @@ class HumanControl extends Control {
|
||||
@:provide var storage:SettingsStorage;
|
||||
|
||||
private var keyBinding:KeyBinding;
|
||||
private var moveQueue:Array<Int>;
|
||||
private var moveQueue:Array<Direction>;
|
||||
private var shotTimer:Timer;
|
||||
|
||||
public function new(playerId:PlayerId, controlIndex:Int) {
|
||||
@@ -40,34 +41,43 @@ class HumanControl extends Control {
|
||||
}
|
||||
}
|
||||
|
||||
private function onKeyDown(event:KeyboardEvent):Void {
|
||||
if (keyBinding.exists(event.keyCode)) switch (keyBinding.get(event.keyCode)) {
|
||||
public function toggleAction(action:TankAction, on:Bool):Void {
|
||||
switch action {
|
||||
case TankAction.MOVE(direction):
|
||||
if (moveQueue.indexOf(event.keyCode) == -1) {
|
||||
moveQueue.unshift(event.keyCode);
|
||||
updateMove();
|
||||
if (on) {
|
||||
if (moveQueue.indexOf(direction) == -1) {
|
||||
moveQueue.unshift(direction);
|
||||
}
|
||||
} else {
|
||||
moveQueue.remove(direction);
|
||||
}
|
||||
updateMove();
|
||||
case TankAction.SHOT:
|
||||
if (on) {
|
||||
if (shotTimer == null) {
|
||||
shotTimer = new Timer(300);
|
||||
shotTimer.run = shot;
|
||||
shot();
|
||||
}
|
||||
case _:
|
||||
}
|
||||
}
|
||||
|
||||
private function onKeyUp(event:KeyboardEvent):Void {
|
||||
if (keyBinding.exists(event.keyCode)) switch (keyBinding.get(event.keyCode)) {
|
||||
case TankAction.MOVE(direction):
|
||||
moveQueue.remove(event.keyCode);
|
||||
updateMove();
|
||||
case TankAction.SHOT:
|
||||
} else {
|
||||
if (shotTimer != null) {
|
||||
shotTimer.stop();
|
||||
shotTimer = null;
|
||||
}
|
||||
case _:
|
||||
}
|
||||
case TankAction.STOP:
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,11 +90,7 @@ class HumanControl extends Control {
|
||||
if (moveQueue.length == 0) {
|
||||
action(TankAction.STOP);
|
||||
} else {
|
||||
switch (keyBinding.get(moveQueue[0])) {
|
||||
case TankAction.MOVE(direction):
|
||||
action(TankAction.MOVE(direction));
|
||||
case _:
|
||||
}
|
||||
action(TankAction.MOVE(moveQueue[0]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,21 @@ import ru.m.tankz.control.Control.TankAction;
|
||||
|
||||
class SettingsStorage extends SharedObjectStorage {
|
||||
|
||||
public var screenGamepad(get, set):Bool;
|
||||
|
||||
public function new() {
|
||||
super("settings");
|
||||
}
|
||||
|
||||
private function get_screenGamepad():Bool {
|
||||
return read("screenGamepad");
|
||||
}
|
||||
|
||||
private function set_screenGamepad(value:Bool):Bool {
|
||||
write("screenGamepad", value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public function getActionConfig(index:Int):ActionConfig {
|
||||
return exists('action:$index') ? read('action:$index') : getDefaultActionConfig(index);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
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.VGroupView;
|
||||
import ru.m.tankz.game.GameEvent;
|
||||
@@ -10,6 +14,7 @@ import ru.m.tankz.network.NetworkManager;
|
||||
import ru.m.tankz.sound.SoundManager;
|
||||
import ru.m.tankz.storage.GameStorage;
|
||||
import ru.m.tankz.view.game.GameView;
|
||||
import ru.m.tankz.view.GamepadView;
|
||||
|
||||
@:template class GameFrame extends VGroupView implements GameListener {
|
||||
public static inline var ID = "game";
|
||||
@@ -17,6 +22,7 @@ import ru.m.tankz.view.game.GameView;
|
||||
private static inline var TAG = "GameFrame";
|
||||
|
||||
@:view("game") private var gameView(default, null):GameView;
|
||||
@:view private var gamepad(default, null):GamepadView;
|
||||
|
||||
@:provide var network:NetworkManager;
|
||||
@:provide var soundManager:SoundManager;
|
||||
@@ -24,10 +30,12 @@ import ru.m.tankz.view.game.GameView;
|
||||
@:provide var record:GameRecord;
|
||||
@:provide var switcher:FrameSwitcher;
|
||||
@:provide var gameStorage:GameStorage;
|
||||
@:provide var settings:SettingsStorage;
|
||||
|
||||
@:provide var game:IGame;
|
||||
|
||||
public function onShow():Void {
|
||||
gamepad.visible = settings.screenGamepad;
|
||||
gameView.type = game.type;
|
||||
soundManager.config = game.config;
|
||||
gameView.render.config = game.config;
|
||||
@@ -66,4 +74,21 @@ import ru.m.tankz.view.game.GameView;
|
||||
public function close():Void {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
views:
|
||||
- $type: haxework.view.VGroupView
|
||||
skinId: container
|
||||
layout.overflow: true
|
||||
views:
|
||||
- id: game
|
||||
$type: ru.m.tankz.view.game.GameView
|
||||
- id: gamepad
|
||||
$type: ru.m.tankz.view.GamepadView
|
||||
geometry.position: absolute
|
||||
geometry.size.stretch: true
|
||||
+actionSignal: $this:onGamepadAction
|
||||
visible: false
|
||||
|
||||
119
src/client/haxe/ru/m/tankz/view/GamepadView.hx
Normal file
119
src/client/haxe/ru/m/tankz/view/GamepadView.hx
Normal file
@@ -0,0 +1,119 @@
|
||||
package ru.m.tankz.view;
|
||||
|
||||
import flash.display.Graphics;
|
||||
import flash.events.MouseEvent;
|
||||
import haxework.signal.Signal;
|
||||
import haxework.view.skin.ISkin;
|
||||
import haxework.view.SpriteView;
|
||||
import ru.m.geom.Point;
|
||||
import ru.m.geom.Rectangle;
|
||||
|
||||
enum GamepadAction {
|
||||
UP;
|
||||
LEFT;
|
||||
DOWN;
|
||||
RIGHT;
|
||||
BUTTON_1;
|
||||
}
|
||||
|
||||
typedef ActionArea = {
|
||||
var action:GamepadAction;
|
||||
var rect:Rectangle;
|
||||
}
|
||||
|
||||
class GamepadSkin implements ISkin<GamepadView> {
|
||||
|
||||
public var color(default, default):Int;
|
||||
|
||||
public function new(color:Int = 0) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public function draw(view:GamepadView):Void {
|
||||
var graphics:Graphics = view.content.graphics;
|
||||
graphics.clear();
|
||||
graphics.beginFill(0, 0.0);
|
||||
graphics.drawRect(0, 0, view.width, view.height);
|
||||
graphics.endFill();
|
||||
graphics.lineStyle(2, color);
|
||||
graphics.beginFill(color, 0.2);
|
||||
for (area in view.areas) {
|
||||
graphics.drawRect(area.rect.x, area.rect.y, area.rect.width, area.rect.height);
|
||||
}
|
||||
graphics.lineStyle();
|
||||
}
|
||||
}
|
||||
|
||||
class GamepadView extends SpriteView {
|
||||
|
||||
public var actionSignal(default, null):Signal2<GamepadAction, Bool>;
|
||||
|
||||
public var areas(default, null):Array<ActionArea>;
|
||||
public var currentArea(default, null):ActionArea;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
actionSignal = new Signal2();
|
||||
skin = [new GamepadSkin(0x00ff00)];
|
||||
content.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
|
||||
}
|
||||
|
||||
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);
|
||||
if (currentArea != null) {
|
||||
if (!currentArea.rect.contain(point)) {
|
||||
actionSignal.emit(currentArea.action, false);
|
||||
currentArea = null;
|
||||
}
|
||||
}
|
||||
for (area in areas) {
|
||||
if (area.rect.contain(point)) {
|
||||
currentArea = area;
|
||||
actionSignal.emit(currentArea.action, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function onMouseUp(event:MouseEvent):Void {
|
||||
content.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
|
||||
content.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
|
||||
if (currentArea != null) {
|
||||
actionSignal.emit(currentArea.action, false);
|
||||
currentArea = null;
|
||||
}
|
||||
}
|
||||
|
||||
override public function update():Void {
|
||||
super.update();
|
||||
areas = [];
|
||||
var size = Math.min(width, height) / 8;
|
||||
var padding = size / 2;
|
||||
areas.push({
|
||||
action: GamepadAction.UP,
|
||||
rect: new Rectangle(padding + size, height - size * 3 - padding, size, size)
|
||||
});
|
||||
areas.push({
|
||||
action: GamepadAction.LEFT,
|
||||
rect: new Rectangle(padding, height - size * 2 - padding, size, size)
|
||||
});
|
||||
areas.push({
|
||||
action: GamepadAction.DOWN,
|
||||
rect: new Rectangle(padding + size, height - size - padding, size, size)
|
||||
});
|
||||
areas.push({
|
||||
action: GamepadAction.RIGHT,
|
||||
rect: new Rectangle(padding + size * 2, height - size * 2 - padding, size, size)
|
||||
});
|
||||
areas.push({
|
||||
action: GamepadAction.BUTTON_1,
|
||||
rect: new Rectangle(width - size * 1.5 - padding, height - size * 2 - padding, size, size)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,21 @@
|
||||
package ru.m.tankz.view;
|
||||
|
||||
import haxework.view.ToggleButtonView;
|
||||
import haxework.view.VGroupView;
|
||||
import ru.m.tankz.storage.SettingsStorage;
|
||||
|
||||
@:template class SettingsFrame extends VGroupView {
|
||||
public static var ID(default, never):String = "settings";
|
||||
|
||||
@:view("gamepad") private var gamepadButton:ToggleButtonView;
|
||||
|
||||
@:provide private static var settings:SettingsStorage;
|
||||
|
||||
public function onShow():Void {
|
||||
gamepadButton.on = settings.screenGamepad;
|
||||
}
|
||||
|
||||
private function toggleGamepad():Void {
|
||||
gamepadButton.on = settings.screenGamepad = !settings.screenGamepad;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,12 @@ views:
|
||||
- $type: haxework.view.LabelView
|
||||
skinId: text.header
|
||||
text: Settings
|
||||
- id: gamepad
|
||||
$type: haxework.view.ToggleButtonView
|
||||
skinId: button.simple
|
||||
text: Screen Gamepad Disabled
|
||||
onText: Screen Gamepad Enabled
|
||||
+onPress: $code:toggleGamepad()
|
||||
- $type: haxework.view.HGroupView
|
||||
layout.margin: 20
|
||||
views:
|
||||
|
||||
@@ -14,7 +14,6 @@ enum TankAction {
|
||||
}
|
||||
|
||||
class Control {
|
||||
public var type:String;
|
||||
public var playerId(default, null):PlayerId;
|
||||
public var tankId(default, default):Int;
|
||||
private var handler:IGame;
|
||||
|
||||
@@ -29,8 +29,7 @@ import ru.m.tankz.Type;
|
||||
public var engine(default, null):IEngine;
|
||||
public var controlFactory(default, null):IControlFactory;
|
||||
public var pause(default, set):Bool;
|
||||
|
||||
private var controls:Map<String, Control>;
|
||||
public var controls(default, null):Map<String, Control>;
|
||||
|
||||
@:provide var configBundle:IConfigBundle;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package ru.m.tankz.game;
|
||||
|
||||
import haxework.signal.Signal;
|
||||
import ru.m.tankz.config.Config;
|
||||
import ru.m.tankz.control.Control;
|
||||
import ru.m.tankz.control.IControlFactory;
|
||||
import ru.m.tankz.Type;
|
||||
|
||||
@@ -13,6 +14,7 @@ interface IGame extends GameListener {
|
||||
public var state(default, null):GameState;
|
||||
public var controlFactory(default, null):IControlFactory;
|
||||
public var pause(default, set):Bool;
|
||||
public var controls(default, null):Map<String, Control>;
|
||||
|
||||
public var gameEventSignal(default, null):Signal<GameEvent>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user