TSG / static /js /game.js
Starchik1's picture
Upload 11 files
43f0655 verified
document.addEventListener('DOMContentLoaded', function() {
// Элементы DOM
const textDisplay = document.getElementById('textDisplay');
const inputArea = document.getElementById('inputArea');
const wpmDisplay = document.getElementById('wpm');
const accuracyDisplay = document.getElementById('accuracy');
const timeDisplay = document.getElementById('time');
const startBtn = document.getElementById('startBtn');
const resultContainer = document.getElementById('resultContainer');
const finalWpm = document.getElementById('finalWpm');
const finalAccuracy = document.getElementById('finalAccuracy');
const finalTime = document.getElementById('finalTime');
const restartBtn = document.getElementById('restartBtn');
const overseer = document.getElementById('overseer');
const gunshot = document.getElementById('gunshot');
const usernameInput = document.getElementById('username');
// Переменные для игры
let text = '';
let startTime = null;
let endTime = null;
let timer = null;
let mistakes = 0;
let totalChars = 0;
let currentPosition = 0;
let gameActive = false;
let timeLimit = 60; // Время в секундах
let timeRemaining = timeLimit;
// Получение текста с сервера
function fetchText() {
fetch('/get_text')
.then(response => response.json())
.then(data => {
text = data.text;
displayText();
})
.catch(error => console.error('Error fetching text:', error));
}
// Отображение текста
function displayText() {
textDisplay.innerHTML = '';
for (let i = 0; i < text.length; i++) {
const span = document.createElement('span');
span.textContent = text[i];
textDisplay.appendChild(span);
}
// Выделяем первый символ как текущий
if (textDisplay.firstChild) {
textDisplay.firstChild.classList.add('current');
}
}
// Начало игры
function startGame() {
if (gameActive) return;
// Скрываем кнопку старта во время обратного отсчёта
startBtn.disabled = true;
// Запускаем обратный отсчёт
startCountdown();
}
// Функция обратного отсчёта
function startCountdown() {
const countdown = document.getElementById('countdown');
countdown.style.display = 'block';
let count = 3;
countdown.textContent = count;
countdown.classList.add('pulse');
const countdownTimer = setInterval(() => {
count--;
if (count > 0) {
countdown.textContent = count;
countdown.classList.remove('pulse');
void countdown.offsetWidth; // Перезапуск анимации
countdown.classList.add('pulse');
} else if (count === 0) {
countdown.textContent = 'Старт!';
countdown.classList.remove('pulse');
void countdown.offsetWidth;
countdown.classList.add('pulse');
} else {
clearInterval(countdownTimer);
countdown.style.display = 'none';
initializeGame();
}
}, 1000);
}
// Инициализация игры после обратного отсчёта
function initializeGame() {
fetchText();
inputArea.value = '';
inputArea.disabled = false;
inputArea.focus();
mistakes = 0;
totalChars = 0;
currentPosition = 0;
timeRemaining = timeLimit;
startTime = new Date();
gameActive = true;
// Запускаем таймер
timer = setInterval(updateTimer, 1000);
// Скрываем результаты и надсмотрщика
resultContainer.style.display = 'none';
overseer.classList.remove('show');
// Разблокируем кнопку старта
startBtn.disabled = false;
// Обновляем статистику
updateStats();
}
// Обновление таймера
function updateTimer() {
timeRemaining--;
timeDisplay.textContent = timeRemaining;
if (timeRemaining <= 0) {
endGame(false);
}
}
// Обновление статистики
function updateStats() {
if (!gameActive) return;
const currentTime = new Date();
const timeElapsed = (currentTime - startTime) / 1000; // в секундах
// Расчет WPM (слов в минуту)
// Считаем, что среднее слово - 5 символов
const wpm = Math.round((currentPosition / 5) / (timeElapsed / 60));
// Расчет точности
const accuracy = totalChars > 0 ? Math.round(((totalChars - mistakes) / totalChars) * 100) : 100;
wpmDisplay.textContent = wpm;
accuracyDisplay.textContent = accuracy + '%';
}
// Завершение игры
function endGame(completed = true) {
clearInterval(timer);
gameActive = false;
endTime = new Date();
inputArea.disabled = true;
const timeElapsed = Math.round((endTime - startTime) / 1000);
const wpm = Math.round((currentPosition / 5) / (timeElapsed / 60));
const accuracy = totalChars > 0 ? Math.round(((totalChars - mistakes) / totalChars) * 100) : 100;
finalWpm.textContent = wpm;
finalAccuracy.textContent = accuracy + '%';
finalTime.textContent = timeElapsed + 's';
resultContainer.style.display = 'block';
// Если игра не завершена успешно или точность ниже 70%, показываем надсмотрщика
if (!completed || accuracy < 70) {
showOverseer();
}
// Сохраняем результат
if (usernameInput && usernameInput.value) {
saveResult(usernameInput.value, wpm, accuracy);
}
}
// Показ надсмотрщика и анимация выстрела
function showOverseer() {
overseer.classList.add('show');
// Создаем капли крови для разбрызгивания
createBloodSplatters();
// Через 2 секунды после появления надсмотрщика - "выстрел"
setTimeout(() => {
overseer.classList.add('firing');
gunshot.style.display = 'block';
bloodSplatter.classList.add('show');
// Показываем сообщение о смерти
deathMessage.classList.add('show');
// Звук выстрела
const audio = new Audio('/static/sounds/gunshot.mp3');
audio.play().catch(e => console.log('Audio play failed:', e));
// Эффект тряски экрана
document.body.classList.add('shake');
setTimeout(() => {
document.body.classList.remove('shake');
}, 500);
// Скрываем эффект выстрела через 500мс
setTimeout(() => {
gunshot.style.display = 'none';
}, 500);
}, 2000);
}
// Создание брызг крови
function createBloodSplatters() {
const bloodSplatter = document.getElementById('bloodSplatter');
bloodSplatter.innerHTML = '';
// Создаем 30 капель крови разного размера
for (let i = 0; i < 30; i++) {
const drop = document.createElement('div');
drop.classList.add('blood-drop');
// Случайный размер
const size = Math.random() * 20 + 5;
drop.style.width = `${size}px`;
drop.style.height = `${size}px`;
// Случайное положение
drop.style.left = `${Math.random() * 100}%`;
drop.style.top = `${Math.random() * 50}%`;
// Случайная задержка анимации
drop.style.animationDelay = `${Math.random() * 1.5}s`;
bloodSplatter.appendChild(drop);
}
}
// Сохранение результата
function saveResult(username, wpm, accuracy) {
fetch('/save_result', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: username,
wpm: wpm,
accuracy: accuracy
})
})
.then(response => response.json())
.then(data => console.log('Result saved:', data))
.catch(error => console.error('Error saving result:', error));
}
// Обработка ввода
inputArea.addEventListener('input', function(e) {
if (!gameActive) return;
const inputValue = e.target.value;
const currentChar = text[currentPosition];
// Проверяем, правильно ли введен символ
if (inputValue.charAt(inputValue.length - 1) === currentChar) {
// Правильный символ
const spans = textDisplay.querySelectorAll('span');
spans[currentPosition].classList.remove('current');
spans[currentPosition].classList.add('correct');
currentPosition++;
totalChars++;
// Если есть следующий символ, делаем его текущим
if (currentPosition < text.length) {
spans[currentPosition].classList.add('current');
} else {
// Текст закончился, завершаем игру
endGame(true);
}
} else {
// Неправильный символ
mistakes++;
totalChars++;
const spans = textDisplay.querySelectorAll('span');
spans[currentPosition].classList.add('incorrect');
}
// Обновляем статистику
updateStats();
});
// Обработчики кнопок
startBtn.addEventListener('click', startGame);
restartBtn.addEventListener('click', startGame);
// Инициализация
timeDisplay.textContent = timeLimit;
});