H5 台球猜位置小游戏

devtools/2024/9/24 20:12:12/

刷到抖音有人这样玩,就写了一个这样的小游戏练习一下H5的知识点。

小游戏预览
w(゚Д゚)w 不开挂越急越完成不了,👿确认15次也没全对…
在这里插入图片描述
知识点

获取坐标位置的DOM元素,感觉应该是新的吧,以前的时候没什么印象有这个方法。兼容性不晓得可以自己查下~

document.elementFromPoint(x, y)

源码
注释不多,比较简单的,还是比较好理解的。

<!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"><link rel="stylesheet" href="./assets/global.css"><style>css">.block {width: 65px;height: 65px;/* position: absolute; */background-size: 300px;display: inline-block;user-select: none;background-position: calc(var(--x, 0) * (65px + 13.5px) * -1) calc(var(--y, 0) * (65px + 13.5px) * -1);}.title {margin-top: 40px;font-size: 40px;font-weight: bold;text-align: center;}.container {margin: 0 20px;}.tips {margin: 20px;font-size: 20px;color: rgba(0, 0, 0, .5);}.btn {margin: 20px;color: #fff;background-color: green;width: 120px;height: 40px;line-height: 40px;text-align: center;}.btn:active {opacity: .7;}.abs {position: absolute;z-index: 2;pointer-events: none;}.op5 {opacity: .5;}.billiard-container .block {pointer-events: none;width: 32.5px;height: 32.5px;background-size: 150px;background-position: calc(var(--x, 0) * (32px + 7.5px) * -1) calc(var(--y, 0) * (32px + 7.5px) * -1)/* transform: scale(-50%); */}.result {display: flex;flex-direction: column-reverse}.result-item {display: flex;align-items: center;padding: 10px 20px 0;}.result-item .index {font-size: 20px;font-weight: bold;margin-right: 20px;}.result-item .billiard-container {flex: 1;}.result-item .right-count {color: #12be77;}.win {margin: 20px 20px 0;font-size: 20px;}</style>
</head><body><div class="title">猜位置</div><div class="tips">拖动更换位置,点击确认获取结果,位置都正确获取游戏胜利。</div><div class="container"></div><div class="win">🐂🍺! 🎉游戏胜利!🎉</div><div class="btn">确定</div><div class="result"></div><script type="module">javascript">let winDom = document.querySelector('.win')winDom.hidden = true;import { Maths, Randoms, Animation, cloneDeep, InterchangeFlag } from "https://unpkg.com/@3r/tool"let containerDom = document.querySelector('.container')let btnDom = document.querySelector('.btn')let resultDom = document.querySelector('.result')let billiardConfig = {sprite: './assets/taiqiu.png',blocks: [{id: '1',position: { x: 0, y: 0 }},{id: '2',position: { x: 1, y: 0 }},{id: '3',position: { x: 2, y: 0 }},{id: '4',position: { x: 3, y: 0 }},{id: '5',position: { x: 0, y: 1 }},{id: '6',position: { x: 1, y: 1 }},{id: '7',position: { x: 2, y: 1 }},{id: '8',position: { x: 3, y: 1 }},{id: '9',position: { x: 0, y: 2 }},{id: '10',position: { x: 1, y: 2 }},{id: '11',position: { x: 2, y: 2 }},{id: '12',position: { x: 3, y: 2 }},{id: '13',position: { x: 0, y: 3 }},{id: '14',position: { x: 1, y: 3 }},{id: '15',position: { x: 2, y: 3 }},{id: '白球',position: { x: 3, y: 3 }}]}let allBlocks = cloneDeep(billiardConfig.blocks) // 所有的数据let selBlockDom = null // 移动前不动的球let movBlockDom = null // 当前移动的球let hovBlockDom = null // 不表浮动到哪个球上面let curBlocks = Randoms.getDisorganizeArray(cloneDeep(allBlocks)).slice(0, 5) // 记录当前记录let resDataIds = Randoms.getDisorganizeArray(curBlocks.map(b => b.id)) // 记录本轮结果let hisList = [] // 记录历史document.body.addEventListener("touchmove", handleMoving)document.body.addEventListener("touchend", handleMoveEnd)document.body.addEventListener("touchcancel", handleMoveEnd)document.body.addEventListener("mousemove", handleMoving)document.body.addEventListener("mouseup", handleMoveEnd)function handleMoveStart(ev) {// console.log("handleMoveStart", ev);let x, y;if (ev.type == 'touchstart') {selBlockDom = ev.target;movBlockDom = ev.target.cloneNode()x = ev.touches[0].clientXy = ev.touches[0].clientY}if (ev.type == 'mousedown') {x = ev.xy = ev.yselBlockDom = ev.target;movBlockDom = ev.target.cloneNode()}if (!movBlockDom) return;movBlockDom.classList.add('abs')movBlockDom.classList.add('op5')movBlockDom.style.left = `${x}px`movBlockDom.style.top = `${y}px`document.body.appendChild(movBlockDom)}function handleMoving(ev) {// console.log("handleMoving", ev);let x, y;if (ev.type == 'touchmove') {x = ev.touches[0].clientXy = ev.touches[0].clientY}if (ev.type == 'mousemove') {x = ev.xy = ev.y}x = Math.floor(x)y = Math.floor(y)hovBlockDom?.classList.remove('op5')hovBlockDom = null;let tmpHovBlockDom = document.elementFromPoint(x, y)if (tmpHovBlockDom.classList.contains('block')) {tmpHovBlockDom.classList.add('op5')hovBlockDom = tmpHovBlockDom;}if (!movBlockDom) return;movBlockDom.style.left = `${x}px`movBlockDom.style.top = `${y}px`}function handleMoveEnd(ev) {if (!movBlockDom) return;if (hovBlockDom) {// 交换位置let dataId = hovBlockDom.getAttribute('data-id')let style = hovBlockDom.getAttribute('style');hovBlockDom.setAttribute('data-id', selBlockDom.getAttribute('data-id'))hovBlockDom.setAttribute('style', selBlockDom.getAttribute('style'))selBlockDom.setAttribute('data-id', dataId)selBlockDom.setAttribute('style', style)let idx1 = curBlocks.findIndex(b => b.id == selBlockDom.getAttribute('data-id'))let idx2 = curBlocks.findIndex(b => b.id == hovBlockDom.getAttribute('data-id'))// 下标交换Maths.interchange(curBlocks, idx1, idx2, InterchangeFlag.Change)}hovBlockDom?.classList.remove('op5')document.body.removeChild(movBlockDom)hovBlockDom = null;movBlockDom = null;selBlockDom = null;}// 生成球function generateBilliardItemDom(blocks) {let blockDomList = []for (const block of blocks) {let blockDom = document.createElement('div')blockDom.classList.add('block')// let px = Math.round(block.position.x * billiardConfig.width + billiardConfig.marginRight * block.position.x) * -1// let py = Math.round(block.position.y * billiardConfig.height + billiardConfig.marginBottom * block.position.y) * -1// let backgroundPosition = `background-position: ${px}px ${py}px;`// blockDom.style = `background-image: url(${billiardConfig.sprite});${backgroundPosition}`blockDom.setAttribute('style', `--x: ${block.position.x}; --y: ${block.position.y}`);blockDom.style.backgroundImage = `url(${billiardConfig.sprite})`blockDom.setAttribute('data-id', block.id)blockDom.addEventListener("mousedown", handleMoveStart)blockDom.addEventListener("touchstart", handleMoveStart)blockDomList.push(blockDom)// containerDom.appendChild(blockDom)}return blockDomList}// 生成历史结果function generateResultDom(result) {let resultItemDom = document.createElement('div')resultItemDom.classList.add('result-item')let indexDom = document.createElement('div')indexDom.classList.add('index')indexDom.textContent = `${hisList.length + 1}`let billiardDom = document.createElement('div')billiardDom.classList.add('billiard-container')let rightCountDom = document.createElement('div')rightCountDom.classList.add('right-count')rightCountDom.textContent = `✔ × ${result.rightCount}`generateBilliardItemDom(result.blocks).forEach(item => {billiardDom.appendChild(item)});resultItemDom.appendChild(indexDom)resultItemDom.appendChild(billiardDom)resultItemDom.appendChild(rightCountDom)resultDom.appendChild(resultItemDom)}// 计算结果function calculateResult() {let curDataIds = curBlocks.map(b => b.id)let rightCount = 0;for (let i = 0; i < curDataIds.length; i++) {if (curDataIds[i] == resDataIds[i]) {rightCount++;}}// 判断是否游戏胜利✌if (rightCount == curBlocks.length) {winDom.hidden = false;btnDom.hidden = true;}let result = {rightCount,blocks: cloneDeep(curBlocks)}generateResultDom(result)hisList.push(result)}btnDom.addEventListener('click', calculateResult)generateBilliardItemDom(curBlocks).forEach(item => {containerDom.appendChild(item)});</script>
</body></html>

源码地址 https://github.com/linyisonger/H5.Examples
在线试玩 https://linyisonger.github.io/H5.Examples/?name=./066.%E7%8C%9C%E4%BD%8D%E7%BD%AE.html


http://www.ppmy.cn/devtools/12074.html

相关文章

第 2 章:FFmpeg简介

2.1 历史 历史 一些相关术语介绍&#xff1a; 容器&#xff08;Container&#xff09;格式&#xff1a;一种文件封装格式&#xff0c;里边主要包含了流&#xff0c;一般会使用一个特定的后缀名标识&#xff0c;例如.mov、.avi、.wav等。流 &#xff08;Stream&#xff09;&am…

Hive,Presto,Spark 共性

Hive、Presto 和 Spark 都是大数据处理工具&#xff0c;都属于大数据处理技术栈&#xff0c;都需要集群环境支持&#xff0c;都可以进行数据处理和分析。 都可以进行数据处理&#xff1a;Hive、Presto、Spark 都可以用 SQL 语句进行数据处理&#xff0c;也可以用它们的语言&…

uniapp:小白1分钟学会使用webSocket(可无脑复制)

uni.connectSocket() uni.$emit页面通信 项目中使用uni.connectSocket()创建webSocket的总结&#xff0c;代码可无脑复制&#xff0c;直接使用。 1、main.js 引入vuex import store from ./store; Vue.prototype.$store store;vuex中封装webSocket 2、vuex的&#xff1a;index…

springcloud alibaba 整合seata的TCC

一、seata服务端搭建同上篇。 Seata的AT模式客户端两阶段提交流程源码分析 二、seata客户端的结构 1.示例DEMO工程 下单&#xff0c;扣余额&#xff0c; 减库存。 2. MAVEN配置。 父工程&#xff1a;由于spring-cloud-starter-alibaba-seata依赖的seata-spring-boot-starter…

【数据库】MySQL分页查询

分页查询&#xff1a; 数据记录条数过多的时候&#xff0c;需要分页来显示。 语法&#xff1a; select 查询字段 from 表名 where ....等等 limit offset&#xff08;开始记录索引,是从0开始的&#xff09;,size&#xff08;要取出的条数&#xff09;&#xff1b; 案例&…

如何使用WEB前端模板

我最近想搞一搞前端&#xff0c;前端属实不太行&#xff0c;像前端搞个模板直接套一下。但是发现下载下来也有点不知道怎么用起来&#xff0c;这里我就把我的一个Bootstrap工程套用模板的具体过程记录一下。 首先创建一个前端工程&#xff0c;我这里用的是Bootstrap5&#xff…

前端面试笔记vue

vue2 生命周期 beforeCreate&#xff1a;无data、methods、dom created&#xff1a;有data、methods&#xff0c;无dom beforeMount&#xff1a;有data&#xff0c;无dom mounted&#xff1a;有data&#xff0c;有dom beforeUpdate updated deforeDestroy destroy&#xff1a…

Octopus+: An RDMA-Enabled Distributed Persistent Memory File System——泛读笔记

TOS 2021 Paper 分布式元数据论文阅读笔记整理 问题 非易失性存储器&#xff08;NVM&#xff09;和远程直接存储器访问&#xff08;RDMA&#xff09;在存储和网络硬件中提供了极高的性能。然而&#xff0c;现有的分布式文件系统隔离了文件系统和网络层&#xff0c;而且分层的…