mylingo3d
Version:
Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor
97 lines (84 loc) • 3.1 kB
text/typescript
import EventLoopItem from "../api/core/EventLoopItem"
import nipplejs from "nipplejs"
import { container } from "../engine/renderLoop/renderSetup"
import IJoystick, {
joystickDefaults,
joystickSchema
} from "../interface/IJoystick"
import { Point } from "@lincode/math"
import Nullable from "../interface/utils/Nullable"
import createElement from "../utils/createElement"
import { Cancellable } from "@lincode/promiselikes"
import store, { Reactive } from "@lincode/reactivity"
import { onBeforeRender } from "../events/onBeforeRender"
export default class Joystick extends EventLoopItem implements IJoystick {
public static componentName = "joystick"
public static defaults = joystickDefaults
public static schema = joystickSchema
public onMove: Nullable<(e: Point) => void>
public onMoveStart: Nullable<(e: Point) => void>
public onMoveEnd: Nullable<(e: Point) => void>
private onPressState = new Reactive<((e: Point) => void) | undefined>(
undefined
)
public get onPress() {
return this.onPressState.get()
}
public set onPress(cb) {
this.onPressState.set(cb)
}
public constructor() {
super()
let pt = new Point(0, 0)
const [setDown, getDown] = store(false)
this.createEffect(() => {
const cb = this.onPressState.get()
if (!cb || !getDown()) return
const handle = onBeforeRender(() => {
cb(pt)
})
return () => {
return handle.cancel()
}
}, [this.onPressState.get, getDown])
this.createEffect(() => {
const zone = createElement<HTMLDivElement>(`
<div style="width: 150px; height: 150px; position: absolute; bottom: 25px; left: 25px;"></div>
`)
container.appendChild(zone)
const prevent = (e: Event) => {
e.preventDefault()
e.stopPropagation()
}
zone.onmousedown = prevent
zone.ontouchstart = prevent
zone.onpointerdown = prevent
const handle = new Cancellable()
setTimeout(() => {
const manager = nipplejs.create({
zone,
mode: "static",
position: { left: "75px", bottom: "75px" },
color: "white"
})
handle.then(() => manager.destroy())
manager.on("start", () => {
this.onMoveStart?.(new Point(0, 0))
setDown(true)
})
manager.on("move", (_, nipple) => {
this.onMove?.(nipple.vector)
pt = nipple.vector
})
manager.on("end", () => {
this.onMoveEnd?.(new Point(0, 0))
pt = new Point(0, 0)
setDown(false)
})
})
return () => {
handle.cancel()
}
}, [])
}
}