刷到抖音有人这样玩,就写了一个这样的小游戏练习一下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>.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">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