Создайте игру для теста скорости набора текста с помощью JavaScript

Опубликовано: 5 Января, 2022

Тест на набор текста предназначен для определения того, насколько быстро человек печатает за заданный промежуток времени. Мы будем разрабатывать игру с набором текста с использованием JavaScript, которая представляет собой простую задачу набора текста и определяет производительность набора путем расчета символов в минуту (CPM), слов в минуту (WPM) и точности набранных символов.

Игра показывает серию цитат, которые необходимо ввести в указанный срок и как можно быстрее. Чем выше скорость набора текста, тем выше значение WPM. Неправильно набранные символы будут соответствующим образом отмечены во время набора.

Сначала мы создадим HTML-макет, стилизуем его с помощью CSS, а затем напишем логику на JavaScript.
Макет HTML: макет HTML определяет структуру элементов, которые будут отображаться на странице. Это включает:

  • Заголовок: в этом разделе отображается статистика текущего сеанса набора текста. Это включает отображение оставшегося времени, количества ошибок, точности, WPM и CPM.
  • Раздел цитат: в этом разделе отображается текущий текст, который необходимо ввести в область ввода.
  • Область ввода: этот раздел содержит область ввода, в которой необходимо ввести текст.
  • Кнопка перезапуска: это кнопка перезапуска, которая будет отображаться, когда время истечет и игра закончится.
  • Код:
    < html lang = "en" >
    < head >
    < title >Simple Speed Typer</ title >
    <!-- link the CSS file here -->
    < link rel = "stylesheet" href = "style.css" >
    </ head >
    < body >
    < div class = "container" >
    < div class = "heading" >
    Simple Speed Typing
    </ div >
    < div class = "header" >
    < div class = "wpm" >
    < div class = "header_text" >WPM</ div >
    < div class = "curr_wpm" >100</ div >
    </ div >
    < div class = "cpm" >
    < div class = "header_text" >CPM</ div >
    < div class = "curr_cpm" >100</ div >
    </ div >
    < div class = "errors" >
    < div class = "header_text" >Errors</ div >
    < div class = "curr_errors" >0</ div >
    </ div >
    < div class = "timer" >
    < div class = "header_text" >Time</ div >
    < div class = "curr_time" >60s</ div >
    </ div >
    < div class = "accuracy" >
    < div class = "header_text" >% Accuracy</ div >
    < div class = "curr_accuracy" >100</ div >
    </ div >
    </ div >
    < div class = "quote" >
    Click on the area below to start the game.
    </ div >
    < textarea class = "input_area"
    placeholder = "start typing here..."
    oninput = "processCurrentText()"
    onfocus = "startGame()" >
    </ textarea >
    < button class = "restart_btn"
    onclick = "resetValues()" >
    Restart
    </ button >
    </ div >
    <!-- link the JavaScript file here -->
    < script src = "game.js" >
    </ script >
    </ body >
    </ html >

Примечание. Каждая часть заполнена фиктивными данными, чтобы упростить стилизацию. HTML-код вышеизложенного выглядит следующим образом.

Стили CSS: CSS используется для стилизации различных частей и придания им большей визуальной привлекательности.

  • Часть заголовка отображается с использованием гибкого макета.
  • Каждому элементу даны соответствующие отступы и поля.
  • Размер текста каждого элемента таков, что он легко читается пользователем во время игры.
  • Два дополнительных класса определены для обозначения букв, которые набираются правильно или неправильно. Эти классы будут динамически добавляться или удаляться при необходимости.
  • Код:
    body {
    background-color: #fe9801;
    color: black;
    text-align: center;
    }
    .container {
    display: flex;
    flex-direction: column;
    align-items: center;
    }
    .heading {
    margin-bottom: 20px;
    font-size: 3rem;
    color: black;
    }
    .header {
    display: flex;
    align-items: center;
    }
    .timer, .errors, .accuracy,
    .cpm, .wpm {
    background-color: #ccda46;
    height: 60px;
    width: 70px;
    margin: 8px;
    padding: 12px;
    border-radius: 20%;
    box-shadow: black 5px 8px 5px;
    }
    .cpm, .wpm {
    display: none;
    }
    .header_text {
    text-transform: uppercase;
    font-size: 0.6rem;
    font-weight: 600;
    }
    .curr_time, .curr_errors,
    .curr_accuracy, .curr_cpm,
    .curr_wpm {
    font-size: 2.75rem;
    }
    .quote {
    background-color: #ccda46;
    font-size: 1.5rem;
    margin: 10px;
    padding: 25px;
    box-shadow: black 5px 8px 5px;
    }
    .input_area {
    background-color: #f5f5c6;
    height: 80px;
    width: 40%;
    font-size: 1.5rem;
    font-weight: 600;
    margin: 15px;
    padding: 20px;
    border: 0px;
    box-shadow: black 5px 8px 5px;
    }
    .restart_btn {
    display: none;
    background-color: #326765;
    font-size: 1.5rem;
    padding: 10px;
    border: 0px;
    box-shadow: black 5px 8px 5px;
    }
    .incorrect_char {
    color: red;
    text-decoration: underline;
    }
    .correct_char {
    color: darkgreen;
    }

