import { useEffect, useRef } from "react"; import { create } from "nipplejs"; import { joystickValues } from "../joystickInput"; // const isTouch = navigator.maxTouchPoints > 0; const isTouch = true; // debug export function JoystickView() { const moveZoneRef = useRef(null); const jumpBtnRef = useRef(null); const lookZoneRef = useRef(null); useEffect(() => { if (!isTouch) return; const moveZone = moveZoneRef.current; const jumpBtn = jumpBtnRef.current; const lookZone = lookZoneRef.current; if (!moveZone || !jumpBtn || !lookZone) return; let moveJoystick: ReturnType; let lookJoystick: ReturnType; const setup = () => { moveJoystick = create({ zone: moveZone, mode: 'static', position: { left: '80px', bottom: '80px' }, color: 'white', shape: 'circle', size: 100, }); lookJoystick = create({ zone: lookZone, mode: 'dynamic', dataOnly: true, }); 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.look = { x: 0, y: 0 }; joystickValues.jump = false; }; setup(); const onJumpDown = () => { joystickValues.jump = true; }; const onJumpUp = () => { joystickValues.jump = false; }; jumpBtn.addEventListener('pointerdown', onJumpDown); jumpBtn.addEventListener('pointerup', onJumpUp); jumpBtn.addEventListener('pointercancel', 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 () => { teardown(); jumpBtn.removeEventListener('pointerdown', onJumpDown); jumpBtn.removeEventListener('pointerup', onJumpUp); jumpBtn.removeEventListener('pointercancel', onJumpUp); jumpBtn.removeEventListener('pointerleave', onJumpUp); document.removeEventListener('visibilitychange', onVisibilityChange); }; }, []); if (!isTouch) return null; return ( <>
JUMP
); }