H5 台球猜位置小游戏

news2025/1/13 10:18:46

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

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

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

相关文章

基于STM32F103RCT6最小系统原理图和PCB

目录 1、原理图 2、PCB 3、3D图 资料下载地址&#xff1a;基于STM32F103RCT6最小系统原理图和PCB 1、原理图 2、PCB 3、3D图

亚信安全入选中国数据安全市场图谱

近日&#xff0c;全球领先的IT市场研究和咨询公司IDC发布了《IDC Market Glance&#xff1a;中国数据安全市场图谱&#xff0c;2024》报告&#xff08;以下简称“报告”&#xff09;&#xff0c;报告展示了中国数据安全市场的构成和格局&#xff0c;遴选出不同细分市场领域的主…

vmware安装ubantu系统

镜像下载 官网地址 :https://ubuntu.com/ 历史版本下载 https://old-releases.ubuntu.com/releases/ 虚拟机系统安装 虚拟机上右键设置 选择ubantu的iso镜像 进入启动页 等待安装好系统 到此系统安装成功

【面试经典 150 | 二叉树层序遍历】二叉树的锯齿形层序遍历

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;层序遍历双端队列 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等…

决策树原理及应用

目录 一、决策树概述 1.1决策树的组成 1.2构建决策树 1.3决策树的剪枝 1.4决策树的优点和缺点 二、决策树在计算机视觉中的应用 三、基于决策树的图像分类实例 一、决策树概述 决策树是一种非常流行的机器学习算法&#xff0c;它用树状图的形式来表示决策过程。决策树可…

HarmonyOS开发实例:【分布式邮件】

概述 基于TS扩展的声明式开发范式编程语言编写的一个分布式邮件系统&#xff0c;可以由一台设备拉起另一台设备&#xff0c;每次改动邮件内容&#xff0c;都会同步更新两台设备的信息。效果图如下&#xff1a; 搭建OpenHarmony开发环境 完成本篇Codelab我们首先要完成开发环境…

NLP自然语言处理_序章

开一个新篇章&#xff0c;立一个flag&#xff0c;用一段时间来学习一下NLP&#xff0c;涨涨见识。 准备以B站 机器学习算法到transformer神经网络模型应用视频作为入门&#xff0c;此分类专门用于记录学习过程中的知识点以备自用。 一、何为NLP自然语言处理&#xff1f; NLP…

【ARFoundation自学01】搭建AR框架+检测平面+点击克隆立方体到地面=自信入门!

介绍 AR 的功能其实是个大手机系统厂商和眼镜设备厂商开发的功能&#xff0c;并不是Unity的功能&#xff0c;毕竟Unity没有自己的手机设备&#xff01;比如谷歌公司的安卓开发了ARcore&#xff0c;让所有安卓8.0版本以上的用户能够在手机上体验AR功能&#xff01;苹果推出了AR…

局域网无法连接怎么办?

局域网连接是我们日常生活和工作中常用的方式之一&#xff0c;但有时我们可能会遇到局域网无法连接的问题。这给我们的工作和生活带来了很大的困扰。本文将介绍局域网无法连接的常见原因&#xff0c;并推荐一款名为【天联】的组网产品&#xff0c;它能够解决不同地区间的局域网…

Meta Llama 3 简介

文章目录 要点我们对 Llama 3 的目标最先进的性能模型架构训练数据扩大预训练规模指令微调与 Llama 3 一起建造系统级责任方法大规模部署 Llama 3Llama 3 的下一步是什么&#xff1f;立即尝试 Meta Llama 3 本文翻译自&#xff1a;https://ai.meta.com/blog/meta-llama-3/ 要点…

Android开发:应用百度智能云中的身份证识别OCR实现获取个人信息的功能

百度智能云&#xff1a; 百度智能云是百度提供的公有云平台&#xff0c;于2015年正式开放运营。该平台秉承“用科技力量推动社会创新”的愿景&#xff0c;致力于将百度在云计算、大数据、人工智能的技术能力向社会输出。 百度智能云为金融、城市、医疗、客服与营销、能源、制造…

