用HTML5的<canvas>元素实现刮刮乐游戏

news2024/11/15 21:05:59

用HTML5的<canvas>元素实现刮刮乐

用HTML5的<canvas>元素实现刮刮乐,要求:将上面的“图层”的图像可用鼠标刮去,露出下面的“图层”的图像。

示例从简单到复杂。

简单示例

准备两张图像,我这里上面的图像top_image.png,下面的图像bottom_image.png,如下图:

 

 

我这里为方便 ,经图片和源码文件放在同一个文件夹中。

先看用一个canvas元素实现刮刮乐,源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>刮刮乐(Scratch Card)</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: #f0f0f0; /* 背景色 */
        }
        canvas {
            background-image: url('bottom_image.png'); /* 底层图片 */
            background-size: cover;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="356" height="358"></canvas>
    <script>
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");

        // 加载上层图片(可被刮去的图层)
        var img = new Image();
        img.src = "top_image.png"; // 上层图片路径
        img.onload = function() {
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        };

        // 标记是否按下鼠标(开始刮卡)
        var isDown = false;

        // 鼠标按下事件
        canvas.addEventListener('mousedown', function() {
            isDown = true;
            // 切换到“擦除”模式
            ctx.globalCompositeOperation = 'destination-out';
        });

        // 鼠标松开事件
        canvas.addEventListener('mouseup', function() {
            isDown = false;
        });

        // 鼠标移动事件
        canvas.addEventListener('mousemove', function(event) {
            if (isDown) {
                let x = event.offsetX;
                let y = event.offsetY;
                // 绘制擦除效果
                ctx.beginPath();
                ctx.arc(x, y, 20, 0, Math.PI * 2, false); // 使用圆形笔触
                ctx.fill();
                ctx.closePath();
            }
        });
    </script>
</body>
</html>

下面用两个canvas元素实现刮刮乐,底层图片和上层图片各用一个canvas元素,效果和上面的一样。实现的源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>刮刮乐(Scratch Card)2</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: #f0f0f0;
        }
        #container {
            position: relative;
            width: 356px;
            height: 358px;
        }
        canvas {
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>
<body>
    <div id="container">
        <canvas id="bottomCanvas" width="356" height="358"></canvas> <!-- 底层Canvas -->
        <canvas id="topCanvas" width="356" height="358"></canvas> <!-- 上层Canvas -->
    </div>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            var bottomCanvas = document.getElementById('bottomCanvas');
            var topCanvas = document.getElementById('topCanvas');
            var bottomCtx = bottomCanvas.getContext('2d');
            var topCtx = topCanvas.getContext('2d');

            // 加载底层图片
            var bottomImage = new Image();
            bottomImage.src = 'bottom_image.png'; // 底层图片路径
            bottomImage.onload = function() {
                bottomCtx.drawImage(bottomImage, 0, 0, bottomCanvas.width, bottomCanvas.height);
            };

            // 加载上层图片
            var topImage = new Image();
            topImage.src = 'top_image.png'; // 上层图片路径
            topImage.onload = function() {
                topCtx.drawImage(topImage, 0, 0, topCanvas.width, topCanvas.height);
            };

            var isDown = false;

            // 鼠标按下事件
            topCanvas.addEventListener('mousedown', function() {
                isDown = true;
                topCtx.globalCompositeOperation = 'destination-out';
            });

            // 鼠标松开事件
            topCanvas.addEventListener('mouseup', function() {
                isDown = false;
            });

            // 鼠标移动事件
            topCanvas.addEventListener('mousemove', function(event) {
                if (!isDown) return;
                var x = event.offsetX;
                var y = event.offsetY;
                // 绘制擦除效果
                topCtx.beginPath();
                topCtx.arc(x, y, 20, 0, Math.PI * 2, false); // 使用圆形笔触
                topCtx.fill();
                topCtx.closePath();
            });
        });

    </script>
</body>
</html>

复杂示例

下面是改进,从列表框(下拉框)选择图片刮刮乐,增加了游戏的趣味性。

先给出效果

我这里游戏图片:

