" />

飞道的博客

JavaScript 练手小技巧:打字小游戏

491人阅读  评论(0)

 放假闲来无事,一群小屁孩想玩我的电脑。

字都不会打,还玩电脑。

用 js 写一个打字游戏,打不到 100 分,就不要玩我的电脑~~~!!!

整体界面如下所示,一切从简~

 HTML 结构


  
  1. <div id="box" class="box">
  2. <div class="tips">
  3. 击中数量: <span id="scoreSpan" style="margin-right: 20px;">0 </span>
  4. 失误: <span id="missSpan">0 </span>
  5. </div>
  6. <div class="container" id="container">
  7. </div>
  8. <!-- 游戏结束标签 -->
  9. <div class="gameover">
  10. <h1>游戏结束 </h1>
  11. <div class="overBtn">
  12. <button type="button" id="btn">重新开始 </button>
  13. </div>
  14. </div>
  15. </div>

div.container 是字母出现的区域,相对定位。

字母是 JS 动态生成的 span 标签,全部绝对定位。

div.gameover 是游戏结束时的画面,默认是隐藏的。当游戏结束的时候,给 div.box 添加一个类 over,才让 div.gameover 显示出来。

具体样式见下 CSS 样式部分。

CSS 样式


  
  1. *{
  2. margin: 0;
  3. padding: 0;
  4. }
  5. div .box{
  6. width: 100vw;
  7. height: 100vh;
  8. position: relative;
  9. background:center center url( "../images/mm.jpg") no-repeat;
  10. background-size: cover;
  11. }
  12. .tips{
  13. position: absolute;
  14. left: 20px;
  15. top: 20px;
  16. font-size: 20px;
  17. line-height: 40px;
  18. z-index: 2;
  19. }
  20. .tips span{
  21. font-size: 30px;
  22. color: #ff6600;
  23. vertical-align: middle;
  24. }
  25. .container{
  26. width: 100%;
  27. height: 100vh;
  28. position: relative;
  29. overflow: hidden;
  30. background: rgba( 255, 255, 255, 0.5);
  31. }
  32. .container span .zm{
  33. font-size: 40px;
  34. display: inline-block;
  35. padding: 5px 10px;
  36. height: 80px;
  37. line-height: 80px;
  38. overflow: hidden;
  39. position: absolute;
  40. }
  41. span .zm .shoot{
  42. animation: shootAni 0.2s;
  43. }
  44. @keyframes shootAni {
  45. 0%{
  46. opacity: 1;
  47. transform: scale( 1);
  48. }
  49. 100%{
  50. opacity: 0;
  51. transform: scale( 1.5);
  52. }
  53. }
  54. .gameover{
  55. position: absolute;
  56. left: 0;
  57. top: 0;
  58. background: rgba( 0, 0, 0, 0.5);
  59. bottom: 0;
  60. right: 0;
  61. text-align: center;
  62. display: none;
  63. }
  64. .over .gameover{
  65. display: block;
  66. }
  67. .over .gameover h1{
  68. padding-top: 40vh;
  69. margin-bottom: 40px;
  70. }
  71. .over .gameover button{
  72. cursor: pointer;
  73. width: 100px;
  74. height: 50px;
  75. }
  76. </style>

JavaScript 部分

字母是 26 个字母随机出现,因此利用一个字符串存储字母。

let zmStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

字母是随机生成的 span,span的内容就是随机字母。但是,字母不能跟已有的字母重复,因此要做一个重复性的判断。

判断的方式:先把已有的字母收集起来,形成一个字符串。随机字母的时候,就判断是否已经存在。如果存在,就重新随机选取字母。如果不存在,ok,就把这个字母放入span 中。


  
  1. // 随机生成字母
  2. let zmInStr = ""; // 已有的字母
  3. for( let i= 0; i<=container. children. length- 1; i++){
  4. zmInStr += container. children[i]. innerText ;
  5. }
  6. let zmNow = zmStr[ Math. floor( Math. random()*zmStr. length) ];
  7. // 防止字母重复
  8. while( zmInStr. indexOf(zmNow) >= 0){
  9. zmNow = zmStr[ Math. floor( Math. random()*zmStr. length) ]
  10. }
  11. span. innerText = zmNow;

每个生成的字母,也就是 span,它的位置,速度都是随机的。


  
  1. span. style. fontSize = ( Math. random()* 50+ 30)+ "px";
  2. span. style. color = fontColorArr[ Math. floor(fontColorArr. length* Math. random())];
  3. // 字母出现的位置
  4. span. style. left = ( 80+ Math. random()*(container. offsetWidth- 160)) + "px";
  5. span. style. top = `${60}px` ;
  6. // 每个字母设置下落速度
  7. span. speed = spDi+ Math. random()*spCtr;
  8. // 每个字母的下落距离
  9. span. dis = 0;

当字母被击中,会执行一个 animation 动画。动画结束后,该字母span标签要被删除。所以,字母的span标签需要监听 animationend 事件。


  
  1. // 添加动画事件
  2. span. addEventListener( "animationend", function ( ) {
  3. // 当 animation 动画结束后,移除该字母
  4. container. removeChild(span);
  5. });

下坠动画部分。

利用的是  requestAnimationFrame ,每次执行动画先遍历所有字母 span。

获取每个 span 的速度 speed 和 移动的距离 dis。在当前 dis 上添加 speed 值,实现位置变化。


  
  1. // 获取每个span的速度和位置
  2. let speed = Number(span. speed);
  3. let dis = Number(span. dis);
  4. span. style. top = `${dis+speed}px`;
  5. span. dis = `${dis+speed}`;

还要判断字母是否移动到了屏幕之外,这个时候说明字母没有被击中。要添加失误分。


  
  1. // 判断字母是否在外面。
  2. if( Number(span. dis) > Number(container. offsetHeight)+ 10){
  3. container. removeChild(span);
  4. createSpan();
  5. missScore++;
  6. missSpan. innerText = missScore;
  7. }

当失误分超过10分的时候,游戏结束。 


  
  1. // 判断游戏是否结束:失误超过10次
  2. if(missScore>= 10){
  3. cancelAnimationFrame(req);
  4. box. classList. add( "over");
  5. return ;
  6. }

当用户击打键盘的时候,要判断按下的键是否在已有的字母中。

因此,要遍历字母 span 标签,判断按键是否跟其中的一个一致。

有,则这个字母被击中,添加击中动画 shoot,速度归零,再创建一个新的字母补位。得分+1 。


  
  1. // 添加事件
  2. document. addEventListener( "keyup", function ( e) {
  3. console. info( e. code );
  4. let spans = container. getElementsByTagName( "span");
  5. // 判断按键
  6. for( let i= 0; i<spans. length ; i++){
  7. // 击中了字母:按下了正确的字母键
  8. if( "Key"+spans[i]. innerText == e. code ){
  9. spans[i]. classList. add( "shoot"); // 击中字母
  10. spans[i]. speed = 0; // 被击中的字母不再移动
  11. createSpan(); // 再生成一个字母
  12. // 得分
  13. score++;
  14. scoreSpan. innerText = score ;
  15. break;
  16. }
  17. }
  18. });