jeecgflow之camunda工作流-并行网关

引言 书接上回&#xff0c;继续三国流程系列教程。 本文主要讲解并行网关。 并行网关允许流程中的多个任务同时执行&#xff0c;从而提高流程的执行效率。 并行网关会忽视序列流上的条件设置。 并行网关分为两部分。 Fork: 用于任务开始 Join:用于任务结束 体验文章demo演示站…

HarmonyOS-静态库(SDK)的创建和使用

文章目录 一、静态库&#xff08;SDK&#xff09;二、创建静态库1.新建静态库模块2. 开发静态库内容3. 编译静态库 三、使用静态库1. 配置项目依赖2. 在应用中使用静态库3. 注意事项 四、打包错误1. library引用本地har包错误 一、静态库&#xff08;SDK&#xff09; 在Harmon…

美团财务科技Java后端一面:面向对象、类加载过程、全限定类名相同的类是否可以同时被加载

更多大厂面试内容可见 -> http://11come.cn 美团财务科技Java后端一面&#xff1a;面向对象、类加载过程、全限定类名相同的类是否可以同时被加载 如何理解面向对象&#xff1f; 面向对象 是具有对象概念的编程范式&#xff0c;面向对象将程序实现分为了一个个独立的对象&…

Vue.js------Vue组件基础

能够理解Vue组件概念和作用能够掌握封装创建组件能力能够使用组件之间通信能够完成todo案例 一.Vue组件创建和使用 1.折叠面板-实现多个 创建一个文件夹demo 具体步骤请参考vue.js---vue基础 ⚫ 解决方案: 采用vue提供的单.vue文件-组件方式来封装一套然后复用 在component…

Hadoop的安装及配置

8.下面我们开始安装配置Hadoop 1&#xff09;首先下载hadoop-2.7.2的jar包 并添加到我们的jtxy1的/root/目录下 2&#xff09;yum install在线安装软件 yum install net-tools //支持ifconfig yum install vim //支持vim yum install glibc.i686 --java命令不好使 3&am…

人工智能论文GPT-3(2):2020.5 Language Models are Few-Shot Learners;微调;少样本Few-Shot (FS)

2 方法Approach 我们的基本预训练方法&#xff0c;包括模型、数据和训练&#xff0c;与GPT-2中描述的过程相似&#xff0c;只是模型规模、数据集规模和多样性&#xff0c;以及训练时长有所扩大&#xff0c;相对简单直接。 我们使用的上下文学习也与GPT-2相似&#xff0c;但在…

Web程序设计-实验03 JavaScript语言基础

题目 【实验主题】 素数问题求解。计算&#xff08;判断&#xff09; 1~100中哪些是素数、哪些是合数。 素数也称为质数&#xff0c;是只能被1及其自身整除的自然数。与素数相对应的是合数&#xff0c;合数可以被分解为若干个素数的乘积&#xff0c;这些素数称为这个合数的质…

即席查询笔记

文章目录 一、Kylin4.x1、Kylin概述1.1 定义1.2 Kylin 架构1.3 Kylin 特点1.4 Kylin4.0 升级 2、Kylin 环境搭建2.1 简介2.2 Spark 安装和部署2.3 Kylin 安装和部署2.4 Kylin 启动环境准备2.5 Kylin 启动和关闭 3、快速入门3.1 数据准备3.2 Kylin项目创建入门3.3 Hive 和 Kylin…

Qt Debug模式下应用程序输出界面乱码【已解决】

Qt Debug模式下应用程序输出乱码 一、问题描述二、解决方法三、相关测试 一、问题描述 源码为utf-8编码. Qt Creator在Debug模式下运行程序&#xff0c;下方应用程序输出界面显示乱码. 但正常运行无乱码&#xff1a; 二、解决方法 尝试修改文件编码、执行编码无果… 可参考…