102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
import { Vector2 } from 'three';
|
|
import { Player } from './player';
|
|
|
|
export class Joystick {
|
|
public element = document.createElement('div');
|
|
private knob = document.createElement('div');
|
|
|
|
private mousePos = new Vector2();
|
|
private prevMousePos = new Vector2();
|
|
private center = new Vector2();
|
|
private knobCenter = new Vector2();
|
|
private mouseCenterOffset = new Vector2();
|
|
private radiusSquare = new Vector2();
|
|
private negRadiusSquare = new Vector2();
|
|
private appliedForce = new Vector2();
|
|
|
|
private dragging = false;
|
|
|
|
constructor(private player: Player, public radius = 60) {}
|
|
|
|
initialize() {
|
|
this.element.classList.add('joystick', 'joystick__wrapper');
|
|
this.knob.classList.add('joystick__knob');
|
|
this.element.append(this.knob);
|
|
document.body.append(this.element);
|
|
|
|
this.element.addEventListener('touchstart', (e) => {
|
|
e.preventDefault();
|
|
const touch = e.touches[0] || e.changedTouches[0];
|
|
this.mousePos.fromArray([touch.pageX, touch.pageY]);
|
|
this.dragging = true;
|
|
});
|
|
|
|
this.element.addEventListener('touchmove', (e) => {
|
|
e.preventDefault();
|
|
if (this.dragging) {
|
|
this.prevMousePos.copy(this.mousePos);
|
|
this.mousePos.fromArray([e.touches[0].clientX, e.touches[0].clientY]);
|
|
this.mouseCenterOffset.copy(this.center).sub(this.mousePos);
|
|
this.mouseCenterOffset.clamp(this.negRadiusSquare, this.radiusSquare);
|
|
|
|
const knobPosition = new Vector2();
|
|
knobPosition.copy(this.knobCenter).sub(this.mouseCenterOffset);
|
|
this.knob.style.transform = `translate(${knobPosition.x}px, ${knobPosition.y}px)`;
|
|
|
|
this.appliedForce
|
|
.copy(this.mouseCenterOffset)
|
|
.divideScalar(this.radius);
|
|
}
|
|
});
|
|
|
|
this.element.addEventListener('touchend', (e) => {
|
|
this.dragging = false;
|
|
this.centerKnob();
|
|
});
|
|
|
|
window.addEventListener('resize', this._windowEventBound);
|
|
|
|
this.getCenter();
|
|
this.centerKnob();
|
|
}
|
|
|
|
getCenter() {
|
|
const rect = this.element.getBoundingClientRect();
|
|
this.center.fromArray([rect.left + this.radius, rect.top + this.radius]);
|
|
this.knobCenter.fromArray([this.radius / 2 - 2, this.radius / 2 - 2]);
|
|
}
|
|
|
|
centerKnob() {
|
|
this.appliedForce.set(0, 0);
|
|
this.knob.style.transform = `translate(${this.knobCenter.x}px, ${this.knobCenter.y}px)`;
|
|
}
|
|
|
|
reset() {
|
|
this.radiusSquare.set(this.radius, this.radius);
|
|
this.negRadiusSquare.set(-this.radius, -this.radius);
|
|
this.element.style.setProperty('--size', `${this.radius * 2}px`);
|
|
this.getCenter();
|
|
}
|
|
|
|
update(dt: number) {
|
|
if (this.appliedForce.length() !== 0) {
|
|
this.player.applyForce(this.appliedForce);
|
|
}
|
|
}
|
|
|
|
dispose() {
|
|
this.element.parentElement.removeChild(this.element);
|
|
}
|
|
|
|
show() {
|
|
this.element.style.display = 'block';
|
|
this.reset();
|
|
}
|
|
|
|
private _windowEvent() {
|
|
this.reset();
|
|
}
|
|
|
|
private _windowEventBound = this._windowEvent.bind(this);
|
|
}
|