最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Html5 Canvas如何实现一个刮刮乐游戏 Html5 Canvas实现一个刮刮乐游戏方法
时间:2022-06-25 18:02:21 编辑:袖梨 来源:一聚教程网
本篇文章小编给大家分享一下Html5 Canvas实现一个刮刮乐游戏方法,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。
Demo 和 项目源码 .
2. 实现
我们创建一个 ScrapAward 类,通过传入 option 和调用其 restart() 方法实现重新开始。
(1)定义 option 参数及 ScrapAward 结构
class ScrapAward {
constructor(userOption) {
this.option = {
canvasId: 'canvas', // canvas的id
backgroundImageUrl: '', // 背景图url
width: 320, // canvas宽度
height: 160, // canvas高度
backgroundSize: '100% 100%',
coverImage: { // 覆盖图层背景图url
url: '',
width: 320,
height: 160,
},
callback: () => {}, // 刮奖完成的回调函数
};
this.ctx = null;
this.init(userOption); // 初始化
}
// 初始化方法
init(userOption) {
}
// 重新开始也是一次初始化
restart(userOption) {
if (userOption) {
this.init(userOption);
} else {
this.init({});
}
}
}
(2) init 初始化
首先合并用户的配置 userOption 和默认 option , 等背景图片加载完成后调用fillCanvas()方法绘制覆盖层的图片后设置 canvas 的背景图。
当上述行为完成后,我们便监听鼠标或者touch事件。刮奖这一行为其实是canvas对鼠标或者touch的移动路径进行绘画,只不过是将绘画的路径变成了透明,这种效果我们通过设置ctx.globalCompositeOperation = 'destination-out';即可实现。
init(userOption) {
// 合并用户配置
if (Object.assign) {
Object.assign(this.option, userOption);
} else {
extend(this.option, userOption, true);
}
// 定义一系列变量
let that = this,
img = (this.img = new Image()), //背景图片
imgLoaded = false, //背景图是否加载完成
canvas = (this.canvas = document.querySelector(`#${this.option.canvasId}`)),
hastouch = 'ontouchstart' in window ? true : false,
tapstart = hastouch ? 'touchstart' : 'mousedown',
tapmove = hastouch ? 'touchmove' : 'mousemove',
tapend = hastouch ? 'touchend' : 'mouseup',
coverImg = (this.coverImg = new Image()),
hasDone = false, // 是否刮奖完毕
coverImgLoad = false;
that.mousedown = false; //鼠标的mousedown事件或者touchmove事件是否开启
// 移除事件监听,用于重新开始
if (this.canvas) {
this.canvas.removeEventListener(tapstart, eventDown);
this.canvas.removeEventListener(tapend, eventUp);
this.canvas.removeEventListener(tapmove, eventMove);
}
coverImg.src = this.option.coverImage.url;
coverImg.crossOrigin = 'Anonymous'; // 解决一些跨域问题
img.src = this.option.backgroundImageUrl;
var w = (img.width = this.option.width),
h = (img.height = this.option.height);
this.canvasOffsetX = canvas.offsetLeft;
this.canvasOffsetY = canvas.offsetTop;
canvas.width = w;
canvas.height = h;
this.ctx = canvas.getContext('2d');
let ctx = this.ctx;
this.img.addEventListener('load', backgroundImageLoaded);
this.option.coverImage.url && this.coverImg.addEventListener('load', coverImageLoaded);
// 背景图片加载完成后
function backgroundImageLoaded(e) {
imgLoaded = true;
fillCanvas();
canvas.style.background = 'url(' + img.src + ') no-repeat';
canvas.style.backgroundSize = that.option.backgroundSize || 'contain';
}
// 覆蓋图片加载完成后
function coverImageLoaded(e) {
coverImgLoad = true;
fillCanvas();
canvas.style.background = 'url(' + img.src + ') no-repeat';
canvas.style.backgroundSize = that.option.backgroundSize || 'contain';
}
// 绘制canvas
function fillCanvas() {
if (that.option.coverImage.url && (!imgLoaded || !coverImgLoad)) return;
if (!that.option.coverImage.url) {
ctx.fillStyle = that.option.coverImage.color || 'gray';
ctx.fillRect(0, 0, w, h);
} else {
ctx.drawImage(coverImg, 0, 0, that.option.coverImage.width, that.option.coverImage.height);
}
ctx.globalCompositeOperation = 'destination-out';
canvas.addEventListener(tapstart, eventDown);
canvas.addEventListener(tapend, eventUp);
canvas.addEventListener(tapmove, eventMove);
}
// 点击开始事件
function eventDown(e) {
e.preventDefault();
that.mousedown = true;
}
// 点击结束事件
function eventUp(e) {
e.preventDefault();
that.mousedown = false;
}
// 刮奖事件
function eventMove(e) {
if (hasDone) return; // 刮奖结束则return
let ctx = that.ctx;
e.preventDefault();
if (that.mousedown) {
if (e.changedTouches) {
e = e.changedTouches[0];
}
var x = (e.clientX + document.body.scrollLeft || e.pageX) - that.canvasOffsetX || 0,
y = (e.clientY + document.body.scrollTop || e.pageY) - that.canvasOffsetY || 0;
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI * 2);
ctx.fill();
}
}
}
(3)刮奖完毕的实现
上述代码实现刮奖的效果,但是一般的场景是用户刮奖的面积超过一半时,覆盖图层全部散开,此时为刮奖完成的状态。
如何知道刮奖的面积超过一半了呢? canvas 中的 ctx 对象提供了一个方法 getImageData() , 该方法可返回某个区域内每个像素点的数值的组成的数组,数组中4个元素表示一个像素点的rgba值。
因此我们可以判断 rgba 中的 a 值透明度,透明度小于 256 的一半( 128 )即可视为透明状态,计算透明 a 值的百分比.
判断 a 值百分比大于 50 , 则调用 ctx.clearRect(0, 0, w, h); 清除画布, 并执行成功回调 callback .
function eventMove(e) {
if (hasDone) return; // 刮奖结束则return
let ctx = that.ctx;
e.preventDefault();
if (that.mousedown) {
if (e.changedTouches) {
e = e.changedTouches[0];
}
var x = (e.clientX + document.body.scrollLeft || e.pageX) - that.canvasOffsetX || 0,
y = (e.clientY + document.body.scrollTop || e.pageY) - that.canvasOffsetY || 0;
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI * 2);
ctx.fill();
}
handleFilledPercentage(getFilledPercentage());
}
// 计算已经刮过的区域占整个区域的百分比
function getFilledPercentage() {
let imgData = that.ctx.getImageData(0, 0, w, h);
// imgData.data是个数组,存储着指定区域每个像素点的信息,数组中4个元素表示一个像素点的rgba值
let pixels = imgData.data;
let transPixels = [];
for (let i = 0; i 50) {
// 当像素点的个数超过 50% 时,清空画布,显示底图
ctx.clearRect(0, 0, w, h);
hasDone = true;
that.option.callback();
}
}
3. 使用
将代码引入 html 后,新建 new scraAward(option) 即可实现。页面结构如下:
实现一个“刮刮乐”游戏
刮刮下面图片看看什么效果哈哈哈,
相关文章
- 创世秩序东院藏有秘密哪里有人指导过法详解 11-27
- dnf徐福记觉醒插图外观一览 11-27
- 原神4.3秘宝迷踪第二天攻略 藏宝地位置分享 11-27
- 崩坏星穹铁道黄金与机械难度12通关攻略 11-27
- dnf燃武套武器装扮全职业外观图 11-27
- dnf燃武套红色外观全职业一览 11-27
