From 543fc80752df4fd204ffdcd8adb3bbc382523ef6 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 19 Feb 2024 15:45:47 +0300 Subject: [PATCH] feat: add new experimental touch controls --- src/index.ts | 64 ++++-- src/optionsGuiScheme.tsx | 11 +- src/optionsStorage.ts | 25 ++- src/playerWindows.ts | 2 +- src/react/AppStatus.tsx | 4 +- src/react/PixelartIcon.tsx | 7 +- src/react/TouchAreas.stories.tsx | 19 -- src/react/TouchAreasControls.tsx | 248 ++++++++++++++++------- src/react/TouchAreasControlsProvider.tsx | 12 +- src/react/TouchControls.tsx | 3 +- 10 files changed, 280 insertions(+), 115 deletions(-) delete mode 100644 src/react/TouchAreas.stories.tsx diff --git a/src/index.ts b/src/index.ts index 2e2564c2..933d68de 100644 --- a/src/index.ts +++ b/src/index.ts @@ -91,6 +91,7 @@ import { loadInMemorySave } from './react/SingleplayerProvider' // side effects import { downloadSoundsIfNeeded } from './soundSystem' import { ua } from './react/utils' +import { handleMovementStickDelta, joystickPointer } from './react/TouchAreasControls' window.debug = debug window.THREE = THREE @@ -670,6 +671,7 @@ async function connect (connectOptions: { let screenTouches = 0 let capturedPointer: { id; x; y; sourceX; sourceY; activateCameraMove; time } | undefined registerListener(document, 'pointerdown', (e) => { + const usingJoystick = options.touchControlsType === 'joystick-buttons' const clickedEl = e.composedPath()[0] if (!isGameActive(true) || !miscUiState.currentTouch || clickedEl !== cameraControlEl || e.pointerId === undefined) { return @@ -679,6 +681,16 @@ async function connect (connectOptions: { // todo needs fixing! // window.dispatchEvent(new MouseEvent('mousedown', { button: 1 })) } + if (usingJoystick) { + if (!joystickPointer.pointer && e.clientX < window.innerWidth / 2) { + joystickPointer.pointer = { + pointerId: e.pointerId, + x: e.clientX, + y: e.clientY + } + return + } + } if (capturedPointer) { return } @@ -692,19 +704,33 @@ async function connect (connectOptions: { activateCameraMove: false, time: Date.now() } - virtualClickTimeout ??= setTimeout(() => { - virtualClickActive = true - document.dispatchEvent(new MouseEvent('mousedown', { button: 0 })) - }, touchStartBreakingBlockMs) + if (options.touchControlsType !== 'joystick-buttons') { + virtualClickTimeout ??= setTimeout(() => { + virtualClickActive = true + document.dispatchEvent(new MouseEvent('mousedown', { button: 0 })) + }, touchStartBreakingBlockMs) + } }) registerListener(document, 'pointermove', (e) => { - if (e.pointerId === undefined || e.pointerId !== capturedPointer?.id) return + if (e.pointerId === undefined) return + const supportsPressure = (e as any).pressure !== undefined && (e as any).pressure !== 0 && (e as any).pressure !== 0.5 && (e as any).pressure !== 1 && (e.pointerType === 'touch' || e.pointerType === 'pen') + if (e.pointerId === joystickPointer.pointer?.pointerId) { + handleMovementStickDelta(e) + if (supportsPressure && (e as any).pressure > 0.5) { + bot.setControlState('sprint', true) + // todo + } + return + } + if (e.pointerId !== capturedPointer?.id) return window.scrollTo(0, 0) e.preventDefault() e.stopPropagation() const allowedJitter = 1.1 - // todo support .pressure (3d touch) + if (supportsPressure) { + bot.setControlState('jump', (e as any).pressure > 0.5) + } const xDiff = Math.abs(e.pageX - capturedPointer.sourceX) > allowedJitter const yDiff = Math.abs(e.pageY - capturedPointer.sourceY) > allowedJitter if (!capturedPointer.activateCameraMove && (xDiff || yDiff)) capturedPointer.activateCameraMove = true @@ -717,18 +743,26 @@ async function connect (connectOptions: { }, { passive: false }) const pointerUpHandler = (e: PointerEvent) => { - if (e.pointerId === undefined || e.pointerId !== capturedPointer?.id) return + if (e.pointerId === undefined) return + if (e.pointerId === joystickPointer.pointer?.pointerId) { + handleMovementStickDelta() + joystickPointer.pointer = null + return + } + if (e.pointerId !== capturedPointer?.id) return clearTimeout(virtualClickTimeout) virtualClickTimeout = undefined - if (virtualClickActive) { - // button 0 is left click - document.dispatchEvent(new MouseEvent('mouseup', { button: 0 })) - virtualClickActive = false - } else if (!capturedPointer.activateCameraMove && (Date.now() - capturedPointer.time < touchStartBreakingBlockMs)) { - document.dispatchEvent(new MouseEvent('mousedown', { button: 2 })) - worldInteractions.update() - document.dispatchEvent(new MouseEvent('mouseup', { button: 2 })) + if (options.touchControlsType !== 'joystick-buttons') { + if (virtualClickActive) { + // button 0 is left click + document.dispatchEvent(new MouseEvent('mouseup', { button: 0 })) + virtualClickActive = false + } else if (!capturedPointer.activateCameraMove && (Date.now() - capturedPointer.time < touchStartBreakingBlockMs)) { + document.dispatchEvent(new MouseEvent('mousedown', { button: 2 })) + worldInteractions.update() + document.dispatchEvent(new MouseEvent('mouseup', { button: 2 })) + } } capturedPointer = undefined screenTouches-- diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 1ec83643..c0b64979 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -188,7 +188,16 @@ export const guiOptionsScheme: { }, touchButtonsPosition: { max: 80 - } + }, + touchControlsType: { + values: [['classic', 'Classic'], ['joystick-buttons', 'New']], + }, + }, + { + custom () { + const { touchControlsType } = useSnapshot(options) + return + + } } + +const MineIcon = () => { + return + + +} diff --git a/src/react/TouchAreasControlsProvider.tsx b/src/react/TouchAreasControlsProvider.tsx index 7a3f9637..7de8eaca 100644 --- a/src/react/TouchAreasControlsProvider.tsx +++ b/src/react/TouchAreasControlsProvider.tsx @@ -1,5 +1,5 @@ import { useSnapshot } from 'valtio' -import { activeModalStack } from '../globalState' +import { activeModalStack, hideModal } from '../globalState' import { options } from '../optionsStorage' import TouchAreasControls from './TouchAreasControls' import { useIsModalActive, useUsingTouch } from './utils' @@ -7,7 +7,13 @@ import { useIsModalActive, useUsingTouch } from './utils' export default () => { const usingTouch = useUsingTouch() const hasModals = useSnapshot(activeModalStack).length !== 0 - const setupActive = useIsModalActive('touch-areas-setup') + const setupActive = useIsModalActive('touch-buttons-setup') + const { touchControlsPositions, touchControlsType } = useSnapshot(options) - return + return { + if (newPositions) { + options.touchControlsPositions = newPositions + } + hideModal() + }} /> } diff --git a/src/react/TouchControls.tsx b/src/react/TouchControls.tsx index 6e5cb4a7..db71ae1f 100644 --- a/src/react/TouchControls.tsx +++ b/src/react/TouchControls.tsx @@ -49,8 +49,9 @@ export default () => { const usingTouch = useUsingTouch() const { usingGamepadInput } = useSnapshot(miscUiState) const modals = useSnapshot(activeModalStack) + const { touchControlsType } = useSnapshot(options) - if (!usingTouch || usingGamepadInput) return null + if (!usingTouch || usingGamepadInput || touchControlsType !== 'classic') return null return (