Use split frame and movable helm knob

This commit is contained in:
Admin 2026-09-18 00:29:25 +00:00
parent 4e2a4d7318
commit c9beda6ea0

View File

@ -3,8 +3,8 @@ import topHudSrc from './assets/controller/top-hud.js';
import leftStatusSrc from './assets/controller/left-status.js'; import leftStatusSrc from './assets/controller/left-status.js';
import rightControlsSrc from './assets/controller/right-controls.js'; import rightControlsSrc from './assets/controller/right-controls.js';
import cannonRoundelSrc from './assets/controller/cannon-roundel.js'; import cannonRoundelSrc from './assets/controller/cannon-roundel.js';
import helmFrameSrc from './assets/controller/helm-frame.js';
const helmSpriteSheetSrc = '/assets/controller/helm-sheet.webp'; import helmKnobSrc from './assets/controller/helm-knob.js';
const isDesktopPointer = window.matchMedia('(hover: hover) and (pointer: fine)'); const isDesktopPointer = window.matchMedia('(hover: hover) and (pointer: fine)');
@ -162,22 +162,27 @@ if (!isDesktopPointer.matches) {
aspect-ratio: 1; aspect-ratio: 1;
} }
.steam-helm-frame, .steam-helm-frame {
.steam-helm-inner {
position: absolute; position: absolute;
inset: 0; inset: 0;
background-repeat: no-repeat; width: 100%;
background-size: 300% 300%; height: 100%;
object-fit: contain;
pointer-events: none; pointer-events: none;
z-index: 1;
} }
.steam-helm-frame { .steam-helm-knob {
background-position: 50% 50%; position: absolute;
} left: 50%;
top: 46%;
.steam-helm-inner { width: 32%;
background-position: 50% 50%; height: auto;
clip-path: circle(36% at 50% 48%); object-fit: contain;
transform: translate(-50%, -50%);
pointer-events: none;
z-index: 3;
will-change: transform;
} }
.steam-helm-label { .steam-helm-label {
@ -201,6 +206,7 @@ if (!isDesktopPointer.matches) {
height: 69%; height: 69%;
border-radius: 50%; border-radius: 50%;
overflow: hidden; overflow: hidden;
z-index: 2;
} }
.steam-radar-player, .steam-radar-player,
@ -442,15 +448,19 @@ if (!isDesktopPointer.matches) {
const radarPiece = document.createElement('div'); const radarPiece = document.createElement('div');
radarPiece.className = 'steam-piece steam-radar-wrap'; radarPiece.className = 'steam-piece steam-radar-wrap';
const helmFrame = document.createElement('div'); const helmFrame = document.createElement('img');
helmFrame.className = 'steam-helm-frame'; helmFrame.className = 'steam-helm-frame';
helmFrame.style.backgroundImage = `url("${helmSpriteSheetSrc}")`; helmFrame.src = helmFrameSrc;
helmFrame.alt = '';
helmFrame.draggable = false;
radarPiece.appendChild(helmFrame); radarPiece.appendChild(helmFrame);
const helmInner = document.createElement('div'); const helmKnob = document.createElement('img');
helmInner.className = 'steam-helm-inner'; helmKnob.className = 'steam-helm-knob';
helmInner.style.backgroundImage = `url("${helmSpriteSheetSrc}")`; helmKnob.src = helmKnobSrc;
radarPiece.appendChild(helmInner); helmKnob.alt = '';
helmKnob.draggable = false;
radarPiece.appendChild(helmKnob);
radarPiece.insertAdjacentHTML('beforeend', ` radarPiece.insertAdjacentHTML('beforeend', `
<div id="steam-radar-contacts"> <div id="steam-radar-contacts">
@ -479,48 +489,18 @@ if (!isDesktopPointer.matches) {
const radarContacts = radarPiece.querySelector('#steam-radar-contacts'); const radarContacts = radarPiece.querySelector('#steam-radar-contacts');
// Drive the 3×3 helm sheet from the same arrow-key state emitted by the const setHelmKnob = (x = 0, y = 0) => {
// mobile drag control. This keeps the visual frame exactly in sync with const maxOffset = Math.min(radarPiece.clientWidth * 0.20, 32);
// movement and avoids a second, jitter-prone pointer-direction calculation. const px = Math.max(-1, Math.min(1, x)) * maxOffset;
const helmKeys = new Set(); const py = Math.max(-1, Math.min(1, y)) * maxOffset;
let activeHelmFrame = '1:1'; helmKnob.style.transform = `translate(-50%, -50%) translate(${px}px, ${py}px)`;
const applyHelmFrame = (column, row) => {
const key = `${column}:${row}`;
if (key === activeHelmFrame) return;
activeHelmFrame = key;
helmInner.style.backgroundPosition = `${column * 50}% ${row * 50}%`;
}; };
const updateHelmFromKeys = () => { window.addEventListener('airship:helm-vector', (event) => {
const left = helmKeys.has('ArrowLeft'); setHelmKnob(event.detail?.x ?? 0, event.detail?.y ?? 0);
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('blur', () => setHelmKnob(0, 0));
const radarDots = Array.from({ length: 10 }, () => { const radarDots = Array.from({ length: 10 }, () => {
const dot = document.createElement('span'); const dot = document.createElement('span');
dot.className = 'steam-radar-dot'; dot.className = 'steam-radar-dot';