Fix G key (playBestSolution never awaited async bestSolution), add menu exit
- playBestSolution() called bestSolution() (now async, hits the server)
without await/async — got a Promise object back, .moves was undefined,
autoPlayStep() bailed on its first tick. G silently did nothing.
- No way back to the menu from gameplay — add 🏠 HUD button + M key,
cancels any in-flight search/autoplay before switching screens.
- settings-save button now shows "Сохраняю…" and disables itself during
the request — previously gave no feedback while the fetch was in
flight, looked like a dead button even though it worked (confirmed via
server logs/DB — the save itself was never broken).
This commit is contained in:
+25
-3
@@ -13,6 +13,8 @@
|
|||||||
canvas { border: 3px solid #e94560; border-radius: 12px; box-shadow: 0 0 20px rgba(233,69,96,0.4); }
|
canvas { border: 3px solid #e94560; border-radius: 12px; box-shadow: 0 0 20px rgba(233,69,96,0.4); }
|
||||||
#hud { display: flex; gap: 20px; color: #e94560; font-size: 16px; font-weight: bold; }
|
#hud { display: flex; gap: 20px; color: #e94560; font-size: 16px; font-weight: bold; }
|
||||||
#hud span { background: rgba(233,69,96,0.1); padding: 8px 16px; border-radius: 20px; border: 1px solid rgba(233,69,96,0.3); }
|
#hud span { background: rgba(233,69,96,0.1); padding: 8px 16px; border-radius: 20px; border: 1px solid rgba(233,69,96,0.3); }
|
||||||
|
#menu-btn { cursor: pointer; }
|
||||||
|
#menu-btn:hover { background: rgba(233,69,96,0.25) !important; }
|
||||||
#controls { color: #aaa; font-size: 13px; }
|
#controls { color: #aaa; font-size: 13px; }
|
||||||
kbd { background: #1a1a2e; border: 1px solid #e94560; border-radius: 4px; padding: 2px 6px; color: #e94560; }
|
kbd { background: #1a1a2e; border: 1px solid #e94560; border-radius: 4px; padding: 2px 6px; color: #e94560; }
|
||||||
#solve-overlay { position: fixed; inset: 0; background: rgba(10,10,21,0.75); display: flex; justify-content: center; align-items: center; z-index: 10; }
|
#solve-overlay { position: fixed; inset: 0; background: rgba(10,10,21,0.75); display: flex; justify-content: center; align-items: center; z-index: 10; }
|
||||||
@@ -124,6 +126,7 @@
|
|||||||
<span id="level-name">Уровень 1</span>
|
<span id="level-name">Уровень 1</span>
|
||||||
<span id="box-count">📦 0/0</span>
|
<span id="box-count">📦 0/0</span>
|
||||||
<span id="moves-count">👣 0</span>
|
<span id="moves-count">👣 0</span>
|
||||||
|
<span id="menu-btn" title="В меню">🏠</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="controls">
|
<div id="controls">
|
||||||
<kbd>← → ↑ ↓</kbd> или <kbd>WASD</kbd> — движение
|
<kbd>← → ↑ ↓</kbd> или <kbd>WASD</kbd> — движение
|
||||||
@@ -131,7 +134,8 @@
|
|||||||
<kbd>P</kbd> — пред.
|
<kbd>P</kbd> — пред.
|
||||||
<kbd>R</kbd> — рестарт
|
<kbd>R</kbd> — рестарт
|
||||||
<kbd>F</kbd> — автопоиск (<kbd>Esc</kbd> — отмена)
|
<kbd>F</kbd> — автопоиск (<kbd>Esc</kbd> — отмена)
|
||||||
<kbd>G</kbd> — лучшее сохранённое решение
|
<kbd>G</kbd> — лучшее сохранённое решение
|
||||||
|
<kbd>M</kbd> — в меню
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1722,9 +1726,9 @@ function autoPlayStep() {
|
|||||||
tryMove(dx, dy);
|
tryMove(dx, dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
function playBestSolution() {
|
async function playBestSolution() {
|
||||||
if (autoSolveActive || levelComplete || solveState || playerMoving || boxes.some(b => b.moving)) return;
|
if (autoSolveActive || levelComplete || solveState || playerMoving || boxes.some(b => b.moving)) return;
|
||||||
const best = bestSolution(LEVELS[currentLevel].name);
|
const best = await bestSolution(LEVELS[currentLevel].name);
|
||||||
if (!best) { alert('Нет сохранённых решений для этого уровня — сначала пройди его (F или руками)'); return; }
|
if (!best) { alert('Нет сохранённых решений для этого уровня — сначала пройди его (F или руками)'); return; }
|
||||||
startFlatPlayback(best.moves);
|
startFlatPlayback(best.moves);
|
||||||
}
|
}
|
||||||
@@ -2080,6 +2084,7 @@ window.addEventListener('keydown', e => {
|
|||||||
if (key === 'p') { currentLevel=(currentLevel-1+LEVELS.length)%LEVELS.length; loadLevel(currentLevel); e.preventDefault(); return; }
|
if (key === 'p') { currentLevel=(currentLevel-1+LEVELS.length)%LEVELS.length; loadLevel(currentLevel); e.preventDefault(); return; }
|
||||||
if (key === 'f') { startAutoSolve(); e.preventDefault(); return; }
|
if (key === 'f') { startAutoSolve(); e.preventDefault(); return; }
|
||||||
if (key === 'g') { playBestSolution(); e.preventDefault(); return; }
|
if (key === 'g') { playBestSolution(); e.preventDefault(); return; }
|
||||||
|
if (key === 'm') { backToMenu(); e.preventDefault(); return; }
|
||||||
|
|
||||||
// Стрелки и WASD
|
// Стрелки и WASD
|
||||||
if (['arrowup','arrowdown','arrowleft','arrowright','w','a','s','d'].includes(key)) {
|
if (['arrowup','arrowdown','arrowleft','arrowright','w','a','s','d'].includes(key)) {
|
||||||
@@ -2149,14 +2154,31 @@ document.getElementById('start-begin').addEventListener('click', () => {
|
|||||||
});
|
});
|
||||||
document.getElementById('end-menu').addEventListener('click', () => showScreen('screen-menu'));
|
document.getElementById('end-menu').addEventListener('click', () => showScreen('screen-menu'));
|
||||||
|
|
||||||
|
// Выход в меню из игры — гасим поиск/автопроигрывание, если шли, иначе
|
||||||
|
// они продолжат тикать в фоне за скрытым экраном.
|
||||||
|
function backToMenu() {
|
||||||
|
if (solveState) cancelAutoSolve();
|
||||||
|
autoSolveActive = false;
|
||||||
|
autoPlayMoves = null;
|
||||||
|
showScreen('screen-menu');
|
||||||
|
}
|
||||||
|
document.getElementById('menu-btn').addEventListener('click', backToMenu);
|
||||||
|
|
||||||
document.getElementById('settings-save').addEventListener('click', async () => {
|
document.getElementById('settings-save').addEventListener('click', async () => {
|
||||||
const name = document.getElementById('settings-name-input').value.trim();
|
const name = document.getElementById('settings-name-input').value.trim();
|
||||||
if (!name) return;
|
if (!name) return;
|
||||||
|
const btn = document.getElementById('settings-save');
|
||||||
|
btn.disabled = true;
|
||||||
|
const originalText = btn.textContent;
|
||||||
|
btn.textContent = 'Сохраняю…';
|
||||||
try {
|
try {
|
||||||
await apiPost('set_name', { name });
|
await apiPost('set_name', { name });
|
||||||
showScreen(settingsReturnTo === null ? 'screen-menu' : settingsReturnTo);
|
showScreen(settingsReturnTo === null ? 'screen-menu' : settingsReturnTo);
|
||||||
} catch {
|
} catch {
|
||||||
alert('Не удалось сохранить имя — сервер недоступен');
|
alert('Не удалось сохранить имя — сервер недоступен');
|
||||||
|
} finally {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = originalText;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.getElementById('settings-name-input').addEventListener('keydown', e => {
|
document.getElementById('settings-name-input').addEventListener('keydown', e => {
|
||||||
|
|||||||
Reference in New Issue
Block a user