Результат макета HTML и стиля CSS будет выглядеть следующим образом:

Основная логика игры: Основная логика игры определяется в файле JavaScript. Есть несколько функций, которые работают вместе для запуска игры.

Шаг 1. Выбор всех элементов и определение переменных

Необходимые элементы в макете HTML сначала выбираются с помощью метода querySelector() Им присваиваются имена переменных, чтобы к ним можно было легко получить доступ и изменить. Другие переменные, к которым будет осуществляться доступ во всей программе, также определены в начале.

// define the time limit
let TIME_LIMIT = 60;
// define quotes to be used
let quotes_array = [
"Push yourself, because no one else is going to do it for you." ,
"Failure is the condiment that gives success its flavor." ,
"Wake up with determination. Go to bed with satisfaction." ,
"It's going to be hard, but hard does not mean impossible." ,
"Learning never exhausts the mind." ,
"The only way to do great work is to love what you do."
];
// selecting required elements
let timer_text = document.querySelector( ".curr_time" );
let accuracy_text = document.querySelector( ".curr_accuracy" );
let error_text = document.querySelector( ".curr_errors" );
let cpm_text = document.querySelector( ".curr_cpm" );
let wpm_text = document.querySelector( ".curr_wpm" );
let quote_text = document.querySelector( ".quote" );
let input_area = document.querySelector( ".input_area" );
let restart_btn = document.querySelector( ".restart_btn" );
let cpm_group = document.querySelector( ".cpm" );
let wpm_group = document.querySelector( ".wpm" );
let error_group = document.querySelector( ".errors" );
let accuracy_group = document.querySelector( ".accuracy" );
let timeLeft = TIME_LIMIT;
let timeElapsed = 0;
let total_errors = 0;
let errors = 0;
let accuracy = 0;
let characterTyped = 0;
let current_quote = "" ;
let quoteNo = 0;
let timer = null ;

Шаг 2: Подготовка текста для отображения

Определена функция updateQuote() которая обрабатывает следующие вещи:

  • Получение текста
    Цитаты использовались в качестве текста, который нужно набирать, чтобы играть в игру. Каждая цитата берется одна за другой из предопределенного массива. Переменная отслеживает текущий индекс котировки и увеличивает его при каждом запросе нового.
  • Разбиение персонажей на элементы
    Каждый из символов в тексте разделен на серию элементов <span> . Это позволяет индивидуально изменять цвет каждого символа в зависимости от того, правильно ли он набран пользователем. Эти элементы добавляются к переменной quote_text .
function updateQuote() {
quote_text.textContent = null ;
current_quote = quotes_array[quoteNo];
// separate each character and make an element
// out of each of them to individually style them
current_quote.split( '' ).forEach(char => {
const charSpan = document.createElement( 'span' )
charSpan.innerText = char
quote_text.appendChild(charSpan)
})
// roll over to the first quote
if (quoteNo < quotes_array.length - 1)
quoteNo++;
else
quoteNo = 0;
}

Шаг 3. Получение пользователем текста, набранного в данный момент.

Определена функция processCurrentText() которая будет вызываться всякий раз, когда пользователь вводит или изменяет что-либо в поле ввода. Следовательно, он используется с oninput события oninput поля ввода. Эта функция обрабатывает следующие вещи:

  • Получение текущего значения поля ввода
    Свойство value области ввода используется для получения текущего текста, вводимого пользователем. Он разбивается на массив символов для сравнения с текстом цитаты. Это хранится в curr_input_array .
  • Раскрашивание символов текста цитаты
    Символы отображаемой цитаты окрашиваются в красный или зеленый цвет в зависимости от того, правильно ли она набрана. Для этого нужно выбрать элементы диапазона цитаты, которую мы создали ранее, и просмотреть их в цикле. Затем элемент применил классы, созданные выше, в зависимости от того, соответствует ли он набранному тексту.
  • Расчет погрешностей и точности
    Каждый раз, когда пользователь делает ошибку во время набора текста, errors увеличивается. Это используется для расчета значения точности путем деления количества правильно набранных символов на общее количество символов, набранных пользователем.
  • Переход к следующей цитате
    Когда длина вводимого текста совпадает с длиной текста цитаты, updateQuote() которая изменяет цитату и очищает область ввода. Количество общих ошибок также обновляется для использования в следующей расценке.
