钟摆小游戏的开发过程

news2024/9/25 7:23:23

框架

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>钟摆游戏</title>
    <style>
        * {
			box-sizing: border-box;
			margin: 0;
		}
        /* game盒子 采用 相对布局 ,便于后续添加 绝对定位的item*/
        .game {
			position: relative;
			height: 500px;
			width: 500px;
		}
        
        /* 分数 绝对布局,在 正中间 */
        .score {
			position: absolute;
			left: 250px;
			top: 250px;
			transform: translate(-50%, -50%);
		}
    </style>
</head>
<body>
    <div class="score">分数:<label id="val">0</label></div>
	<div class="game"></div>
</body>
</html>

 整个游戏我们都放在500 * 500 的区域中进行。 所以我们使用了 box-sizing属性,具体用法可见 盒子模型中box-sizing: border-box;的作用_Eric加油学!的博客-CSDN博客

得分圈和钟摆

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>钟摆游戏</title>
    <style>
        * {
			box-sizing: border-box;
			margin: 0;
		}
        /* game盒子 采用 相对布局 ,便于后续添加 绝对定位的item*/
        .game {
			position: relative;
			height: 500px;
			width: 500px;
		}
        .item {
			display: flex;
			justify-content: center;
			align-items: center;
			background-color: cadetblue;
			border-radius: 100%;
			color: #fff;
			width: 85px;
			height: 85px;
			border: 1px solid rgb(55, 101, 103);
			position: absolute;
			left: 50%;
			top: 50%;
			margin: -40px 0 0 -40px;
		}
        .item-name {
			position: relative;
			z-index: 1;
		}
        /* 摆锤动画 */
        .tool {
			animation: run 2s linear infinite;
		}
		@keyframes run {
			0% {
				transform:rotate(0deg);
			}
			100% {
				transform:rotate(360deg);
			}
		}
        .paused {
			animation-play-state: paused;
		}
		.tool,.tool-circle {
			position: absolute;
			width: 60px;
			height: 60px;
			left: 50%;
			top: 50%;
			margin: -30px 0 0 -30px;
			background-color: rgb(117, 68, 68);
			border-radius: 100%;
		}
		.tool:after {
			content: '';
			position: absolute;
			height: 100px;
			width: 10px;
			background-color: rgb(117, 68, 68);
			left: 50%;
			margin-left: -5px;
			bottom: 30px;
		}
		.tool-circle {
			top: -78px;
			display: flex;
			justify-content: center;
			align-items: center;
		}
        /* 分数 绝对布局,在 正中间 */
        .score {
			position: absolute;
			left: 250px;
			top: 250px;
			transform: translate(-50%, -50%);
		}
    </style>
</head>
<body>
    <div class="score">分数:<label id="val">0</label></div>
	<div class="game"></div>
</body>
<script>
    const game = document.querySelector('.game')
    const score = document.querySelector('#val')
    // 定义一圈设置9个得分点
    const max = 9
    let index = 0
    const data = Array.from(new Array(max)).map((v, i) => {
        // 均分角度
        const deg = i * 360 / max;
        return `<div class="item" style="transform: rotate(${deg}deg) translate(160px);z-index:${i === index ? '10' : ''}">
			<span class="item-name"></span>
			${i === index ? `<div class="tool">
				<div class="tool-circle"><span id="curr"></span></div>	
			</div>`:''}
		</div>`
    })
    game.innerHTML = data.join('')
</script>
</html>

 

 首先获取到相应的元素,并设置一共9个得分圈,从正右边开始(0号),index从0起。

const data = Array.from(new Array(max)).map((v, i) => {
        // 均分角度
        const deg = i * 360 / max;
        return `<div class="item" style="transform: rotate(${deg}deg) translate(160px);z-index:${i === index ? '10' : ''}">
			<span class="item-name"></span>
			${i === index ? `<div class="tool">
				<div class="tool-circle"><span id="curr"></span></div>	
			</div>`:''}
		</div>`
    })
game.innerHTML = data.join('')

这段代码,就是利用JS添加这9个item得分圈。 并计算旋转角度,设置平移距离160px;

然后如果当前索引上有钟摆,我们添加钟摆,并为其设置动画。

tool 就是 得分圈上的钟摆座, tool-circle就是正在旋转的钟摆,我们利用 .tool:after 为其添加中间的杆  tool-name和curr分别是得分圈和钟摆的中心点

这里其实是用拼接innerHTML属性的字符串,各个字符串追加game里面,最后调用数组的join方法生成目标字符串 。 这种方法其实效率更高,但是可读性并不是很强。

也有最简单的方法,就是将元素先写好,然后再设置属性

<div class="game">
		<div class="item">1</div>
		<div class="item">2</div>
		<div class="item">3</div>
		<div class="item">4</div>
		<div class="item">5</div>
		<div class="item">6</div>
		<div class="item">7</div>
		<div class="item">8</div>
		<div class="item">9</div>
