src/components/templates/AnimateMap/game/map/systems/MotionJoystickSystem.ts
import { Engine, NodeList } from "@ash.ts/ash";
import { Container, Graphics, Sprite } from "pixi.js";
import { Joystick, JoystickChangeEvent } from "pixi-virtual-joystick";
import {
JOYSTICK_HANDLE_IMAGE,
JOYSTICK_IMAGE,
} from "../../constants/AssetConstants";
import { Easing } from "../../utils/Easing";
import { JoystickComponent } from "../components/JoystickComponent";
import EntityFactory from "../entities/EntityFactory";
import { JoystickNode } from "../nodes/JoystickNode";
import { MotionJoystickControlNode } from "../nodes/MotionJoystickControlNode";
import { MotionKeyboardControlNode } from "../nodes/MotionKeyboardControlNode";
import { ViewportNode } from "../nodes/ViewportNode";
import { MotionBaseSystem } from "./MotionBaseSystem";
export class MotionJoystickSystem extends MotionBaseSystem {
private joystick?: NodeList<JoystickNode>;
private motionJoystickControl?: NodeList<MotionJoystickControlNode>;
private motionKeyboardControl?: NodeList<MotionKeyboardControlNode>;
private _container: Container;
private _joystick: Joystick;
private _outer: Graphics;
private _inner: Sprite;
private easingX?: Easing;
private easingY?: Easing;
constructor(container: Container, private entityFactory: EntityFactory) {
super();
this._container = container;
const background = Sprite.from(JOYSTICK_IMAGE);
background.anchor.set(0.5);
this._container.addChild(background);
this._outer = new Graphics();
this._outer.beginFill(0x000000);
this._outer.drawCircle(0, 0, background.width / 3);
this._outer.alpha = 0;
this._inner = Sprite.from(JOYSTICK_HANDLE_IMAGE);
this._inner.anchor.set(0.5);
const inner = new Container();
inner.addChild(this._inner);
this._joystick = new Joystick({
outer: this._outer,
inner: inner,
onChange: (e: JoystickChangeEvent) => this._onJoystickChange(e),
onStart: () => this._onJoystickStart(),
onEnd: () => this._onJoystickEnd(),
});
this._joystick.innerAlphaStandby = 1;
this._container?.addChild(this._joystick);
}
addToEngine(engine: Engine) {
this.motionJoystickControl = engine.getNodeList(MotionJoystickControlNode);
this.motionKeyboardControl = engine.getNodeList(MotionKeyboardControlNode);
this.viewport = engine.getNodeList(ViewportNode);
this.joystick = engine.getNodeList(JoystickNode);
this.entityFactory.createJoystick(new JoystickComponent());
}
removeFromEngine(engine: Engine) {
this.joystick = undefined;
this.motionJoystickControl = undefined;
this.motionKeyboardControl = undefined;
this.viewport = undefined;
}
update(time: number) {
if (this.easingY) {
this.easingY.update(time);
}
if (this.easingX) {
this.easingX.update(time);
}
if (!this.joystick || !this.joystick.head) {
return;
}
if (
this.motionJoystickControl &&
this.motionJoystickControl.head &&
this.joystick.head.joystick.active
) {
this.easingX = undefined;
this.easingY = undefined;
// move hero
const speed = this.getSpeed();
const angle = this.joystick.head.joystick.angle;
const power = this.joystick.head.joystick.power;
for (
let node: MotionJoystickControlNode | null | undefined = this
.motionJoystickControl.head;
node;
node = node.next
) {
node.movement.velocityX =
speed * Math.cos(angle * (Math.PI / 180)) * power;
node.movement.velocityY =
-speed * Math.sin(angle * (Math.PI / 180)) * power;
}
} else if (this.motionKeyboardControl && this.motionKeyboardControl.head) {
// hero is moved by WASD?
for (
let node: MotionKeyboardControlNode | null | undefined = this
.motionKeyboardControl.head;
node;
node = node.next
) {
let x =
node.movement.velocityX === 0
? 0
: node.movement.velocityX > 0
? 1
: -1;
let y =
node.movement.velocityY === 0
? 0
: node.movement.velocityY > 0
? 1
: -1;
const delta = this._outer.width * 0.42;
const k = x !== 0 && y !== 0 ? 0.825 : 1;
const time = 100;
x *= delta * k;
y *= delta * k;
if (!this.easingX || this.easingX.endValue !== x) {
this.easingX = new Easing(this._inner.position.x, x, time);
this.easingX.onComplete = () => {
this.easingX = undefined;
};
this.easingX.onStep = (value: number) => {
this._inner.position.x = value;
};
}
if (!this.easingY || this.easingY.endValue !== y) {
this.easingY = new Easing(this._inner.position.y, y, time);
this.easingY.onComplete = () => {
this.easingY = undefined;
};
this.easingY.onStep = (value: number) => {
this._inner.position.y = value;
};
}
}
}
}
private _onJoystickChange(data: JoystickChangeEvent) {
if (this.joystick && this.joystick.head) {
this.joystick.head.joystick.active = true;
this.joystick.head.joystick.angle = data.angle;
this.joystick.head.joystick.power = data.power;
}
}
private _onJoystickStart() {
if (this.joystick && this.joystick.head) {
this.joystick.head.joystick.active = true;
this.joystick.head.joystick.angle = 0;
this.joystick.head.joystick.power = 0;
this.entityFactory.updateJoystick();
}
}
private _onJoystickEnd() {
if (this.joystick && this.joystick.head) {
this.joystick.head.joystick.active = true;
this.joystick.head.joystick.angle = 0;
this.joystick.head.joystick.power = 0;
}
for (
let node: MotionJoystickControlNode | null | undefined = this
.motionJoystickControl?.head;
node;
node = node.next
) {
node.movement.velocityX = 0;
node.movement.velocityY = 0;
}
}
}