function processCurrentText() {
  
  // get current input text and split it
  curr_input = input_area.value;
  curr_input_array = curr_input.split("");
  
  // increment total characters typed
  characterTyped++;
  
  errors = 0;
  
  quoteSpanArray = quote_text.querySelectorAll("span");
  quoteSpanArray.forEach((char, index) => {
    let typedChar = curr_input_array[index]
  
    // character not currently typed
    if (typedChar == null) {
      char.classList.remove("correct_char");
      char.classList.remove("incorrect_char");
  
      // correct character
    } else if (typedChar === char.innerText) {
      char.classList.add("correct_char");
      char.classList.remove("incorrect_char");
  
      // incorrect character
    } else {
      char.classList.add("incorrect_char");
      char.classList.remove("correct_char");
  
      // increment number of errors
      errors++;
    }
  });
  
  // display the number of errors
  error_text.textContent = total_errors + errors;
  
  // update accuracy text
  let correctCharacters = (characterTyped - (total_errors + errors));
  let accuracyVal = ((correctCharacters / characterTyped) * 100);
  accuracy_text.textContent = Math.round(accuracyVal);
  
  // if current text is completely typed
  // irrespective of errors
  if (curr_input.length == current_quote.length) {
    updateQuote();
  
    // update total errors
    total_errors += errors;
  
    // clear the input area
    input_area.value = "";
  }
}

Шаг 4: Запуск новой игры

Определена функция startGame() которая будет вызываться, когда пользователь фокусируется на поле ввода. Следовательно, он используется с onfocus событий onfocus поля ввода. Эта функция обрабатывает следующие вещи:

  • Сбросить все значения
    Все значения сбрасываются до значений по умолчанию перед началом новой игры. Мы создаем другую функцию с именем resetValues() которая этим занимается.
  • Обновить текст цитаты
    Новый текст цитаты подготавливается и отображается путем вызова функции updateQuote() .
  • Создание нового таймера
    Таймер отслеживает количество оставшихся секунд и отображает его пользователю. Он создается с помощью setInterval() который многократно вызывает updateTimer() определенную ниже. Перед созданием нового таймера предыдущий экземпляр таймера очищается с помощью clearInterval() .
function startGame() {
resetValues();
updateQuote();
// clear old and start a new timer
clearInterval(timer);
timer = setInterval(updateTimer, 1000);
}
function resetValues() {
timeLeft = TIME_LIMIT;
timeElapsed = 0;
errors = 0;
total_errors = 0;
accuracy = 0;
characterTyped = 0;
quoteNo = 0;
input_area.disabled = false ;
input_area.value = "" ;
quote_text.textContent = 'Click on the area below to start the game.' ;
accuracy_text.textContent = 100;
timer_text.textContent = timeLeft + 's' ;
error_text.textContent = 0;
restart_btn.style.display = "none" ;
cpm_group.style.display = "none" ;
wpm_group.style.display = "none" ;
}

Шаг 5: Обновление таймера

Определена функция updateTimer() которая будет вызываться каждую секунду для отслеживания времени. Эта функция обрабатывает следующие вещи:

  • Обновите значения времени
    Все переменные, которые отслеживают время, обновляются. Значение timeLeft уменьшается, timeElapsed увеличивается, а текст таймера обновляется до текущего оставшегося времени.
  • Завершение игры
    Эта часть запускается при достижении лимита времени. Он вызывает finishGame() определенную ниже, которая завершает игру.
function updateTimer() {
if (timeLeft > 0) {
// decrease the current time left
timeLeft--;
// increase the time elapsed
timeElapsed++;
// update the timer text
timer_text.textContent = timeLeft + "s" ;
}
else {
// finish the game
finishGame();
}
}

Шаг 6: завершение игры

Определена функция finishGame() которая будет вызываться, когда игра должна быть завершена. Эта функция обрабатывает следующие вещи:

  • Удаление таймера
    Созданный ранее экземпляр таймера удаляется.
  • Отображение текста и кнопки перезапуска игры
    Цитируемый текст, отображаемый для пользователя, изменяется на текст, указывающий на то, что игра окончена. Кнопка «Перезагрузка» также отображается, если для свойства display установлено значение «block».
  • Расчет CPM и WPM текущего сеанса
    1. Число символов в минуту (CPM) рассчитывается путем деления общего количества набранных символов на прошедшее время и последующего умножения результата на 60. Оно округляется во избежание запятой.
    2. Количество слов в минуту (WPM) рассчитывается путем деления CPM на 5 и последующего умножения результата на 60. 5 обозначает среднее количество символов в слове. Оно округлено, чтобы не было десятичных знаков.
function finishGame() {
// stop the timer
clearInterval(timer);
// disable the input area
input_area.disabled = true ;
// show finishing text
quote_text.textContent = "Click on restart to start a new game." ;
// display restart button
restart_btn.style.display = "block" ;
// calculate cpm and wpm
cpm = Math.round(((characterTyped / timeElapsed) * 60));
wpm = Math.round((((characterTyped / 5) / timeElapsed) * 60));
// update cpm and wpm text
cpm_text.textContent = cpm;
wpm_text.textContent = wpm;
// display the cpm and wpm
cpm_group.style.display = "block" ;
wpm_group.style.display = "block" ;
}

Заключительная демонстрация

Теперь игра готова к игре в любом браузере.

Исходный код: https://github.com/sayantanm19/js-simple-typing-game