JavaScript设计打字速度测试游戏的实现

家住魔仙堡 提交于 2021-02-16 12:33:43

英文 | https://www.geeksforgeeks.org/design-a-typing-speed-test-game-using-javascript/?ref=leftbar-rightbar

翻译 | web前端开发(ID:web_qdkf)


打字测试的目的是找出在给定的时间内打字的速度。我们将使用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用于对不同部分进行样式设置,并使其在视觉上更具吸引力。
  • 标题部分使用flex布局显示。

  • 给每个元素足够的填充和边距。

  • 每个元素的文本大小应使用户在玩游戏时易于阅读。

  • 定义了两个附加类来表示正确或错误键入的字母。这些类将在需要时动态添加或删除。

代码:
   
     
   
   
   
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: 选择所有元素并定义变量
首先使用querySelector()方法选择HTML布局中的必需元素。为它们分配了变量名,以便可以轻松访问和修改它们。开头还将定义在整个程序中将要访问的其他变量。
   
     
   
   
   
// 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输入框的事件处理程序一起使用。此函数处理以下事情:
  • 获取输入框的当前值输入区域value属性用于获取用户输入的当前文本。这被拆分为一个字符数组以与报价文本进行比较。这存储在中curr_input_array

  • 为引用文本的字符着色,根据所输入引用的字符是否正确,将其显示为“红色”或“绿色”。这是通过选择我们之前创建的报价的span元素并循环遍历它们来完成的。然后,元素将根据是否与键入的文本匹配来应用上面创建的类。

  • 计算错误和准确性
    每次用户在输入过程中输入错误时,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输入框的事件处理程序一起使用。此函数处理以下事情:
  • 重置所有值
    在开始新游戏之前,所有值都将重置为其默认值。我们创建一个名为的不同函数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()定义了一个功能,当必须完成游戏时将调用该功能。此函数处理以下事情:
  • 删除计时器
    之前创建的计时器实例将被删除。

  • 显示重新启动游戏的文本和按钮
    显示给用户的引用文本将更改为表示游戏结束的文本。通过将显示属性设置为“阻止”,还可以显示“重新启动”按钮。

  • 计算当前会话的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"; }
最后效果
现在可以在任何浏览器中玩游戏了,截图如下:


本文分享自微信公众号 - web前端开发(web_qdkf)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!