Projete um jogo de teste de velocidade de digitação usando JavaScript
Um teste de digitação é projetado para descobrir com que rapidez alguém digita em um determinado período de tempo. Estaremos projetando um jogo de digitação em JavaScript que apresenta um desafio de digitação simples e encontra o desempenho da digitação calculando os caracteres por minuto (CPM), palavras por minuto (WPM) e a precisão dos caracteres digitados.
O jogo mostra uma série de citações que devem ser digitadas em um determinado limite de tempo, o mais rápido possível. Uma velocidade de digitação mais alta mostraria um valor de WPM mais alto. Os caracteres digitados incorretamente seriam marcados de acordo durante a digitação.
Vamos criar o layout HTML primeiro, estilizá-lo usando CSS e, em seguida, escrever a lógica em JavaScript.
O Layout HTML: O layout HTML define a estrutura do elemento que seria mostrado na página. Isso inclui:
- Parte do cabeçalho: Esta seção mostra as estatísticas da sessão de digitação atual. Isso inclui a exibição do tempo restante, número de erros, precisão, WPM e CPM.
- Seção de Citação: Esta seção mostra o texto atual que deve ser digitado na área de entrada.
- Área de entrada: esta seção contém a área de entrada onde o texto deve ser digitado.
- Botão de reinicialização: Este é o botão de reinicialização que será mostrado quando o tempo acabar e o jogo terminar.
- Código:
<
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
>
Nota: Cada uma das partes é preenchida com dados fictícios para tornar o estilo mais fácil. O código HTML acima é o seguinte.
O estilo CSS: CSS é usado para estilizar as diferentes partes e torná-las mais visualmente atraentes.
- A parte do cabeçalho é exibida usando o layout flexível.
- Preenchimento e margem adequados são dados a cada elemento.
- O tamanho do texto de cada elemento é de fácil leitura pelo usuário durante o jogo.
- Duas classes adicionais são definidas para denotar as letras digitadas corretamente ou incorretamente. Essas classes seriam adicionadas ou removidas dinamicamente quando necessário.
- Código:
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;
}
O resultado do layout HTML e estilo CSS seria assim:
Lógica principal do jogo: A lógica principal do jogo é definida em um arquivo JavaScript. Existem várias funções que funcionam juntas para executar o jogo.
Etapa 1: Seleção de todos os elementos e definição de variáveis
Os elementos necessários no layout HTML são selecionados primeiro usando o querySelector()
método. Eles recebem nomes de variáveis para que possam ser facilmente acessados e modificados. Outras variáveis que seriam acessadas ao longo do programa também são definidas no início.
// 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;
Etapa 2: Preparando o texto a ser exibido
updateQuote()
É definida uma função que lida com as seguintes coisas:
- Obtendo o texto As
citações têm sido usadas como o texto que deve ser digitado para jogar o jogo. Cada citação é obtida uma a uma de uma matriz predefinida. Uma variável rastreia o índice de cotação atual e o incrementa sempre que um novo é solicitado. - Dividindo os caracteres em elementos
Cada um dos caracteres do texto é separado em uma série de<span>
elementos. Isso torna possível alterar individualmente a cor de cada caractere, dependendo se ele foi digitado corretamente pelo usuário. Esses elementos são anexados a uma variávelquote_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;
}
Etapa 3: Obter o texto digitado atualmente pelo usuário
processCurrentText()
É definida uma função que será chamada sempre que o usuário digitar ou alterar qualquer coisa na caixa de entrada. Portanto, é usado com o oninput
manipulador de eventos da caixa de entrada. Esta função lida com o seguinte:
- Obtendo o valor atual da caixa de entrada
Avalue
propriedade da área de entrada é usada para obter o texto atual digitado pelo usuário. Ele é dividido em uma matriz de caracteres para comparar com o texto de citação. Isso é armazenado emcurr_input_array
. - Colorindo os caracteres do texto da citação
Os caracteres da citação exibida são coloridos de 'vermelho' ou 'verde', dependendo se ela foi digitada corretamente. Isso é feito selecionando os elementos span da citação que criamos anteriormente e percorrendo-os. O elemento então aplicou as classes criadas acima dependendo se ele corresponde ao texto digitado. - Calculando os erros e a precisão
Cada vez que o usuário comete um erro durante a digitação, aerrors
variável é incrementada. Isso é usado para calcular o valor de precisão, dividindo o número de caracteres digitados corretamente pelo número total de caracteres digitados pelo usuário. - Movendo para a próxima citação
Quando o comprimento do texto de entrada corresponde ao comprimento do texto da citação, aupdateQuote()
função é chamada, o que altera a citação e limpa a área de entrada. O número total de erros também é atualizado para ser usado na próxima cotação.
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 = "";
}
}
A coloração dos personagens baseou sua correção
Etapa 4: Iniciando um novo jogo
startGame()
É definida uma função que será chamada quando o usuário focar na caixa de entrada. Portanto, é usado com o onfocus
manipulador de eventos da caixa de entrada. Esta função lida com o seguinte:
- Redefinir todos os valores
Todos os valores são redefinidos para os valores padrão antes do início de um novo jogo. Criamos uma função diferente chamadaresetValues()
que trata disso. - Atualizar o texto da cotação
Um novo texto da cotação é preparado e exibido chamando aupdateQuote()
função. - Criando um novo cronômetro
Um cronômetro registra o número de segundos restantes e o exibe para o usuário. Ele é criado usando osetInterval()
método que chama repetidamente aupdateTimer()
função definida abaixo. Antes de criar um novo cronômetro, a instância anterior do cronômetro é apagada usandoclearInterval()
.
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";
}
Etapa 5: Atualizar o cronômetro
updateTimer()
É definida uma função que será chamada a cada segundo para controlar o tempo. Esta função lida com o seguinte:
- Atualizar os valores de tempo
Todas as variáveis que controlam o tempo são atualizadas. OtimeLeft
valor é decrementado, otimeElapsed
valor é incrementado e o texto do cronômetro é atualizado para o tempo restante atual. - Terminando o jogo
Esta parte é acionada quando o tempo limite é atingido. Ele chama afinishGame()
função definida abaixo que termina o jogo.
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();
}
}
Etapa 6: Finalizando o jogo
finishGame()
É definida uma função que será invocada quando o jogo tiver que ser finalizado. Esta função lida com o seguinte:
- Excluindo o cronômetro
A instância do cronômetro criada antes é removida. - Exibindo o texto e o botão de reinicialização do jogo
O texto citado exibido ao usuário é alterado para um que indica que o jogo acabou. O botão 'Reiniciar' também é exibido definindo a propriedade de exibição para 'bloquear'. - Calculando o CPM e WPM da sessão atual
- O número de caracteres por minuto (CPM) é calculado dividindo-se o número total de caracteres digitados com o tempo decorrido e multiplicando o resultado por 60. É arredondado para evitar pontos decimais.
- As palavras por minuto (WPM) são calculadas dividindo o CPM por 5 e multiplicando o resultado por 60. O 5 denota o número médio de caracteres por palavra. É arredondado para evitar casas decimais.
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";
}
Demonstração Final
O jogo agora está pronto para ser jogado em qualquer navegador.
Código-fonte: https://github.com/sayantanm19/js-simple-typing-game
As postagens do blog Acervo Lima te ajudaram? Nos ajude a manter o blog no ar!
Faça uma doação para manter o blog funcionando.
70% das doações são no valor de R$ 5,00...
Diógenes Lima da Silva