• H5 台球猜位置小游戏


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

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

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

    document.elementFromPoint(x, y)
    
    • 1

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

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383

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

  • 相关阅读:
    CentOS Linux release 7.9.2009 (Core)中安装配置Tomcat
    【JavaScript】基础学习记录
    Vue源码阅读【番外篇】:为什么Proxy需要搭配Reflect来实现响应式?
    计算机毕业设计之java+springboot基于vue的校园交友网站
    怎么辨别哪些才是真的低代码开发平台?
    MySQL事物
    【ESP 保姆级教程】疯狂点灯篇 —— 案例:ESP8266 + 风扇 + 按键(模拟按键控制电器设备开关)
    Netty如何解决粘包半包问题
    优化软件测试成本的 7 个步骤
    P2802 回家
  • 原文地址:https://blog.csdn.net/linyisonger/article/details/137964458