</div>
    const game = document.querySelector('.game')
	const item = game.getElementsByClassName("item")
    const score = document.querySelector('#val')
    // 定义一圈设置9个得分点
    const max = 9
    let index = 0
    const data = Array.from(new Array(max)).map((v, i) => {
        // 均分角度
        const deg = i * 360 / max;
		item[i].style.webkitTransform = "rotate(" + deg + "deg)" + " translate(160px)";
    })

这里用JS设置transform属性,常用的setAttribute不起作用,可以使用:

element.style.webkitTransform = "40deg"

这种方法,看上去很清楚明了,但是效率最慢 

动态得分规则

当我们点击屏幕的时候,暂停动画,计算 当前摆锤的中心点位置 和 目标得分圈的中心点位置,由二者差值得出 是否成功得分。如果得分,将摆锤底座 添加至 下一个得分圈,重新开始动画,否则游戏结束。

document.onclick = () => {
        const tool = game.querySelector('.tool')
        // 动画暂停
        tool.classList.add('paused')
        // 计算下一个点
        const nextIndex = index === max - 1 ? 0 : index + 1
        const list = game.children
        // 当前摆锤的位置,获得其中心点位置
        const currRect = document.getElementById('curr').getBoundingClientRect()
        // 找到下一个得分圈的中心点
        const moveEl = list[nextIndex].querySelector('.item-name')
        // 下一个得分圈中心点位置信息
        const moveRect = moveEl.getBoundingClientRect()

        // 计算两者之间差值 (得分圈和钟摆大小差值为25)
        if(Math.abs(currRect.left - moveRect.left) < 15 && Math.abs(currRect.top - moveRect.top) < 15){
            // 摆锤 停的位置 是正确的
            // 将摆锤底座 添加到 下一个得分圈上
            list[nextIndex].appendChild(tool)
            // 移除 暂停状态
			tool.classList.remove('paused')
            // 清空当前状态的index,并将下一个得分圈的index设为10
			list[index].style.zIndex = ''
			list[nextIndex].style.zIndex = '10'
			if (index === max - 1) {
				index = 0
			} else {
				index++
			}
            // 得分+1
			score.innerHTML = parseInt(score.innerHTML) + 1
        } else if (score.innerHTML.indexOf(',') ===  - 1) {
			score.innerHTML += ',游戏结束'
		}
    }

调整游戏难度

如果想要调整游戏的难度,可以 设置 钟摆旋转动画的快慢,或者判定得分的差值大小。

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>钟摆游戏</title>
    <style>
        * {
			box-sizing: border-box;
			margin: 0;
		}
        /* game盒子 采用 相对布局 ,便于后续添加 绝对定位的item*/
        .game {
			position: relative;
			height: 500px;
			width: 500px;
		}
        .item {
			display: flex;
			justify-content: center;
			align-items: center;
			background-color: cadetblue;
			border-radius: 100%;
			color: #fff;
			width: 85px;
			height: 85px;
			border: 1px solid rgb(55, 101, 103);
			position: absolute;
			left: 50%;
			top: 50%;
			margin: -40px 0 0 -40px;
		}
        .item-name {
			position: relative;
			z-index: 1;
		}
        /* 摆锤动画 */
        .tool {
			animation: run 3s linear infinite;
		}
		@keyframes run {
			0% {
				transform:rotate(0deg);
			}
			100% {
				transform:rotate(360deg);
			}
		}
        .paused {
			animation-play-state: paused;
		}
		.tool,.tool-circle {
			position: absolute;
			width: 60px;
			height: 60px;
			left: 50%;
			top: 50%;
			margin: -30px 0 0 -30px;
			background-color: rgb(117, 68, 68);
			border-radius: 100%;
		}
		.tool:after {
			content: '';
			position: absolute;
			height: 100px;
			width: 10px;
			background-color: rgb(117, 68, 68);
			left: 50%;
			margin-left: -5px;
			bottom: 30px;
		}
		.tool-circle {
			top: -78px;
			display: flex;
			justify-content: center;
			align-items: center;
		}
        /* 分数 绝对布局,在 正中间 */
        .score {
			position: absolute;
			left: 250px;
			top: 250px;
			transform: translate(-50%, -50%);
		}
    </style>
</head>
<body>
    <div class="score">分数:<label id="val">0</label></div>
	<div class="game"></div>
