fixed touchscreen controls stuck bug
This commit is contained in:
parent
c80b76e06e
commit
1210201802
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { create } from "nipplejs";
|
import { create } from "nipplejs";
|
||||||
import { DEFAULT_JOYSTICK_VALUES, joystickValues } from "../joystickInput";
|
import { joystickValues } from "../joystickInput";
|
||||||
|
|
||||||
// const isTouch = navigator.maxTouchPoints > 0;
|
// const isTouch = navigator.maxTouchPoints > 0;
|
||||||
const isTouch = true; // debug
|
const isTouch = true; // debug
|
||||||
|
|
@ -11,7 +11,7 @@ export function JoystickView() {
|
||||||
const lookZoneRef = useRef<HTMLDivElement>(null);
|
const lookZoneRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
if (!isTouch)
|
if (!isTouch)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -22,67 +22,100 @@ export function JoystickView() {
|
||||||
if (!moveZone || !jumpBtn || !lookZone)
|
if (!moveZone || !jumpBtn || !lookZone)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const moveJoystick = create({
|
let moveJoystick: ReturnType<typeof create>;
|
||||||
zone: moveZone,
|
let lookJoystick: ReturnType<typeof create>;
|
||||||
mode: 'static',
|
|
||||||
position: { left: '80px', bottom: '80px' },
|
|
||||||
color: 'white',
|
|
||||||
shape: 'square',
|
|
||||||
size: 100,
|
|
||||||
});
|
|
||||||
|
|
||||||
const lookJoystick = create({
|
const setup = () => {
|
||||||
zone: lookZone,
|
moveJoystick = create({
|
||||||
mode: 'dynamic',
|
zone: moveZone,
|
||||||
dataOnly: true,
|
mode: 'static',
|
||||||
});
|
position: { left: '80px', bottom: '80px' },
|
||||||
|
color: 'white',
|
||||||
|
shape: 'circle',
|
||||||
|
size: 100,
|
||||||
|
});
|
||||||
|
|
||||||
moveJoystick.on('move', (evt) => {
|
lookJoystick = create({
|
||||||
joystickValues.move.x = evt.data.vector.x;
|
zone: lookZone,
|
||||||
joystickValues.move.y = evt.data.vector.y;
|
mode: 'dynamic',
|
||||||
});
|
dataOnly: true,
|
||||||
moveJoystick.on('end', () => {
|
});
|
||||||
|
|
||||||
|
moveJoystick.on('move', (evt) => {
|
||||||
|
joystickValues.move.x = evt.data.vector.x;
|
||||||
|
joystickValues.move.y = evt.data.vector.y;
|
||||||
|
});
|
||||||
|
moveJoystick.on('end', () => {
|
||||||
|
joystickValues.move = { x: 0, y: 0 };
|
||||||
|
});
|
||||||
|
|
||||||
|
lookJoystick.on('move', (evt) => {
|
||||||
|
joystickValues.look = evt.data.vector;
|
||||||
|
});
|
||||||
|
lookJoystick.on('end', () => {
|
||||||
|
joystickValues.look = { x: 0, y: 0 };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const teardown = () => {
|
||||||
|
moveJoystick?.destroy();
|
||||||
|
lookJoystick?.destroy();
|
||||||
joystickValues.move = { x: 0, y: 0 };
|
joystickValues.move = { x: 0, y: 0 };
|
||||||
});
|
|
||||||
|
|
||||||
lookJoystick.on('move', (evt) => {
|
|
||||||
joystickValues.look = evt.data.vector;
|
|
||||||
});
|
|
||||||
lookJoystick.on('end', () => {
|
|
||||||
joystickValues.look = { x: 0, y: 0 };
|
joystickValues.look = { x: 0, y: 0 };
|
||||||
});
|
joystickValues.jump = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
setup();
|
||||||
|
|
||||||
const onJumpDown = () => { joystickValues.jump = true; };
|
const onJumpDown = () => { joystickValues.jump = true; };
|
||||||
const onJumpUp = () => { joystickValues.jump = false; };
|
const onJumpUp = () => { joystickValues.jump = false; };
|
||||||
|
|
||||||
jumpBtn.addEventListener('pointerdown', onJumpDown);
|
jumpBtn.addEventListener('pointerdown', onJumpDown);
|
||||||
jumpBtn.addEventListener('pointerup', onJumpUp);
|
jumpBtn.addEventListener('pointerup', onJumpUp);
|
||||||
|
jumpBtn.addEventListener('pointercancel', onJumpUp);
|
||||||
jumpBtn.addEventListener('pointerleave', onJumpUp);
|
jumpBtn.addEventListener('pointerleave', onJumpUp);
|
||||||
|
|
||||||
|
// When the OS interrupts a touch (app switch, notification, etc.) the browser
|
||||||
|
// fires pointercancel instead of pointerup, leaving nipplejs with a stuck active
|
||||||
|
// identifier. In dynamic mode this silently drops all subsequent touches on the
|
||||||
|
// look zone. Destroying and recreating resets nipplejs's internal touch tracking.
|
||||||
|
const onVisibilityChange = () => {
|
||||||
|
if (document.hidden) {
|
||||||
|
teardown();
|
||||||
|
} else {
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('visibilitychange', onVisibilityChange);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
moveJoystick.destroy();
|
teardown();
|
||||||
lookJoystick.destroy();
|
|
||||||
jumpBtn.removeEventListener('pointerdown', onJumpDown);
|
jumpBtn.removeEventListener('pointerdown', onJumpDown);
|
||||||
jumpBtn.removeEventListener('pointerup', onJumpUp);
|
jumpBtn.removeEventListener('pointerup', onJumpUp);
|
||||||
|
jumpBtn.removeEventListener('pointercancel', onJumpUp);
|
||||||
jumpBtn.removeEventListener('pointerleave', onJumpUp);
|
jumpBtn.removeEventListener('pointerleave', onJumpUp);
|
||||||
Object.assign(joystickValues, DEFAULT_JOYSTICK_VALUES);
|
document.removeEventListener('visibilitychange', onVisibilityChange);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!isTouch) return null;
|
if (!isTouch)
|
||||||
|
return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
ref={moveZoneRef}
|
ref={moveZoneRef}
|
||||||
style={{ position: 'absolute', left: 0, bottom: 0, width: '50%', height: '45%', touchAction: 'none' }}
|
id="move-zone"
|
||||||
|
style={{ position: 'absolute', left: 0, bottom: 0, width: '30vw', height: '30vw', touchAction: 'none', background: 'red' }}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
ref={lookZoneRef}
|
ref={lookZoneRef}
|
||||||
style={{ position: 'absolute', right: 0, bottom: 0, width: '50%', height: '45%', touchAction: 'none' }}
|
id="look-zone"
|
||||||
|
style={{ position: 'absolute', right: 0, bottom: 0, width: '100%', height: '100%', touchAction: 'none' }}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
ref={jumpBtnRef}
|
ref={jumpBtnRef}
|
||||||
|
id="jump-zone"
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
right: 30,
|
right: 30,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue