翼度科技»论坛 编程开发 html5 查看内容

记录--Canvas实现打飞字游戏

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助



打开游戏界面,看到一个画面简洁、却又富有挑战性的游戏。屏幕上,有一个白色的矩形框,里面不断下落着各种单词,而我需要迅速地输入这些单词。如果我输入的单词与屏幕上的单词匹配,那么我就可以获得得分;如果我输入的单词错误或者时间过长,那么我就会输掉游戏。游戏的节奏非常快,每当我输入一个单词,屏幕上就会有新的单词出现,让我不能有丝毫的懈怠。
在游戏中,我不断地挑战自己,不断地提高自己的打字速度和准确性。经过一段时间的练习,我发现我的打字速度和准确性都有了显著的提高,这让我非常开心。
一、游戏介绍

打字游戏使用Canvas和JavaScript实现。游戏的核心玩法是,玩家需要在字母下落到底部之前输入相应的单词。如果玩家输入正确,就会得到相应的分数。游戏中包含了许多有趣的功能,如随机生成单词、单词下落、单词匹配、得分计算等等。此外,游戏设计还考虑到了玩家的游戏体验,如游戏难度的调整、游戏音效的设置等等。如果你喜欢挑战和打字游戏,那么这款游戏一定不容错过!
二、效果预览

体验链接:打飞字游戏 - 码上掘金 (juejin.cn)

三、实现思路

在实现游戏时,主要包括以下几个部分:

  • 随机生成单词
  • 添加新的单词
  • 更新画面
  • 画出单词
  • 处理已输入单词
  • 处理未输入单词
  • 重置游戏
具体实现可以参考代码中的注释。
1. 搭建页面结构

使用Canvas和JavaScript实现的打字游戏的HTML模板。在这个HTML模板中,我们使用了canvas元素来显示游戏画面。此外,我们还添加了一个得分标签、一个文本输入框和一个重置游戏按钮。在游戏开始时,用户需要点击文本输入框并输入单词。如果输入的单词与下落的单词匹配,则会得到相应的分数。如果下落的单词没有被输入,则游戏结束。用户可以通过点击重置游戏按钮重新开始游戏。
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <title>Canvas打字游戏</title>
  5.     <meta charset="UTF-8">
  6. </head>
  7. <body>
  8.     <canvas id="gameCanvas" width="500" height="400"></canvas>
  9.     <p>得分: <span id="score">0</span></p>
  10.     <input type="text" id="userInput" autofocus>
  11.     <button id="resetButton">重新开始</button>
  12. </body>
  13. </html>
复制代码
2. 美化界面
  1. canvas {
  2.   border: 1px solid black;
  3. }
  4. body {
  5.   display: flex;
  6.   flex-direction: column;
  7.   align-items: center;
  8. }
  9. #gameCanvas {
  10.   margin: 20px;
  11. }
  12. input[type=text] {
  13.   margin: 20px;
  14.   font-size: 20px;
  15.   padding: 10px;
  16.   border: none;
  17.   border-bottom: 2px solid gray;
  18. }
  19. #score {
  20.   font-size: 20px;
  21.   margin: 20px;
  22. }
  23. #resetButton {
  24.   margin: 20px;
  25.   font-size: 20px;
  26.   padding: 10px;
  27.   border: none;
  28.   background-color: #4CAF50;
  29.   color: white;
  30.   border-radius: 5px;
  31. }
  32. #resetButton:hover {
  33.   background-color: #3E8E41;
  34. }
复制代码
3. 编写JavaScript代码

对于js代码的编写,我用ES6的class语法来进行编写。使用ES6中的class语法来定义一个游戏类,能够利用class语法的面向对象特性来进行游戏逻辑的封装和组织。使用class语法可以更加清晰地表达游戏的结构和关系,将游戏的各个部分封装在一个类中,可以更加方便地管理和维护代码。
同时,使用class语法还可以更加方便地进行继承和多态的操作,方便扩展和重用代码。在实现游戏时,可能会有不同的游戏模式,或者需要对游戏进行一些特殊的调整。使用class语法可以更加便捷地扩展和修改游戏的逻辑,提高代码的可维护性和可扩展性。
还可以更加方便地进行代码的组织和管理。游戏逻辑封装在一个类中,可以更加清晰地表达游戏的结构和关系,方便代码的组织和管理。同时还可以更加方便地进行代码的测试和调试,提高代码的质量和可靠性。
  1. class TypingGame {
  2.   constructor() {
  3.     this.canvas = document.getElementById("gameCanvas");
  4.     this.context = this.canvas.getContext("2d");
  5.     this.gameStatus = 'looping' // 游戏状态,初始值为 'looping'
  6.     this.blinkInterval = null;
  7.     this.score = 0 // 得分,初始值为 0
  8.     this.wordList = [];
  9.     this.SPEED = 1; // 字符下落速度
  10.     this.ANGLE = Math.PI / 2;
  11.     this.words = ['apple', 'orange', 'banana', 'pear', 'grape'];
  12.     this.userInput = document.getElementById("userInput");
  13.     this.resetButton = document.getElementById("resetButton");
  14.     this.addNewWord = this.addNewWord.bind(this);
  15.     this.handleKeyPress = this.handleKeyPress.bind(this);
  16.     this.resetGame = this.resetGame.bind(this);
  17.     this.update = this.update.bind(this);
  18.     this.drawWord = this.drawWord.bind(this);
  19.     this.handleWordMatch = this.handleWordMatch.bind(this);
  20.     this.handleWordMiss = this.handleWordMiss.bind(this);
  21.     this.init();
  22.   }
  23.   /**
  24.    * 初始化游戏
  25.    */
  26.   init() {
  27.     // 随机生成一些单词
  28.     this.generateRandomWords();
  29.     // 绑定键盘输入事件
  30.     this.userInput.addEventListener("keypress", this.handleKeyPress);
  31.     // 绑定重置游戏按钮点击事件
  32.     this.resetButton.addEventListener("click", this.resetGame);
  33.     // 添加第一个单词
  34.     this.addNewWord();
  35.     // 开始游戏循环
  36.     this.update();
  37.   }
  38.   /**
  39.    * 随机生成一些单词
  40.    */
  41.   generateRandomWords() {
  42.     for (let i = 0; i < 100; i++) {
  43.       // 随机生成一个指定长度的单词
  44.       const word = this.getRandomString(Math.floor(Math.random() * 7) + 3);
  45.       this.words.push(word);
  46.     }
  47.   }
  48.   /**
  49.    * 随机生成一个字母
  50.    */
  51.   getRandomLetter() {
  52.     const letters = "abcdefghijklmnopqrstuvwxyz";
  53.     const index = Math.floor(Math.random() * letters.length);
  54.     return letters[index];
  55.   }
  56.   /**
  57.    * 随机生成一个指定长度的单词
  58.    */
  59.   getRandomString(length) {
  60.     let result = "";
  61.     for (let i = 0; i < length; i++) {
  62.       result += this.getRandomLetter();
  63.     }
  64.     return result;
  65.   }
  66.   /**
  67.    * 添加新的单词
  68.    */
  69.   addNewWord() {
  70.     // 获取单词的宽度
  71.     const wordWidth = this.context.measureText(this.getRandomWord()).width;
  72.     const word = {
  73.       word: this.getRandomWord(),
  74.       x: Math.max(wordWidth, Math.random() * (this.canvas.width - wordWidth)),
  75.       y: 0,
  76.       angle: this.ANGLE,
  77.     };
  78.     this.wordList.push(word);
  79.   }
  80.   /**
  81.    * 随机获取一个单词
  82.    */
  83.   getRandomWord() {
  84.     const index = Math.floor(Math.random() * this.words.length);
  85.     return this.words[index];
  86.   }
  87.   /**
  88.    * 更新画面
  89.    */
  90.   update() {
  91.     if (this.gameStatus !== 'looping') return;
  92.     // 清空画布
  93.     this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  94.     this.wordList.forEach((word, i) => {
  95.       word.y += this.SPEED;
  96.       word.x += Math.sin(word.angle);
  97.       word.angle += Math.random() * 0.1 - 0.05;
  98.       const x = word.x - this.context.measureText(word.word).width / 2;
  99.       // 画出单词
  100.       this.drawWord(word.word, x, word.y);
  101.       if (word.x < 0 || word.x > this.canvas.width) {
  102.         word.angle = -word.angle;
  103.       }
  104.       if (word.y > this.canvas.height) {
  105.         // 处理未输入单词
  106.         this.handleWordMiss(word);
  107.         this.wordList.splice(i, 1);
  108.         // 添加新的单词
  109.         this.addNewWord();
  110.       }
  111.     });
  112.     // 请求下一帧动画
  113.     requestAnimationFrame(this.update);
  114.   }
  115.   /**
  116.    * 画出单词
  117.    */
  118.   drawWord(word, x, y) {
  119.     this.context.font = "30px Arial";
  120.     this.context.fillText(word, x, y);
  121.   }
  122.   /**
  123.    * 处理已输入单词
  124.    */
  125.   handleKeyPress(event) {
  126.     if (event.keyCode === 13) {
  127.       const userWord = this.userInput.value;
  128.       this.userInput.value = "";
  129.       this.wordList.forEach((word, idx) => {
  130.         if (word.word === userWord) {
  131.           // 处理已输入单词
  132.           this.handleWordMatch(word, idx);
  133.         }
  134.       });
  135.     }
  136.   }
  137.   /**
  138.    * 处理已输入单词
  139.    */
  140.   handleWordMatch(word, idx) {
  141.     // 增加得分
  142.     this.score++;
  143.     // 更新得分显示
  144.     document.getElementById("score").innerText = this.score;
  145.     const x = word.x - this.context.measureText(word.word).width / 2;
  146.     const y = word.y;
  147.     let isWhite = true;
  148.     let blinkCount = 0;
  149.     // 单词闪烁
  150.     this.blinkInterval = setInterval(() => {
  151.       if (isWhite) {
  152.         this.context.fillStyle = "white";
  153.       } else {
  154.         this.context.fillStyle = "black";
  155.       }
  156.       this.context.fillText(word.word, x, y);
  157.       isWhite = !isWhite;
  158.       blinkCount++;
  159.       if (blinkCount >= 10) {
  160.         this.context.fillStyle = "black";
  161.         this.context.fillText(word.word, x, y);
  162.         this.wordList.splice(idx, 1)
  163.         // 添加新的单词
  164.         this.addNewWord()
  165.         clearInterval(this.blinkInterval);
  166.       }
  167.     }, 100);
  168.   }
  169.   /**
  170.    * 处理未输入单词
  171.    */
  172.   handleWordMiss(word) {
  173.     if (word.y > this.canvas.height) {
  174.       clearInterval(this.blinkInterval);
  175.       this.gameStatus = 'pause';
  176.       this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  177.       this.context.font = "30px Arial";
  178.       let text =['你输了,你这个菜鸡,','恭喜你,虽败犹荣,','真棒,我的宝子厉害,']
  179.       let textSay=this.score>15?this.score>50?text[2]:text[1]:text[0];
  180.       this.context.fillText(`${textSay}分数${this.score}分`, this.canvas.width / 2 - 180, this.canvas.height / 2);
  181.     }
  182.   }
  183.   /**
  184.    * 重置游戏
  185.    */
  186.   resetGame() {
  187.     this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  188.     // 开始游戏循环
  189.     requestAnimationFrame(this.update);
  190.     clearInterval(this.blinkInterval);
  191.     this.gameStatus='looping';
  192.     this.score = 0;
  193.     // 更新得分显示
  194.     document.getElementById("score").innerText = this.score;
  195.     this.wordList = [];
  196.     // 添加新的单词
  197.     this.addNewWord();
  198.   }
  199. }
  200. const typingGame = new TypingGame();
