Add touch joystick movement
This commit is contained in:
parent
23fa7646d6
commit
8b49b44ebf
7 changed files with 161 additions and 95 deletions
|
|
@ -0,0 +1,108 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import {
|
||||
CommandGenerator,
|
||||
SecondaryActionCommand,
|
||||
TernaryActionCommand,
|
||||
MoveActionCommand,
|
||||
last,
|
||||
} from 'shared';
|
||||
import { Game } from '../../game';
|
||||
import { OptionsHandler } from '../../options-handler';
|
||||
|
||||
export class TouchJoystickListener extends CommandGenerator {
|
||||
private joystick: HTMLElement;
|
||||
private joystickButton: HTMLElement;
|
||||
|
||||
private isJoystickActive = false;
|
||||
private touchStartPosition!: vec2;
|
||||
|
||||
constructor(
|
||||
target: HTMLElement,
|
||||
private overlay: HTMLElement,
|
||||
private readonly game: Game,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.joystick = document.createElement('div');
|
||||
this.joystick.className = 'joystick';
|
||||
this.joystickButton = document.createElement('div');
|
||||
this.joystick.appendChild(this.joystickButton);
|
||||
|
||||
target.addEventListener('touchstart', (event: TouchEvent) => {
|
||||
event.preventDefault();
|
||||
if (this.isJoystickActive) {
|
||||
const center = vec2.fromValues(
|
||||
last(event.touches)!.clientX,
|
||||
last(event.touches)!.clientY,
|
||||
);
|
||||
this.sendCommandToSubcribers(
|
||||
new SecondaryActionCommand(this.game.displayToWorldCoordinates(center)),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
target.addEventListener('touchmove', (event: TouchEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (!this.isJoystickActive) {
|
||||
this.isJoystickActive = true;
|
||||
this.overlay.appendChild(this.joystick);
|
||||
this.touchStartPosition = vec2.fromValues(
|
||||
event.touches[0].clientX,
|
||||
event.touches[0].clientY,
|
||||
);
|
||||
this.joystickButton.style.transform = `translateX(-50%) translateY(-50%)`;
|
||||
this.joystick.style.transform = `translateX(${this.touchStartPosition.x}px) translateY(${this.touchStartPosition.y}px) translateX(-50%) translateY(-50%)`;
|
||||
}
|
||||
|
||||
const touchPosition = vec2.fromValues(
|
||||
event.touches[0].clientX,
|
||||
event.touches[0].clientY,
|
||||
);
|
||||
|
||||
const movement = vec2.subtract(
|
||||
vec2.create(),
|
||||
touchPosition,
|
||||
this.touchStartPosition,
|
||||
);
|
||||
|
||||
vec2.scale(movement, movement, 1 / 3);
|
||||
const length = vec2.length(movement);
|
||||
const maxLength = 20;
|
||||
vec2.scale(movement, movement, Math.min(1, maxLength / length));
|
||||
this.joystickButton.style.transform = `translateX(${movement.x}px) translateY(${movement.y}px) translateX(-50%) translateY(-50%)`;
|
||||
|
||||
vec2.set(movement, movement.x, -movement.y);
|
||||
if (vec2.squaredLength(movement) > 0) {
|
||||
vec2.normalize(movement, movement);
|
||||
|
||||
this.sendCommandToSubcribers(
|
||||
new MoveActionCommand(movement, OptionsHandler.options.relativeMovementEnabled),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
target.addEventListener('touchend', (event: TouchEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (!this.isJoystickActive) {
|
||||
const center = vec2.fromValues(
|
||||
event.changedTouches[0].clientX,
|
||||
event.changedTouches[0].clientY,
|
||||
);
|
||||
this.sendCommandToSubcribers(
|
||||
new SecondaryActionCommand(this.game.displayToWorldCoordinates(center)),
|
||||
);
|
||||
} else if (event.touches.length === 0) {
|
||||
this.isJoystickActive = false;
|
||||
this.joystick.parentElement?.removeChild(this.joystick);
|
||||
this.sendCommandToSubcribers(
|
||||
new MoveActionCommand(
|
||||
vec2.create(),
|
||||
OptionsHandler.options.relativeMovementEnabled,
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import {
|
||||
CommandGenerator,
|
||||
PrimaryActionCommand,
|
||||
SecondaryActionCommand,
|
||||
TernaryActionCommand,
|
||||
MoveActionCommand,
|
||||
} from 'shared';
|
||||
import { Game } from '../../game';
|
||||
import { OptionsHandler } from '../../options-handler';
|
||||
|
||||
export class TouchListener extends CommandGenerator {
|
||||
private previousPosition = vec2.create();
|
||||
|
||||
constructor(target: HTMLElement, private readonly game: Game) {
|
||||
super();
|
||||
|
||||
target.addEventListener('touchstart', (event: TouchEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
const touchCount = event.touches.length;
|
||||
const position = this.positionFromEvent(event);
|
||||
this.previousPosition = position;
|
||||
|
||||
if (touchCount == 1) {
|
||||
this.sendCommandToSubcribers(new PrimaryActionCommand(position));
|
||||
} else if (touchCount == 2) {
|
||||
this.sendCommandToSubcribers(new SecondaryActionCommand(position));
|
||||
} else {
|
||||
this.sendCommandToSubcribers(new TernaryActionCommand(position));
|
||||
}
|
||||
});
|
||||
|
||||
target.addEventListener('touchmove', (event: TouchEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
const position = this.positionFromEvent(event, true);
|
||||
const movement = vec2.subtract(vec2.create(), position, this.previousPosition);
|
||||
|
||||
if (vec2.squaredLength(movement) > 0) {
|
||||
vec2.normalize(movement, movement);
|
||||
this.sendCommandToSubcribers(
|
||||
new MoveActionCommand(movement, OptionsHandler.options.relativeMovementEnabled),
|
||||
);
|
||||
}
|
||||
|
||||
this.previousPosition = position;
|
||||
});
|
||||
|
||||
target.addEventListener('touchend', (event: TouchEvent) => {
|
||||
event.preventDefault();
|
||||
this.sendCommandToSubcribers(
|
||||
new MoveActionCommand(
|
||||
vec2.create(),
|
||||
OptionsHandler.options.relativeMovementEnabled,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private positionFromEvent(event: TouchEvent, invert = false): vec2 {
|
||||
const touches = Array.prototype.slice.call(event.touches);
|
||||
const center = touches.reduce(
|
||||
(center: vec2, touch: Touch) =>
|
||||
vec2.add(
|
||||
center,
|
||||
center,
|
||||
vec2.fromValues(
|
||||
touch.clientX * (invert ? -1 : 1),
|
||||
touch.clientY * (invert ? -1 : 1),
|
||||
),
|
||||
),
|
||||
vec2.create(),
|
||||
);
|
||||
|
||||
return this.game.displayToWorldCoordinates(
|
||||
vec2.scale(center, center, 1 / event.touches.length),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue