js打地鼠

news2024/9/28 7:24:42

文章目录

  • 1实现效果
  • 2代码实现

1实现效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

游戏难度:简单,一般,困难,噩梦(控制setInterval的time参数)
按钮功能:结束(可以通过修改gameScore的值来修改判定结束的分数),开始,重开
游戏得分

2代码实现

注意路径:
在这里插入图片描述
我的img和html文件是并列关系,引入的相对路径

url(./img/xxx.jpg)

资源图片:

mouse.jpg
在这里插入图片描述

bg.jpg
在这里插入图片描述

hit.jpg
在这里插入图片描述

hummer.png
在这里插入图片描述

注意:注意计时器,何时打开了,何时需要关闭它,创建的timeId从1开始,之前的不关闭,在创建新的时,timeId是2 ,依次类推,不及时关闭定时器,可能会造成逻辑混乱。
比如:在本例中,在游戏执行过程中,直接修改下拉框后,不执行clearInterval(timeId),而是直接调用startGame(),就会创建另一个定时器,此时如果达到了判输的条件,执行gameOver(),虽然执行了clearInterval(timeId),但是关闭的定时器是新开的那个,此时的timeId值是2,原来的1还存活着。但是这个结束条件依然成立(score<=gameScore),在第一个定时器中每次执行到gameOver()都会被触发,这就是bug,所以要在改变下拉框时,要及时关闭第一个定时器(timeId=1的)。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>打地鼠</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        body {
            background-color: lightblue;
        }

        .div1 {
            text-align: center;
            background-color: lightgreen;
            width: 100%;
            line-height: 50px;

        }

        .div2 {
            margin: 0 auto;
            width: 600px;
            height: 610px;
        }

        td {
            width: 200px;
            height: 200px;
            border-radius: 100px;
            background-image: url(./img/bg.jpg);
            background-size: 100% 100%;
            background-repeat: no-repeat;
            border: 1px solid #000;
            cursor: url("./img/hummer.png"), auto;
        }
        select{
            text-align: center;
            width: 70px;
            height: 30px;
            font-family: 'Courier New', Courier, monospace;
            border-radius: 5px;
        }
        button{
            width: 100px;
            height: 30px;
            font-family: 'Courier New', Courier, monospace;
            border-radius: 5px;
            background-color: lightgray;
            margin-right: 30px;
            margin-left: 30px;
        }
        button:hover{
            background-color: orange;
            color: #fff;
        }
        span{
            color: red;
            width: 40px;
            height: 30px;
            padding-left: 10px;
            font-size: 20px;
            font-family: 'Courier New', Courier, monospace;
            display: inline-block;
            box-sizing: border-box;
        }
       
    </style>
</head>

<body>
    <audio src="./audio/bg.mp3" class="bgMusic"></audio>
    <audio src="./audio/hit.wav" class="hitMusic"></audio>
    <div class="div1">
        游戏难度:
        <select id="select">
            <option>简单</option>
            <option>一般</option>
            <option>困难</option>
            <option>噩梦</option>
        </select>
        <button id="start">开始游戏</button>
        游戏得分:
        <span id="score">0</span>
    </div>
    <div class="div2">
        <table>
            <tr>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
            </tr>
        </table>
    </div>
    <script>
        //是否开始游戏
        let isPlay = false;
        let score = 0;
        // 是否捶打
        let flag = true;
        let lastIndex = 0;
        var timeId = 0;
        let Tid=0;
        // 捶了是否锤中
        let isRight=false;
        let isHit=false;
        // 定时器时间
        let time = 2000;
        let index = 0;
        let gameScore = -20;
        // 获取元素
        let select = document.querySelector("#select");
        let start = document.querySelector("#start");
        let scoreSpan = document.querySelector("#score");
        let tds = document.querySelectorAll("td");
        let bgMusic = document.querySelector(".bgMusic");
        let hitMusic = document.querySelector(".hitMusic");
        // 给开始按钮添加点击事件
        start.onclick = function () {
            isPlay = !isPlay;
            if (isPlay) {
                // 获取游戏难度
                let level = select.value;
                clearTimeout(Tid);
                score = 0;
                scoreSpan.innerHTML = score;
                tds[lastIndex].style.backgroundImage = 'url(./img/bg.jpg)';
                // 设置游戏难度
                bgMusic.play();
                startGame(level);
                start.innerHTML = "结束游戏";

            } else {
                // 结束游戏
                bgMusic.pause();
                clearInterval(timeId); // 清除定时器
                start.innerHTML = "开始游戏";
            }
        }
        // 给td添加点击事件
        tds.forEach((td, i) => {
            td.onclick = hit.bind(null, i);
        })
        // 给下拉框添加change事件
        select.onchange = function () {
            if (isPlay) {
                let level = select.value;
                flag = true;
                score = 0;
                scoreSpan.innerHTML = score;
                tds[lastIndex].style.backgroundImage = 'url(./img/bg.jpg)';
                // 清除之前开启的定时器,直接切换选项,之前开启的定时器还在运行,所以要关闭
                clearInterval(timeId); 
                startGame(level);
            }
        }

        function startGame(level) {
            if (level == '简单') {
                time = 2000;
            } else if (level == '一般') {
                time = 1500;
            } else if (level == '困难') {
                time = 1000;
            } else {
                time = 800;
            }
            timeId = setInterval(function () {
                // 在还原之前,检查flag的值,为false,代表上一次没有落捶
                if (flag == false) {
                    score -= 5;
                    scoreSpan.innerHTML = score;
                }
                // 开始新的出现位置,锤击状态置为未锤击
                flag = false;
                isRight=false;
                isHit=false;
                gameOver(score);
                // 将上一次的改回原背景
                tds[lastIndex].style.backgroundImage = 'url(./img/bg.jpg)';
                // 随机获取一个索引
                if (isPlay) {
                    index = Math.floor(Math.random() * tds.length);;
                }
                // 给当前的索引添加样式
                tds[index].style.backgroundImage = 'url(./img/mouse.jpg)';
                lastIndex = index;
            }, time);
        }
        // TODO: 游戏是否击中的判断逻辑需要完善
        function hit(i) {
            // 游戏开始时,锤击才有效
            if (isPlay) {
                hitMusic.play();
                // 锤击的td和随机产生的td索引一致,只第一次捶中有效(锤击地鼠出现位置)
                if (i == lastIndex&&!isRight) {
                    isRight=true;
                    score += 3;
                    // 改变背景
                    tds[i].style.backgroundImage = 'url(./img/hit.jpg)'
                } else if(!isHit){
                    // 捶错地方,只第一次捶错有效
                    score -= 5;
                    gameOver(score);
                }
                scoreSpan.innerHTML = score;
                flag = true;
                isHit=true;
            }
        }
        // 游戏结束
        function gameOver(score) {
            if (score <= gameScore) {
                // 清楚当前的计时器id
                clearInterval(timeId);
                scoreSpan.innerHTML = score;
                isPlay = false;
                flag = true;
                start.innerHTML = "重新开始";
                Tid = setTimeout(() => {
                    alert('游戏结束,得分:' + score);
                }, 300);
            }
        }
    </script>