复制代码
TypingGame类是整个游戏的核心。在constructor方法中,首先初始化了一些游戏状态和相关的变量,然后调用了init方法,对游戏进行初始化。在init方法中,定义了一些事件处理方法,如键盘输入事件处理方法、重置游戏按钮点击事件处理方法等等。在init方法中,还调用了addNewWord方法,添加了第一个单词,并且开始游戏循环。在update方法中,主要是更新画面的逻辑,如清空画布、画出单词、处理已输入单词、处理未输入单词等等。在resetGame方法中,主要是重置游戏的状态,如清空画布、得分归零、添加新的单词等等。
整个游戏的实现比较简单,主要是依赖于Canvas和JavaScript。游戏中使用了一些Canvas的API,如context.fillText()方法、context.clearRect()方法等等,同时还使用了一些JavaScript的语言特性,如类、箭头函数等等。如果你对游戏的实现过程感兴趣,可以参考代码中的注释,了解游戏中每个方法的具体实现细节。
四、写在最后

Canvas和JavaScript看似平凡无奇,却能够创造出令人惊叹的数字世界。在这个数字化时代,掌握这些工具已经成为了一种竞争优势。本篇文章将带领读者一起探索Canvas和JavaScript的世界,通过实现一个打字游戏,领略这些工具的神奇之处。
游戏的实现并不复杂,但却需要运用许多Canvas的API和JavaScript的语言特性。通过随机生成单词、让单词下落、根据用户输入判断单词是否匹配等等,我们成功实现了一个简单而有趣的游戏。在实现游戏的过程中,我们也学习了一些Canvas的API和JavaScript的语言特性,例如类、箭头函数等等。
本文转载于:

https://juejin.cn/post/7217704608034193468

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 


来源:https://www.cnblogs.com/smileZAZ/p/17283712.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具