</body>
<script>
    const game = document.querySelector('.game')
    const score = document.querySelector('#val')
    // 定义一圈设置9个得分点
    const max = 9
    let index = 0
    const data = Array.from(new Array(max)).map((v, i) => {
        // 均分角度
        const deg = i * 360 / max;
        return `<div class="item" style="transform: rotate(${deg}deg) translate(160px);z-index:${i === index ? '10' : ''}">
			<span class="item-name"></span>
			${i === index ? `<div class="tool">
				<div class="tool-circle"><span id="curr"></span></div>	
			</div>`:''}
		</div>`
    })
    game.innerHTML = data.join('')
    document.onclick = () => {
        const tool = game.querySelector('.tool')
        // 动画暂停
        tool.classList.add('paused')
        // 计算下一个点
        const nextIndex = index === max - 1 ? 0 : index + 1
        const list = game.children
        // 当前摆锤的位置,获得其中心点位置
        const currRect = document.getElementById('curr').getBoundingClientRect()
        // 找到下一个得分圈的中心点
        const moveEl = list[nextIndex].querySelector('.item-name')
        // 下一个得分圈中心点位置信息
        const moveRect = moveEl.getBoundingClientRect()

        // 计算两者之间差值 (得分圈和钟摆大小差值)
        if(Math.abs(currRect.left - moveRect.left) < 15 && Math.abs(currRect.top - moveRect.top) < 15){
            // 摆锤 停的位置 是正确的
            // 将摆锤底座 添加到 下一个得分圈上
            list[nextIndex].appendChild(tool)
            // 移除 暂停状态
			tool.classList.remove('paused')
            // 清空当前状态的index,并将下一个得分圈的index设为10
			list[index].style.zIndex = ''
			list[nextIndex].style.zIndex = '10'
			if (index === max - 1) {
				index = 0
			} else {
				index++
			}
            // 得分+1
			score.innerHTML = parseInt(score.innerHTML) + 1
        } else if (score.innerHTML.indexOf(',') ===  - 1) {
			score.innerHTML += ',游戏结束'
		}
    }
</script>
</html>

参考:js实现钟摆小游戏_哔哩哔哩_bilibili

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

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

相关文章

K8S 快速入门(五)网络通信原理:Pod网络

一、Pod网络 1. Pod结构 Pod的特点&#xff1a;容器 1、有自己的IP地址 2、有自己的hostname 3、有自己的端口 Pod实际上可以理解为就是k8s云平台中的虚拟机&#xff0c;而这个pod内部封装的是由docker引擎所创建的容器&#xff0c;也可以理解为pod就是一个虚拟化分组&#xf…

微信小程序后台交互-个人中心06

目录 1.获取用户昵称和头像 2.登录过程 3.登录-小程序 4.后台 1.获取用户昵称和头像 小程序登录https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 登录过程&#xff1a; 说明 调用 wx.login() 获取 临时登录凭证code &#xff0c;并…

Java文件解析:Excel解析

文章目录一、前言二、POI 和 easyExcel1.1概念1.2xls和xlsx区别1.3文档1.4Excel概念二、常用场景三、内存问题四、POI的使用4.1创建一个空项目4.2引入pom依赖4.3workbook的三个实现类4.4写的实现4.4读的实现4.5POI常用的包五、EasyExcel的使用5.1创建一个空项目5.2引入pom依赖5…

智慧城市物联网介绍

智慧城市物联网介绍 智慧城市是一个有机结合的大系统&#xff0c;涵盖了更透切的感知、更全面的互连&#xff0c;更深入的智能。物联网是智慧城市中非常重要的元素&#xff0c;它侧重于底层感知信息的采集与传输&#xff0c;城市范围内泛在网方面的建设。 通过智慧城市物联网支…

探索Feign

目录 1. 简介 2. 原理 2.1. 动态代理 动态代理 动态代理 2.2. 懒加载负载均衡器的问题与解决 2.3. 主要类 3. 使用举例 4. 参数配置 1. 简介 Feign&#xff0c;一种声明式的web service client&#xff0c;可以很容易的创建http apis client。创建一个interface并添加注…

Cubase11/12 Windows 音乐创作工具

前言 Cubase是一款专业级的高级音乐创作软件&#xff0c;凭借其无与伦比的灵活工具&#xff0c;您可以快速和直观地创造任何类型的音&#xff0c;充满了各种各样的虚拟仪器、效果和数千种声音。 下载 官网:Cubase Cubase12 12详细教程 Cubase11教程 管理员身份运行 右击…

python初级教程四 发送邮件

SMTP发送邮件 SMTP&#xff08;Simple Mail Transfer Protocol&#xff09;即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则&#xff0c;由它来控制信件的中转方式。 python的smtplib提供了一种很方便的途径发送电子邮件。它对smtp协议进行了简单的封装。 …

实力认证!中睿天下荣获“创客北京2022”软件与信息技术产业项目十强

近日&#xff0c;第七届“创客中国”北京市中小企业创新创业大赛暨“创客北京2022”创新创业大赛北京区域赛在决赛阶段按照八个产业对参赛项目进行评选&#xff0c;产生了各产业的十强项目&#xff0c;《中睿天下实战对抗攻击溯源项目》从数百个项目中脱颖而出&#xff0c;荣获…

MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《2》

上一篇文章 是对这个模型做个测试&#xff0c;效果很不错&#xff0c;然后这节&#xff0c;我们来关注下论文中的一些知识点 原论文&#xff1a;Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks 本文不是按照原论文的顺序一路下来讲解&…

Python基础语法(三)

Python基础语法&#xff08;三&#xff09; 列表和元组 列表是什么, 元组是什么 编程中, 经常需要使用变量, 来保存/表示数据. 如果代码中需要表示的数据个数比较少, 我们直接创建多个变量即可 num1 10 num2 20 num3 30 ......但是有的时候, 代码中需要表示的数据特别多…

小程序:后台交互-个人中心

目录 获取用户昵称头像和昵称 wx.getUserProfile bindgetuserinfo oa-mini 登录过程 登录-小程序 wx.checkSession wx.login wx.request 后台 准备数据表 反向生成工具生成 准备封装前端传过来的数据 小程序服器配置 导入微信小程序SDK application.yml WxPro…

我眼中的Java内存模型

一.JVM内存结构 &#xff08;1&#xff09;方法区只是一种概念上的区域&#xff0c;并说明了其应该具有什么功能&#xff0c;但是没有规定这个区域到底应该处于何处&#xff0c;不同版本的方法区所处位置不同&#xff0c;并不是绝对意义上的物理区域。 &#xff08;2&#xff0…

CSRF攻击方式及预防准则

跨站点请求伪造&#xff08;CSRF&#xff09; 是一种攻击类型&#xff0c;当恶意网站、电子邮件、博客、即时消息或程序导致用户的Web浏览器在用户通过身份验证后对受信任的站点执行不需要的操作时&#xff0c;就会发生这种攻击。CSRF攻击之所以有效&#xff0c;是因为浏览器请…

OpenHarmony#深入浅出学习eTs#(二)拖拽式UI

本项目Gitee仓地址&#xff1a;深入浅出eTs学习: 带大家深入浅出学习eTs (gitee.com) 一、创建支持Super Visual的工程 在这里选择直尺Super Visual的选项&#xff0c;调整当前路径&#xff0c;进入绘制界面 二、UI设计界面介绍 在左侧是路径&#xff08;即文件管理器&#x…

3.我们一起来学习Linux 安装

Linux 安装 本章节我们将为大家介绍 Linux 的安装&#xff0c;安装步骤比较繁琐&#xff0c;现在其实云服务器挺普遍的&#xff0c;价格也便宜&#xff0c;如果自己不想搭建&#xff0c;也可以直接买一台学习用用。 本章节以 centos6.4 为例。 可以去官网下载最新版本&…

【C语言进阶】通讯录再优化?学会文件操作,没有数据库也能保存和管理本地数据

目录 &#x1f95d;前言&#x1f95d;&#xff1a; 一、&#x1f353;文件概述&#x1f353;&#xff1a; 1.为什么使用文件&#xff1a; 2.什么是文件&#xff1a; ①.程序文件&#xff1a; ②.数据文件&#xff1a; ③.文件名&#xff1a; 二、&#x1f34a;文件顺序读写&…

JAVA集成阿里云OSS对象存储

JAVA集成阿里云OSS对象存储1 : 配置集成1.1、对象存储OSS2 : 代码配置2.1、说明2.2、配置文件2.3、加载配置文件代码2.4、封装统一的DTO2.5、OSS上传Controller2.6、OSS上传Service2.7、OSS上传ServiceImpl3 : 测试3.1、文件上传3.2、文件迁移4 : 总结4.1、参考资料4.2、注意事…

浅谈 C++ 字符串:std::string 与它的替身们

浅谈 C 字符串&#xff1a;std::string 与它的替身们 文章目录浅谈 C 字符串&#xff1a;std::string 与它的替身们零、前言一、前辈&#xff1a;C 风格的字符串1.1 什么是 C 风格的字符串1.2 C 风格的字符串有什么缺陷1.2.1 以 \0 作为结尾&#xff0c;没有直接指明长度1.2.2 …

Android技术分享——APT实现ButterKnife【实战学习】

APT APT &#xff08;Annotation Processing Tool&#xff09; 是一种处理注释的工具&#xff0c;它对源代码文件进行检测并找出其中的 Annotation&#xff0c;根据注解自动生成代码&#xff0c;如果想要自定义的注解处理器能够运行&#xff0c;必须要通过 APT 工具来处理。 …

Python实现FA萤火虫优化算法优化支持向量机分类模型(SVC算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 萤火虫算法&#xff08;Fire-fly algorithm&#xff0c;FA&#xff09;由剑桥大学Yang于2009年提出 , 作…