[client] improve GamepadView
This commit is contained in:
@@ -110,6 +110,10 @@ class AppTheme extends Theme {
|
||||
registerButton("start", "play-circle-solid.svg");
|
||||
registerButton("login", "sign-in-solid.svg");
|
||||
registerButton("logout", "sign-out-solid.svg");
|
||||
|
||||
register(new Style("gamepad", [
|
||||
"skin.color" => colors.active,
|
||||
]));
|
||||
}
|
||||
|
||||
private function registerButton(name:String, resource:String):Void {
|
||||
|
||||
@@ -16,7 +16,7 @@ import ru.m.tankz.sound.SoundManager;
|
||||
import ru.m.tankz.storage.GameStorage;
|
||||
import ru.m.tankz.storage.SettingsStorage;
|
||||
import ru.m.tankz.view.game.GameView;
|
||||
import ru.m.tankz.view.GamepadView;
|
||||
import ru.m.tankz.view.gamepad.GamepadView;
|
||||
|
||||
@:template class GameFrame extends FrameView<GameInit> implements GameListener {
|
||||
public static inline var ID = "game";
|
||||
|
||||
@@ -6,7 +6,7 @@ views:
|
||||
- id: game
|
||||
$type: ru.m.tankz.view.game.GameView
|
||||
- id: gamepad
|
||||
$type: ru.m.tankz.view.GamepadView
|
||||
$type: ru.m.tankz.view.gamepad.GamepadView
|
||||
geometry.position: absolute
|
||||
geometry.stretch: true
|
||||
visible: false
|
||||
|
||||
24
src/client/haxe/ru/m/tankz/view/gamepad/CircleActionArea.hx
Normal file
24
src/client/haxe/ru/m/tankz/view/gamepad/CircleActionArea.hx
Normal file
@@ -0,0 +1,24 @@
|
||||
package ru.m.tankz.view.gamepad;
|
||||
|
||||
import flash.display.Graphics;
|
||||
import ru.m.control.DeviceAction;
|
||||
import ru.m.geom.Circle;
|
||||
import ru.m.geom.Point;
|
||||
|
||||
class CircleActionArea implements IActionArea {
|
||||
public var action(default, null):DeviceAction;
|
||||
public var circle(default, null):Circle;
|
||||
|
||||
public function new(action:DeviceAction, circle:Circle) {
|
||||
this.action = action;
|
||||
this.circle = circle;
|
||||
}
|
||||
|
||||
public function contain(point:Point):Bool {
|
||||
return circle.contain(point);
|
||||
}
|
||||
|
||||
public function draw(graphics:Graphics):Void {
|
||||
graphics.drawCircle(circle.x, circle.y, circle.radius);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package ru.m.tankz.view.gamepad;
|
||||
|
||||
import ru.m.control.DeviceAction;
|
||||
import ru.m.geom.Direction;
|
||||
import ru.m.geom.Rectangle;
|
||||
|
||||
class DefaultActionAreaBuilder implements IActionAreaBuilder {
|
||||
public function new() {
|
||||
}
|
||||
|
||||
public function build(width:Float, height:Float):Array<IActionArea> {
|
||||
var areas:Array<IActionArea> = [];
|
||||
var size = Math.min(width, height) / 7;
|
||||
var padding = size / 2;
|
||||
// top
|
||||
areas.push(new RectangleActionArea(
|
||||
DIRECTION(Direction.TOP),
|
||||
new Rectangle(padding + size, height - size * 3 - padding, size, size)
|
||||
));
|
||||
// left
|
||||
areas.push(new RectangleActionArea(
|
||||
DIRECTION(Direction.LEFT),
|
||||
new Rectangle(padding, height - size * 2 - padding, size, size)
|
||||
));
|
||||
// bottom
|
||||
areas.push(new RectangleActionArea(
|
||||
DIRECTION(Direction.BOTTOM),
|
||||
new Rectangle(padding + size, height - size - padding, size, size)
|
||||
));
|
||||
// right
|
||||
areas.push(new RectangleActionArea(
|
||||
DIRECTION(Direction.RIGHT),
|
||||
new Rectangle(padding + size * 2, height - size * 2 - padding, size, size)
|
||||
));
|
||||
// button
|
||||
areas.push(new RectangleActionArea(
|
||||
KEY(0),
|
||||
new Rectangle(width - size * 1.5 - padding, height - size * 2 - padding, size, size)
|
||||
));
|
||||
return areas;
|
||||
}
|
||||
}
|
||||
29
src/client/haxe/ru/m/tankz/view/gamepad/GamepadSkin.hx
Normal file
29
src/client/haxe/ru/m/tankz/view/gamepad/GamepadSkin.hx
Normal file
@@ -0,0 +1,29 @@
|
||||
package ru.m.tankz.view.gamepad;
|
||||
|
||||
import flash.display.Graphics;
|
||||
import haxework.color.Color;
|
||||
import haxework.view.skin.ISkin;
|
||||
|
||||
@:style class GamepadSkin implements ISkin<GamepadView> {
|
||||
|
||||
@:style(0x00ff00) public var color(default, default):Null<Color>;
|
||||
|
||||
public function new(?color:Color) {
|
||||
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) {
|
||||
area.draw(graphics);
|
||||
}
|
||||
graphics.lineStyle();
|
||||
graphics.endFill();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,14 @@
|
||||
package ru.m.tankz.view;
|
||||
package ru.m.tankz.view.gamepad;
|
||||
|
||||
import flash.display.Graphics;
|
||||
import flash.display.Stage;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.events.TouchEvent;
|
||||
import haxework.color.Color;
|
||||
import haxework.signal.Signal;
|
||||
import haxework.view.skin.ISkin;
|
||||
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.Rectangle;
|
||||
|
||||
typedef ActionArea = {
|
||||
var action:DeviceAction;
|
||||
var rect:Rectangle;
|
||||
}
|
||||
|
||||
@:style class GamepadSkin implements ISkin<GamepadView> {
|
||||
|
||||
@:style(0) public var color(default, default):Null<Color>;
|
||||
|
||||
public function new(?color:Color) {
|
||||
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 implements IControlDevice {
|
||||
public static var ID(default, never):Int = -128;
|
||||
@@ -49,18 +16,21 @@ class GamepadView extends SpriteView implements IControlDevice {
|
||||
public var type(default, null):DeviceType;
|
||||
public var signal(default, null):Signal2<DeviceAction, Bool>;
|
||||
|
||||
public var areas(default, null):Array<ActionArea>;
|
||||
public var currentAreas(default, null):Map<Int, ActionArea>;
|
||||
public var areas(default, null):Array<IActionArea>;
|
||||
public var currentAreas(default, null):Map<Int, IActionArea>;
|
||||
|
||||
private var builder:IActionAreaBuilder;
|
||||
private var stage:Stage;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
style = "gamepad";
|
||||
type = GAMEPAD(ID);
|
||||
builder = new SmartActionAreaBuilder();
|
||||
signal = new Signal2();
|
||||
areas = [];
|
||||
currentAreas = new Map();
|
||||
skin = new GamepadSkin(0x00ff00);
|
||||
skin = new GamepadSkin();
|
||||
content.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
|
||||
content.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
|
||||
}
|
||||
@@ -106,13 +76,13 @@ class GamepadView extends SpriteView implements IControlDevice {
|
||||
private function updateTouch(pointID:Int, point:Point):Void {
|
||||
if (currentAreas.exists(pointID)) {
|
||||
var area = currentAreas[pointID];
|
||||
if (!area.rect.contain(point)) {
|
||||
if (!area.contain(point)) {
|
||||
currentAreas.remove(pointID);
|
||||
signal.emit(area.action, false);
|
||||
}
|
||||
}
|
||||
for (area in areas) {
|
||||
if (area.rect.contain(point)) {
|
||||
if (area.contain(point)) {
|
||||
currentAreas[pointID] = area;
|
||||
signal.emit(area.action, true);
|
||||
break;
|
||||
@@ -129,31 +99,10 @@ class GamepadView extends SpriteView implements IControlDevice {
|
||||
|
||||
override public function update():Void {
|
||||
super.update();
|
||||
areas = [];
|
||||
var size = Math.min(width, height) / 7;
|
||||
var padding = size / 2;
|
||||
areas.push({
|
||||
action: DIRECTION(Direction.TOP),
|
||||
rect: new Rectangle(padding + size, height - size * 3 - padding, size, size)
|
||||
});
|
||||
areas.push({
|
||||
action: DIRECTION(Direction.LEFT),
|
||||
rect: new Rectangle(padding, height - size * 2 - padding, size, size)
|
||||
});
|
||||
areas.push({
|
||||
action: DIRECTION(Direction.BOTTOM),
|
||||
rect: new Rectangle(padding + size, height - size - padding, size, size)
|
||||
});
|
||||
areas.push({
|
||||
action: DIRECTION(Direction.RIGHT),
|
||||
rect: new Rectangle(padding + size * 2, height - size * 2 - padding, size, size)
|
||||
});
|
||||
areas.push({
|
||||
action: KEY(0),
|
||||
rect: new Rectangle(width - size * 1.5 - padding, height - size * 2 - padding, size, size)
|
||||
});
|
||||
areas = builder.build(width, height);
|
||||
}
|
||||
|
||||
|
||||
public function dispose():Void {
|
||||
stage = null;
|
||||
}
|
||||
11
src/client/haxe/ru/m/tankz/view/gamepad/IActionArea.hx
Normal file
11
src/client/haxe/ru/m/tankz/view/gamepad/IActionArea.hx
Normal file
@@ -0,0 +1,11 @@
|
||||
package ru.m.tankz.view.gamepad;
|
||||
|
||||
import flash.display.Graphics;
|
||||
import ru.m.control.DeviceAction;
|
||||
import ru.m.geom.Point;
|
||||
|
||||
interface IActionArea {
|
||||
public var action(default, null):DeviceAction;
|
||||
public function contain(point:Point):Bool;
|
||||
public function draw(graphics:Graphics):Void;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ru.m.tankz.view.gamepad;
|
||||
|
||||
interface IActionAreaBuilder {
|
||||
public function build(width:Float, height:Float):Array<IActionArea>;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package ru.m.tankz.view.gamepad;
|
||||
|
||||
import flash.display.Graphics;
|
||||
import ru.m.control.DeviceAction;
|
||||
import ru.m.geom.Point;
|
||||
import ru.m.geom.Rectangle;
|
||||
|
||||
class RectangleActionArea implements IActionArea {
|
||||
public var action(default, null):DeviceAction;
|
||||
public var rectangle(default, null):Rectangle;
|
||||
|
||||
public function new(action:DeviceAction, rectangle:Rectangle) {
|
||||
this.action = action;
|
||||
this.rectangle = rectangle;
|
||||
}
|
||||
|
||||
public function contain(point:Point):Bool {
|
||||
return rectangle.contain(point);
|
||||
}
|
||||
|
||||
public function draw(graphics:Graphics):Void {
|
||||
graphics.drawRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
|
||||
}
|
||||
}
|
||||
32
src/client/haxe/ru/m/tankz/view/gamepad/RhombusActionArea.hx
Normal file
32
src/client/haxe/ru/m/tankz/view/gamepad/RhombusActionArea.hx
Normal file
@@ -0,0 +1,32 @@
|
||||
package ru.m.tankz.view.gamepad;
|
||||
|
||||
import flash.display.Graphics;
|
||||
import ru.m.control.DeviceAction;
|
||||
import ru.m.geom.Point;
|
||||
import ru.m.geom.Rectangle;
|
||||
|
||||
class RhombusActionArea implements IActionArea {
|
||||
public var action(default, null):DeviceAction;
|
||||
public var rectangle(default, null):Rectangle;
|
||||
|
||||
private var center:Point;
|
||||
private var distance:Float;
|
||||
|
||||
public function new(action:DeviceAction, rectangle:Rectangle) {
|
||||
this.action = action;
|
||||
this.rectangle = rectangle;
|
||||
center = rectangle.center;
|
||||
distance = Math.max(rectangle.width / 2, rectangle.height / 2);
|
||||
}
|
||||
|
||||
public function contain(point:Point):Bool {
|
||||
return Math.abs(point.x - center.x) + Math.abs(point.y - center.y) < distance;
|
||||
}
|
||||
|
||||
public function draw(graphics:Graphics):Void {
|
||||
graphics.moveTo(rectangle.x + rectangle.width / 2, rectangle.top);
|
||||
graphics.lineTo(rectangle.right, rectangle.y + rectangle.height / 2);
|
||||
graphics.lineTo(rectangle.x + rectangle.width / 2, rectangle.bottom);
|
||||
graphics.lineTo(rectangle.left, rectangle.y + rectangle.height / 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package ru.m.tankz.view.gamepad;
|
||||
|
||||
import ru.m.control.DeviceAction;
|
||||
import ru.m.geom.Circle;
|
||||
import ru.m.geom.Direction;
|
||||
import ru.m.geom.Rectangle;
|
||||
|
||||
class SmartActionAreaBuilder implements IActionAreaBuilder {
|
||||
public function new() {
|
||||
}
|
||||
|
||||
public function build(width:Float, height:Float):Array<IActionArea> {
|
||||
var areas:Array<IActionArea> = [];
|
||||
var size = Math.min(width, height) / 6;
|
||||
var padding = size / 2;
|
||||
// top
|
||||
areas.push(new RhombusActionArea(
|
||||
DIRECTION(Direction.TOP),
|
||||
new Rectangle(padding + size * 0.5, height - size * 2 - padding, size, size )
|
||||
));
|
||||
// left
|
||||
areas.push(new RhombusActionArea(
|
||||
DIRECTION(Direction.LEFT),
|
||||
new Rectangle(padding, height - size * 1.5 - padding, size, size)
|
||||
));
|
||||
// bottom
|
||||
areas.push(new RhombusActionArea(
|
||||
DIRECTION(Direction.BOTTOM),
|
||||
new Rectangle(padding + size * 0.5, height - size - padding, size, size)
|
||||
));
|
||||
// right
|
||||
areas.push(new RhombusActionArea(
|
||||
DIRECTION(Direction.RIGHT),
|
||||
new Rectangle(padding + size, height - size * 1.5 - padding, size, size)
|
||||
));
|
||||
areas.push(new CircleActionArea(
|
||||
KEY(0),
|
||||
new Circle(width - size * 1 - padding, height - size * 1 - padding, size / 2)
|
||||
));
|
||||
return areas;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package ru.m.tankz.view.settings;
|
||||
|
||||
import haxework.view.data.DataView;
|
||||
import haxework.view.group.GroupView;
|
||||
import haxework.view.form.LabelView;
|
||||
import haxework.view.group.GroupView;
|
||||
import haxework.view.group.VGroupView;
|
||||
import promhx.Deferred;
|
||||
import promhx.Promise;
|
||||
@@ -11,6 +11,7 @@ import ru.m.control.DeviceType;
|
||||
import ru.m.control.IControlBus;
|
||||
import ru.m.tankz.control.Binding;
|
||||
import ru.m.tankz.storage.SettingsStorage;
|
||||
import ru.m.tankz.view.gamepad.GamepadView;
|
||||
import ru.m.tankz.view.settings.ActionView;
|
||||
|
||||
class BindEditor {
|
||||
|
||||
Reference in New Issue
Block a user