From c9beda6ea07e84673122ed9e8d78b10a30d7d9ab Mon Sep 17 00:00:00 2001 From: Admin Date: Fri, 18 Sep 2026 00:29:25 +0000 Subject: [PATCH] Use split frame and movable helm knob --- src/mobile-hud.js | 96 +++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 58 deletions(-) diff --git a/src/mobile-hud.js b/src/mobile-hud.js index 1cbbc68..d549d7b 100644 --- a/src/mobile-hud.js +++ b/src/mobile-hud.js @@ -3,8 +3,8 @@ import topHudSrc from './assets/controller/top-hud.js'; import leftStatusSrc from './assets/controller/left-status.js'; import rightControlsSrc from './assets/controller/right-controls.js'; import cannonRoundelSrc from './assets/controller/cannon-roundel.js'; - -const helmSpriteSheetSrc = '/assets/controller/helm-sheet.webp'; +import helmFrameSrc from './assets/controller/helm-frame.js'; +import helmKnobSrc from './assets/controller/helm-knob.js'; const isDesktopPointer = window.matchMedia('(hover: hover) and (pointer: fine)'); @@ -162,22 +162,27 @@ if (!isDesktopPointer.matches) { aspect-ratio: 1; } - .steam-helm-frame, - .steam-helm-inner { + .steam-helm-frame { position: absolute; inset: 0; - background-repeat: no-repeat; - background-size: 300% 300%; + width: 100%; + height: 100%; + object-fit: contain; pointer-events: none; + z-index: 1; } - .steam-helm-frame { - background-position: 50% 50%; - } - - .steam-helm-inner { - background-position: 50% 50%; - clip-path: circle(36% at 50% 48%); + .steam-helm-knob { + position: absolute; + left: 50%; + top: 46%; + width: 32%; + height: auto; + object-fit: contain; + transform: translate(-50%, -50%); + pointer-events: none; + z-index: 3; + will-change: transform; } .steam-helm-label { @@ -201,6 +206,7 @@ if (!isDesktopPointer.matches) { height: 69%; border-radius: 50%; overflow: hidden; + z-index: 2; } .steam-radar-player, @@ -442,15 +448,19 @@ if (!isDesktopPointer.matches) { const radarPiece = document.createElement('div'); radarPiece.className = 'steam-piece steam-radar-wrap'; - const helmFrame = document.createElement('div'); + const helmFrame = document.createElement('img'); helmFrame.className = 'steam-helm-frame'; - helmFrame.style.backgroundImage = `url("${helmSpriteSheetSrc}")`; + helmFrame.src = helmFrameSrc; + helmFrame.alt = ''; + helmFrame.draggable = false; radarPiece.appendChild(helmFrame); - const helmInner = document.createElement('div'); - helmInner.className = 'steam-helm-inner'; - helmInner.style.backgroundImage = `url("${helmSpriteSheetSrc}")`; - radarPiece.appendChild(helmInner); + const helmKnob = document.createElement('img'); + helmKnob.className = 'steam-helm-knob'; + helmKnob.src = helmKnobSrc; + helmKnob.alt = ''; + helmKnob.draggable = false; + radarPiece.appendChild(helmKnob); radarPiece.insertAdjacentHTML('beforeend', `
@@ -479,48 +489,18 @@ if (!isDesktopPointer.matches) { const radarContacts = radarPiece.querySelector('#steam-radar-contacts'); - // Drive the 3×3 helm sheet from the same arrow-key state emitted by the - // mobile drag control. This keeps the visual frame exactly in sync with - // movement and avoids a second, jitter-prone pointer-direction calculation. - const helmKeys = new Set(); - let activeHelmFrame = '1:1'; - - const applyHelmFrame = (column, row) => { - const key = `${column}:${row}`; - if (key === activeHelmFrame) return; - activeHelmFrame = key; - helmInner.style.backgroundPosition = `${column * 50}% ${row * 50}%`; + const setHelmKnob = (x = 0, y = 0) => { + const maxOffset = Math.min(radarPiece.clientWidth * 0.20, 32); + const px = Math.max(-1, Math.min(1, x)) * maxOffset; + const py = Math.max(-1, Math.min(1, y)) * maxOffset; + helmKnob.style.transform = `translate(-50%, -50%) translate(${px}px, ${py}px)`; }; - const updateHelmFromKeys = () => { - const left = helmKeys.has('ArrowLeft'); - const right = helmKeys.has('ArrowRight'); - const up = helmKeys.has('ArrowUp'); - const down = helmKeys.has('ArrowDown'); - - const column = left && !right ? 0 : right && !left ? 2 : 1; - const row = up && !down ? 0 : down && !up ? 2 : 1; - applyHelmFrame(column, row); - }; - - const onHelmKeyDown = (event) => { - if (!['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.code)) return; - helmKeys.add(event.code); - updateHelmFromKeys(); - }; - - const onHelmKeyUp = (event) => { - if (!['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.code)) return; - helmKeys.delete(event.code); - updateHelmFromKeys(); - }; - - window.addEventListener('keydown', onHelmKeyDown); - window.addEventListener('keyup', onHelmKeyUp); - window.addEventListener('blur', () => { - helmKeys.clear(); - applyHelmFrame(1, 1); + window.addEventListener('airship:helm-vector', (event) => { + setHelmKnob(event.detail?.x ?? 0, event.detail?.y ?? 0); }); + + window.addEventListener('blur', () => setHelmKnob(0, 0)); const radarDots = Array.from({ length: 10 }, () => { const dot = document.createElement('span'); dot.className = 'steam-radar-dot';