Add battle action shortcuts and clarify selection UI
This commit is contained in:
@@ -8,8 +8,10 @@ import { createFinishCutscene } from './finish-cutscene.js';
|
||||
import { matchIntroductionMessage } from '../shared/match-introduction.js';
|
||||
import { EMOTE_COOLDOWN_MS, EMOTE_IDS, EMOTE_LABELS, EMOTE_LINES, type EmoteId } from '../../constants/emotes.js';
|
||||
import { sound } from './sound.js';
|
||||
import { ACTION_SHORTCUTS } from '../../constants/match-controls.js';
|
||||
|
||||
const fighter = (i: number, appearance?: FighterAppearance) => `<div class="fighter" data-fighter="${i}">
|
||||
<div class="fighter-position"></div>
|
||||
<div class="avatar"><div class="emote-bubble" role="status" hidden></div><div class="aura"></div><div class="motion-trails"><i></i><i></i><i></i></div><div class="character-direction">${fighterArt(i, false, appearance)}</div>${ashPileArt()}<div class="projectile"></div><div class="shield"></div><div class="impact"></div><button type="button" class="emote-trigger" data-emote-trigger="${i}" aria-label="내 캐릭터 감정표현 선택" aria-expanded="false" aria-controls="emote-choices" hidden></button></div>
|
||||
<div class="fighter-caption"><span class="choice-status"></span><span class="action-label"></span><span class="energy-change" aria-hidden="true"></span></div>
|
||||
</div>`;
|
||||
@@ -62,6 +64,23 @@ export function createMatchView(container: HTMLElement, onAction: (action: Actio
|
||||
const el = <T extends HTMLElement = HTMLElement>(selector: string) => container.querySelector<T>(selector)!;
|
||||
el('.result-banner h2').tabIndex = -1;
|
||||
const buttons = Array.from(container.querySelectorAll<HTMLButtonElement>('[data-action]'));
|
||||
buttons.forEach(button => {
|
||||
const shortcut = ACTION_SHORTCUTS[button.dataset.action as ActionId];
|
||||
button.setAttribute('aria-keyshortcuts', shortcut);
|
||||
button.insertAdjacentHTML('beforeend', `<kbd class="action-shortcut" aria-hidden="true">${shortcut}</kbd>`);
|
||||
});
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.defaultPrevented || event.repeat || event.ctrlKey || event.altKey || event.metaKey || emoteOpen
|
||||
|| container.hidden || document.querySelector('dialog[open]')) return;
|
||||
if (event.target instanceof HTMLElement && (event.target.isContentEditable || event.target.closest('input, textarea, select'))) return;
|
||||
const button = buttons.find(button => event.code === `Key${ACTION_SHORTCUTS[button.dataset.action as ActionId]}`);
|
||||
if (!button || button.disabled) return;
|
||||
tick();
|
||||
if (button.disabled) return;
|
||||
event.preventDefault();
|
||||
button.click();
|
||||
};
|
||||
document.addEventListener('keydown', onKeyDown);
|
||||
buttons.forEach(button => button.addEventListener('click', async () => {
|
||||
if (busy || !current || current.phase !== 'selecting' || current.ownAction || Date.now() + offset >= current.deadline) return;
|
||||
const action = button.dataset.action as ActionId;
|
||||
@@ -191,6 +210,7 @@ export function createMatchView(container: HTMLElement, onAction: (action: Actio
|
||||
appearanceSignatures[i] = signature;
|
||||
}
|
||||
node.classList.toggle('self', i === state.selfIndex);
|
||||
node.querySelector('.fighter-position')!.textContent = i === state.selfIndex ? '▼ 나' : '▼ 상대';
|
||||
node.setAttribute('role', 'group');
|
||||
node.setAttribute('aria-label', i === state.selfIndex ? '내 캐릭터' : state.mode === 'bot' ? '봇 캐릭터' : '상대 캐릭터');
|
||||
});
|
||||
@@ -201,6 +221,6 @@ export function createMatchView(container: HTMLElement, onAction: (action: Actio
|
||||
}
|
||||
cutscene.update(state);
|
||||
tick();
|
||||
}, destroy() { submission++; clearInterval(interval); cutscene.destroy(); renderer.destroy(); sound.stop(); container.onpointerdown = null; container.onkeydown = null; container.innerHTML = ''; current = undefined; },
|
||||
}, destroy() { submission++; clearInterval(interval); document.removeEventListener('keydown', onKeyDown); cutscene.destroy(); renderer.destroy(); sound.stop(); container.onpointerdown = null; container.onkeydown = null; container.innerHTML = ''; current = undefined; },
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user