源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>刮刮乐(Scratch Card)3</title>
    <style>
        div{ 
            margin:20px;
            text-align:center;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: #f0f0f0;
        }
        #container {
            position: relative;
            width: 356px;
            height: 358px;
        }
        canvas {
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>
<body>
    <div> 
        选择游戏图片
        <select id="mySelect" onchange="loadImages()"> <!-- 添加 onchange 事件 -->
            <option value="1">1</option> <!-- 更改 value 以匹配图像名称 -->
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
    <div>

    <div id="container">
        <canvas id="bottomCanvas" width="356" height="358"></canvas> <!-- 底层Canvas -->
        <canvas id="topCanvas" width="356" height="358"></canvas> <!-- 上层Canvas -->
    </div>

    <script>
        function loadImages() {
            var selectElement = document.getElementById('mySelect');
            var selectedValue = selectElement.options[selectElement.selectedIndex].value;

            var bottomCanvas = document.getElementById('bottomCanvas');
            var topCanvas = document.getElementById('topCanvas');
            var bottomCtx = bottomCanvas.getContext('2d');
            var topCtx = topCanvas.getContext('2d');

            // 清除画布
            bottomCtx.clearRect(0, 0, bottomCanvas.width, bottomCanvas.height);
            topCtx.clearRect(0, 0, topCanvas.width, topCanvas.height);

            // 加载底层图片
            var bottomImage = new Image();
            bottomImage.src = 'img/bottom' + selectedValue + '.png';
            bottomImage.onload = function() {
                bottomCtx.drawImage(bottomImage, 0, 0, bottomCanvas.width, bottomCanvas.height);
            };

            // 重新加载并绘制上层图片
            var topImage = new Image();
            topImage.src = 'img/top' + selectedValue + '.png'; // 确保这里的路径正确匹配你的图片路径和命名
            topImage.onload = function() {
                topCtx.globalCompositeOperation = 'source-over'; // 重置合成操作为默认值
                topCtx.drawImage(topImage, 0, 0, topCanvas.width, topCanvas.height);
                // 确保刮刮效果重新应用
                addScratchEffect(topCanvas, topCtx);
            };
        }

        function addScratchEffect(canvas, ctx) {
            var isDown = false;
            // 移除之前可能添加的事件监听器
            canvas.onmousedown = null;
            canvas.onmouseup = null;
            canvas.onmousemove = null;

            // 鼠标按下事件
            canvas.onmousedown = function() {
                isDown = true;
                ctx.globalCompositeOperation = 'destination-out'; // 设置合成操作以实现刮效果
            };

            // 鼠标松开事件
            canvas.onmouseup = function() {
                isDown = false;
            };

            // 鼠标移动事件
            canvas.onmousemove = function(event) {
                if (!isDown) return;
                var x = event.offsetX;
                var y = event.offsetY;
                // 绘制擦除效果
                ctx.beginPath();
                ctx.arc(x, y, 20, 0, Math.PI * 2); // 使用圆形笔触
                ctx.fill();
            };
        }

        // 页面加载完毕后初始化画布
        document.addEventListener('DOMContentLoaded', function() {
            loadImages(); // 页面加载时也加载图片
        });

    </script>
</body>
</html>

本文是对https://blog.csdn.net/cnds123/article/details/112392014 例子的补充

关于HTML5中,使用<select>元素创建一个列表框(下拉框),并使用JavaScript来操作,可参见https://blog.csdn.net/cnds123/article/details/128353007

 

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

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

相关文章

【Spring】spring中怎么解决循环依赖的问题

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Spring ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 解决步骤 考虑 结语 我的其他博客 前言 在软件开发中&#xff0c;依赖注入是一种常见的设计模式&#xff0c;它可以帮助我们管…

探讨javascript的程序性能

如果阅读有疑问的话&#xff0c;欢迎评论或私信&#xff01;&#xff01; 本人会很热心的阐述自己的想法&#xff01;谢谢&#xff01;&#xff01;&#xff01; 文章目录 Web WorkerWorker之间通讯Worker销毁 Web Worker 当我们需要处理一些比较耗时的任务时&#xff0c;我们…

杭电OJ 2045 不容易系列之(3)—— LELE的RPG难题 C++

思路&#xff1a;我先模拟了一下1&#xff0c;2&#xff0c;3的情况&#xff0c;对应的是3 6 6&#xff0c;模拟到4的时候就有感觉了&#xff0c;1是不受到任何制约的&#xff0c;2到n-1是收到了前面一个的制约&#xff0c;n受到了n-1与1的制约&#xff0c;那么就可以去判断4 …

七通道NPN 达林顿管GC2003,专为符合标准 TTL 而制造,最高工作电压 50V,耐压 80V

GC2003 内部集成了 7 个 NPN 达林顿晶体管&#xff0c;连接的阵列&#xff0c;非常适合逻辑接口电平数字电路&#xff08;例 如 TTL&#xff0c;CMOS 或PMOS 上/NMOS&#xff09;和较高的电流/电压&#xff0c;如电灯电磁阀&#xff0c;继电器&#xff0c;打印机或其他类似的负…

构造pop链

反序列化视频笔记 第一步&#xff1a;找到目标触发echo调用$flag 第二步&#xff1a;触发_invoke函数调用appeng函数$varflag.php&#xff08;把对象当成函数&#xff09; 第三步&#xff1a;给$p赋值为对象&#xff0c;即function成为对象Modifier却被当成函数调用&#xff…

csv大数值不显示E科学计算法的解决方案

背景&#xff1a; 从其他系统获取到一个商品mid的大的数值的csv文件&#xff0c;然后使用excel打开的时候有各种问题&#xff0c;本文记录下怎么正确的展示这个大数值的csv文件 正确展示数值精度&#xff1a; 数值展示错误 正确展示的方法&#xff1a; 1使用文本编辑器比如…

分割回文串 复原IP地址 子集 递增子序列

131.分割回文串 力扣题目链接(opens new window) 给定一个字符串 s&#xff0c;将 s 分割成一些子串&#xff0c;使每个子串都是回文串。 返回 s 所有可能的分割方案。 示例: 输入: "aab" 输出: [ ["aa","b"], ["a","a"…

【报名指南】2024年第九届数维杯数学建模挑战赛报名全流程图解

1.官方报名链接&#xff1a; 2024年第九届数维杯大学生数学建模挑战赛http://www.nmmcm.org.cn/match_detail/32 2.报名流程&#xff08;电脑与手机报名操作流程一致&#xff09; 参赛对象为在校专科生、本科生、研究生&#xff0c;每组参赛人数为1-3人&#xff08;指导老师不…

「算法」常见位运算总结

位运算符 异或 按位异或可以实现无进位相加&#xff0c;所谓无进位相加&#xff0c;就是在不考虑进位的情况下将两个数相加&#xff08;后面有道题需要用到这种操作&#xff09; 异或的运算律 ①a ^ 0 a ②a ^ a 0 ③a ^ b ^ c a ^ ( b ^ c ) 有符号右移>> 将一个…

(C语言)函数详解(下) 项目多文件操作 extern ,static详解

&#xff08;C语言&#xff09;函数详解上&#xff1a;http://t.csdnimg.cn/ceDqA 下面我们进行函数下的学习。 目录 我们 1. 函数的声明和定义 1.1 单个文件 1.2 多个文件 2. static和extern 2. 1 static 修饰局部变量&#xff1a; 2. 2 static修饰全局变量 2. 3 st…

HarmonyOS—编译构建概述

编译构建是将应用/服务的源代码、资源、第三方库等&#xff0c;通过编译工具转换为可直接在硬件设备上运行的二进制机器码&#xff0c;然后再将二进制机器码封装为HAP/APP软件包&#xff0c;并为HAP/APP包进行签名的过程。其中&#xff0c;HAP是可以直接运行在模拟器或真机设备…

Java8 - LocalDateTime时间日期类使用详解

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&…

又挖到宝了!国人团队研发的AI视频工具PixVerse,这么好用居然还完全免费!(强烈推荐)

昨天发了一款国产免费的 AI 绘画工具 Dreamina 的介绍&#xff1a; 居然才发现&#xff01;字节跳动旗下国产AI绘画工具Dreamina&#xff0c;这么好用居然还免费&#xff01;&#xff08;强烈推荐&#xff09; 发现大家对国产 AI 工具还挺感兴趣的。今天继续帮大家挖国产的 A…

Python环境搭建:一站式指南

在当前AIGC技术蓬勃发展的背景下&#xff0c;Python作为人工智能领域最受青睐的编程语言之一&#xff0c;成为我们必须掌握的技能。因此&#xff0c;搭建一个适合自己的Python环境成为了每个Python开发者的首要任务。本文将为您提供一站式的Python环境搭建指南&#xff0c;帮助…

学习:Sora技术报告Video generation models as world simulators,2024.2

原文链接&#xff1a; Video generation models as world simulators (openai.com) 摘要&#xff1a; 我们探索了在视频数据上大规模训练生成模型。具体来说&#xff0c;我们在可变片长、分辨率和纵横比的视频和图像上联合训练文本条件扩散模型text-conditional diffusion mo…

腾讯云2024年优惠活动和云服务器优惠价格清单,3月最新整理

腾讯云优惠活动2024新春采购节活动上线&#xff0c;云服务器价格已经出来了&#xff0c;云服务器61元一年起&#xff0c;配置和价格基本上和上个月没什么变化&#xff0c;但是新增了8888元代金券和会员续费优惠&#xff0c;腾讯云百科txybk.com整理腾讯云最新优惠活动云服务器配…

上云还是下云,最大挑战是什么?| 对话章文嵩、毕玄、王小瑞

近半年来&#xff0c;公有云领域频频发生阿里云、滴滴等平台崩溃事件&#xff0c;与此同时&#xff0c;马斯克的“X 下云省钱”言论引起了广泛关注&#xff0c;一时间&#xff0c;“上云”和“下云”成为热议话题。在最近举办的 AutoMQ 云原生创新论坛上&#xff0c;AutoMQ 联合…

【计算机网络】五种IO模型与IO多路转接之select

文章目录 一、五种IO模型二、非阻塞IO1.fcntl2.实现函数SetNoBlock3.轮询方式读取标准输入 三、I/O多路转接之select1.初识select2.select函数原型3.socket就绪条件4.select的特点5.select缺点6.select使用案例--只读取数据的server服务器1.err.hpp2.log.hpp3.sock.hpp4.select…

力扣SQL50 使用唯一标识码替换员工ID 查询

Problem: 1378. 使用唯一标识码替换员工ID 思路 left join&#xff1a;左连接 Code select eu.unique_id,e.name from Employees e left join EmployeeUNI eu # left join 左连接 on e.id eu.id;

模型练习史

文章目录 肌肉光头vikingtorso死侍蓝毒液卡通girlwalletdog headman anatomy总结 肌肉光头 viking torso 死侍 蓝毒液 卡通girl wallet dog head man anatomy 总结 zbrush 与 blender 结合使用, 善 !