</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1414414.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python-自动化篇-办公-excel-实例应用(一维转二维)

文章目录 准备代码效果 准备 放根目录 代码 import openpyxl wbopenpyxl.load_workbook(业绩表.xlsx) if not 二维表 in wb.sheetnames:nwswb.create_sheet(二维表)wswb.worksheets[0]rngslist(ws.values)[1:]mmlist({m.value: for m in ws[b][1:]})namelist({m.value: for …

语义分割(3):损失函数解析

文章目录 1. 常见语义分割损失1.1 Cross Entropy1.2 dice Loss1.2.1 为什么使用Dice loss1.2.2 公式1.2.3 Dice loss 和 F1-score代码 1.3 focal loss1.3.1 公式&#xff1a;1.3.2 代码 2. 语义分割损失应用参考 语义分割任务实际上是一种像素层面上的分类&#xff0c;需要识别…

NPDP认证:产品经理的国际专业认证

你是否想证明自己在产品开发与管理方面的专业能力&#xff1f;NPDP认证正是你需要的&#xff01;&#x1f525; NPDP认证&#xff0c;即产品经理国际资格认证&#xff0c;由美国产品开发与管理协会&#xff08;PDMA&#xff09;所发起&#xff0c;是全球公认的新产品开发专业认…

Vulnhub靶机:FunBox 8

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;FunBox 8&#xff08;10.0.2.38&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vulnhub.com/entry/funb…

第3章-python深度学习——(波斯美女)

第3章 神经网络入门 本章包括以下内容&#xff1a; 神经网络的核心组件 Keras 简介 建立深度学习工作站 使用神经网络解决基本的分类问题与回归问题 本章的目的是让你开始用神经网络来解决实际问题。你将进一步巩固在第 2 章第一个示例中学到的知识&#xff0c;还会将学到的…

Go 知识for-range

Go 知识for-range 1. for-range 的用法1.1 数组1.2 切片1.3 字符串1.4 map1.5 chan 2. 原理2.1 数组2.2 切片2.3 字符串2.4 map2.5 chan 3. 总结 https://a18792721831.github.io/ 1. for-range 的用法 for-range 表达式用于遍历集合元素&#xff0c;比传统的for更加简单直观…

TF_REPEATED_DATA ignoring data with redundant timestamp for frame

一、问题描述 在进行gazebo 小车仿真时终端会出现TF_REPEATED_DATA ignoring data with redundant timestamp for frame,且在未施加数据的情况下&#xff0c;Rviz中模型车轮有微小移动 其原因是: right_wheel_link与left_wheel_link的TF变换有两个发布者&#xff1a;/gazebo …

jsp原理与EL,JSTL表达式基础内容整理

2024年了&#xff0c;vue都到了灌篮高手的版本&#xff0c;真的没想到我还会在这个时间整理一篇关于jsp页面操作的文章。技术就是一个不用就忘的东西&#xff0c;既然工作中还有用武之地&#xff0c;那就整理一下以备不时之需。 长话短说&#xff0c;不展开叙述&#xff0c;只记…

一键搭建《幻兽帕鲁》服务器

幻兽帕鲁越来越火&#xff0c;官方服务器不堪重负&#xff0c;不少玩家有搭建幻兽帕鲁私服的想法&#xff0c;但又碍于对计算机知识的匮乏而不敢动手&#xff0c;现在它来了&#xff0c;马云家的云服务器一键搭建幻兽帕鲁服务器&#xff0c;一站式解决&#xff01;&#xff01;…

C# 设置一个定时器函数

C#中&#xff0c;创建设置一个定时器&#xff0c;能够定时中断执行特定操作&#xff0c;可以用于发送心跳、正计时和倒计时等。 本文对C#的定时器简单封装一下&#xff0c;哎&#xff0c;以方便定时器的创建。 定义 using Timer System.Timers.Timer;class SetTimer {Timer …

智慧文旅:提升旅游体验与推动经济发展的新动力

一、智慧文旅的定义与意义 智慧文旅&#xff0c;即智慧文化旅游&#xff0c;是一种以当地特色文化元素为核心驱动&#xff0c;利用现代科技手段实现旅游景区全面智慧升级的旅游模式。其意义在于为游客提供高效便捷的旅游信息化服务&#xff0c;提升旅游体验&#xff0c;同时推…

谷粒商城【成神路】-【1】——项目搭建

目录 &#x1f95e;1.整体架构图 &#x1f355;2.微服务划分图 &#x1f354;3.开发环境 &#x1f354;4.搭建git &#x1f32d;5.快速搭建服务 &#x1f37f;6.数据库搭建 &#x1f9c2;7.获取脚手架 &#x1f953;8.代码生成器 &#x1f373;9.创建公共模块 …

【Vue】1-1、webpack的基本使用

一、什么是 Webpack 概念&#xff1a; webpack 是前端项目工程化的具体解决方案。 主要功能&#xff1a; 它提供了友好的前端模块化开发支持&#xff0c;以及代码压缩混淆、处理浏览器端 JavaScript 的兼容性、性能化等强大的功能。 好处&#xff1a; 让程序员把工作重心放到具…

一些反序列化总结

1 反序列化漏洞原理 如果反序列化的内容就是那串字符串&#xff0c;是用户可以控制的&#xff08;即变量的值&#xff09;&#xff0c;且后台不正当的使用了PHP中的魔法函数&#xff0c;就会导致反序列化漏洞&#xff0c;可以执行任意命令。Java 序列化指 Java 对象转换为字节序…

C#,数据检索算法之跳跃搜索(Jump Search)的源代码

数据检索算法是指从数据集合&#xff08;数组、表、哈希表等&#xff09;中检索指定的数据项。 数据检索算法是所有算法的基础算法之一。 本文提供跳跃搜索的源代码。 1 文本格式 using System; namespace Legalsoft.Truffer.Algorithm { public static class ArraySe…

港科夜闻|香港科大科研实力受肯定,成立三个赛马会创科实验室,推展数据科学,再生生物学及气候变化研究...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大科研实力受肯定&#xff0c;成立三个赛马会创科实验室&#xff0c;推展数据科学、再生生物学及气候变化研究。香港科大近日获香港赛马会慈善信托基金慷慨捐助港币三千万元&#xff0c;成立三个赛马会创科实验室&…

微信小程序(十七)自定义组件生命周期(根据状态栏自适配)

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.获取手机状态栏的高度 2.验证attached可以修改数据 3.动态绑定样式数值 源码&#xff1a; myNav.js Component({lifetimes:{//相当于vue的created,因为无法更新数据被打入冷宫created(){},//相当于vue的mount…

java------抽象类和接口【详解】

目录 一.抽象类 1.1抽象类的定义&#xff1a; 1.2抽象类的语法&#xff1a; 1.3 抽象类的特性&#xff1a; 二.接口 2.1接口概念&#xff1a; 2.2 接口的语法&#xff1a; 2.3接口的使用&#xff1a; 2.4接口的特性&#xff1a; 2.5多个接口的实现&#xff1a; 2.6抽象…

接口测试怎么测?接口测试的流程和步骤(超详细)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;薪资嘎嘎涨 一、什么是接口测试 我们要想知道接口测试怎么做&#xff0c;首先要明白接口测试是什么?一般…

Tomcat怎么优化

目录 性能方面的优化&#xff1a; 安全方面的优化&#xff1a; 引言&#xff1a;面试官问到的Tomcat怎么优化&#xff0c;这两个方面直接得到他认可&#xff01;&#xff01; 性能方面的优化&#xff1a; 内存优化&#xff1a;-Xms java虚拟机初始化时的最小内存、-Xmx java虚…