H5 台球猜位置小游戏

刷到抖音有人这样玩,就写了一个这样的小游戏练习一下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].clientX
                y = ev.touches[0].clientY
            }

            if (ev.type == 'mousedown') {
                x = ev.x
                y = ev.y

                selBlockDom = 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].clientX
                y = ev.touches[0].clientY
            }

            if (ev.type == 'mousemove') {
                x = ev.x
                y = 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

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林一怂儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值