完整 JavaScript 代码如下:


  
  1. let box = document. getElementById( "box");
  2. let container = document. getElementById( "container");
  3. let missSpan = document. getElementById( "missSpan");
  4. let scoreSpan = document. getElementById( "scoreSpan");
  5. let btn = document. getElementById( "btn");
  6. let numZM = 5;
  7. let score = 0 ; // 得分
  8. let missScore = 0; // 失误
  9. let zmStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  10. let spCtr = 1; // 速度控制变量
  11. let spDi = 0.5;
  12. let req ; // 动画id
  13. let fontColorArr = [ "#ba300c", "#057a7d", "#b724c7", "#8cc111"];
  14. // 创造一个字母
  15. function createSpan( ){
  16. let span = document. createElement( "span");
  17. span. className = "zm";
  18. // 随机生成字母
  19. let zmInStr = ""; // 已有的字母
  20. for( let i= 0; i<=container. children. length- 1; i++){
  21. zmInStr += container. children[i]. innerText ;
  22. }
  23. let zmNow = zmStr[ Math. floor( Math. random()*zmStr. length) ];
  24. // 防止字母重复
  25. while( zmInStr. indexOf(zmNow) >= 0){
  26. zmNow = zmStr[ Math. floor( Math. random()*zmStr. length) ]
  27. }
  28. span. innerText = zmNow;
  29. container. appendChild(span);
  30. span. style. fontSize = ( Math. random()* 50+ 30)+ "px";
  31. span. style. color = fontColorArr[ Math. floor(fontColorArr. length* Math. random())];
  32. // 字母出现的位置
  33. span. style. left = ( 80+ Math. random()*(container. offsetWidth- 160)) + "px";
  34. span. style. top = `${60}px` ;
  35. // 每个字母设置下落速度
  36. span. speed = spDi+ Math. random()*spCtr;
  37. // 每个字母的下落距离
  38. span. dis = 0;
  39. // 添加动画事件
  40. span. addEventListener( "animationend", function ( ) {
  41. // 当 animation 动画结束后,移除该字母
  42. container. removeChild(span);
  43. });
  44. }
  45. // 移动函数
  46. function move( ){
  47. let spans = container. children;
  48. for( let i= 0; i<spans. length; i++){
  49. let span = spans[i];
  50. // 获取每个span的速度和位置
  51. let speed = Number(span. speed);
  52. let dis = Number(span. dis);
  53. span. style. top = `${dis+speed}px`;
  54. span. dis = `${dis+speed}`;
  55. // 判断字母是否在外面。
  56. if( Number(span. dis) > Number(container. offsetHeight)+ 10){
  57. container. removeChild(span);
  58. createSpan();
  59. missScore++;
  60. missSpan. innerText = missScore;
  61. }
  62. }
  63. // 判断游戏是否结束:失误超过10次
  64. if(missScore>= 10){
  65. cancelAnimationFrame(req);
  66. box. classList. add( "over");
  67. return ;
  68. }
  69. // 动画循环
  70. req = requestAnimationFrame(move);
  71. }
  72. // 初始化
  73. function initGame( ){
  74. container. innerHTML = "";
  75. score = 0;
  76. scoreSpan. innerText = score ;
  77. missScore = 0;
  78. missSpan. innerText = missScore;
  79. box. classList. remove( "over");
  80. // 初始生成字母
  81. for( let i= 0; i<numZM; i++){
  82. createSpan()
  83. }
  84. move();
  85. }
  86. // 添加事件
  87. document. addEventListener( "keyup", function ( e) {
  88. console. info( e. code );
  89. let spans = container. getElementsByTagName( "span");
  90. // 判断按键
  91. for( let i= 0; i<spans. length ; i++){
  92. // 击中了字母:按下了正确的字母键
  93. if( "Key"+spans[i]. innerText == e. code ){
  94. spans[i]. classList. add( "shoot"); // 击中字母
  95. spans[i]. speed = 0; // 被击中的字母不再移动
  96. createSpan(); // 再生成一个字母
  97. // 得分
  98. score++;
  99. scoreSpan. innerText = score ;
  100. break;
  101. }
  102. }
  103. });
  104. // 重新开始游戏:
  105. btn. addEventListener( "click", function( ){
  106. initGame()
  107. });
  108. // 启动游戏
  109. initGame();


转载:https://blog.csdn.net/weixin_42703239/article/details/128777424
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场