JavaScript+Canvas模拟实现支付宝画年兔游戏

目录
  • 动手前的思路
    • 思考1、如何让鼠标只能在特定区域内画画?
    • 思考2、如何让绘制的图画动起来
    • 思考3、如何撤销上一步操作
    • 思考4、如何判断线条绘制完毕
  • 关键步骤

接近过年了,支付宝的集福的活动又开始了,集美们的五福集齐了没有。每年的集福活动都有一些小游戏,今年也不例外,画年画就是其中之一,本篇用canvas来写一个画年兔的游戏。

动手前的思路

画年画游戏规则是:跟着特定轮廓画出线条来。

思考1、如何让鼠标只能在特定区域内画画?

首先要获取到这个轮廓区域所在画布上的位置,判断鼠标绘画的位置是否在指定范围内。用canvas的getImageData函数能够获取到画布上有颜色的像素点,然后根据像素点分布计算出像素点所在位置。

getImageData函数的用法在我之前的文章canvas文字粒子特效中有详细介绍,不懂的可以去看看。

getImageData(canvas, ctx) {
    const data = ctx.getImageData(
        0,
        0,
        canvas.width,
        canvas.height,
    ).data;
    const gap = 4;
    const points = [];
    const length = data.length;
    for (let i = 0, wl = canvas.width * gap; i < length; i += gap) {
        if (data[i + gap - 1] == 255) {
            // 根据透明度判断
            const x = (i % wl) / gap;
            const y = Math.ceil(i / wl);
            points.push([x, y]);
        }
    }
    return points;
}

思考2、如何让绘制的图画动起来

通过定时旋转画布实现。我选择用帧动画requestAnimationFrame函数,比setInterval函数性能更好一点。

思考3、如何撤销上一步操作

将每一步绘制的点都记录到创建的栈中,每一次撤销都把上一步的绘制点删除。

思考4、如何判断线条绘制完毕

想了很久没有什么太好的办法,如果你有想法可以分享给我。当mouseup事件执行,会判断当前步骤下绘制的点数是否>=30,如果满足条件会延迟半秒执行下一步绘制,当mousedown在半秒内触发,延迟函数会取消,等待下一个mouseup事件。

// mouseup事件
const length = _this.execStack.reduce((prev, next) => {
    if (next.step == _this.curStep) {
        prev += next.points.length;
    }
    return prev;
}, 0)
if (length >= 30) {
    _this.timer = setTimeout(() => {
        if (_this.curStep == 2) {
            _this.curStep = 2.5
            _this.canEdit = false;
            _this.animate('ears_1', 3);
        } else if (_this.curStep == 4) {
            _this.curStep = 4.5
            _this.canEdit = false;
            _this.animate('shake_head', 5);
        } else if (_this.curStep == 6) {
            _this.curStep = 6.5
            _this.canEdit = false;
            _this.animate('shake_body', 7);
        } else if (_this.curStep <= 6) {
            _this.canEdit = true;
            _this.curStep += 1;
        }
        _this.execCanvas();
    }, 500);
}

关键步骤

1、创建一个RabbitPainting类,初始化时监听canvas的鼠标点击事件。要注意的是移动端和pc端监听的事件不同:

this.pcEvents = ['mousedown', 'mousemove', 'mouseup'];
this.mobileEvents = ['touchstart', 'touchmove', 'touchend'];

我的代码里对兼容的处理比较粗糙,只是将大致功能做出来了,所以大家多看看思路。

鼠标移开之后,需要解除事件监听,当鼠标重新按压时再绑定事件。mousedown事件监听流程如下:

鼠标移动时,会得到两个点,鼠标按压位置和鼠标移动位置,如果绘制的线都是从按压点到移动点的话,就会画出:

上图所示,红色的线是鼠标移动路径,黑色的线是canvas画出的线条,所以mousemove函数执行后要更新初始按压点,使前后两个点衔接在一起。

线条绘制函数如下:

drawLine(point) {
    const { ctx } = this
    ctx.beginPath()
    ctx.moveTo(point.startX, point.startY);
    ctx.lineTo(point.endX, point.endY);
    if (point.style) {
        for (let key in point.style) {
            ctx[key] = point.style[key]
        }
    }
    ctx.stroke();
    ctx.closePath()
}

2、兔子轮廓绘制,采用贝塞尔2阶函数绘制图形

// 外轮廓样式
const wrapperStyle = {
    lineWidth: "30",
    strokeStyle: this.tipPathColor[0]
}
// 内虚线样式
const innerStyle = {
    lineWidth: "3",
    strokeStyle: this.tipPathColor[1],
    lineDash: [15, 12]
}
drawCurve({ list, wrapperStyle, innerStyle }) {
    const { tempCtx: ctx } = this
    list.forEach(point => {
        const { x, y, list } = point;
        ctx.beginPath();
        ctx.moveTo(x, y);
        ctx.bezierCurveTo(...list);
        for (let key in wrapperStyle) {
            ctx[key] = wrapperStyle[key]
        }
        ctx.stroke();
        ctx.save()
        ctx.beginPath();
        ctx.moveTo(x, y);
        ctx.bezierCurveTo(...list);
        for (let key in innerStyle) {
            if (key == 'lineDash') {
                ctx.setLineDash(innerStyle[key]);
            }
            ctx[key] = innerStyle[key]
        }
        ctx.stroke();
        ctx.restore();
    })
}

贝塞尔曲线的关键在于设置p1和p2两个控制点,大家自行把握。

我的兔子轮廓总体是这样的:

3、旋转画布功能

使用canvas的rotate函数,画布的默认中心点是(0,0),所以旋转时需要用translate(x,y)函数将中心点移动到特定位置。要注意旋转后将画布的中心点还原到(0,0)。

const rotateCanvas = (centerPoints, item) => {
    ctx.save()
    ctx.translate(...centerPoints)
    ctx.rotate(Math.PI / 180 * item.curDeg)
    ctx.translate(-centerPoints[0], -centerPoints[1])
}

注意ctx.save(),用来记录画布旋转之前的状态,绘制结束后需要用ctx.restore()将画布状态还原,否则定时函数执行角度旋转时角度会累加。

4、眨眼睛动画

眨眼睛是用一张精灵图,因为图片是我自己画的,只有六帧,所以动画看起来不是很好,将就看着吧。

以上就是JavaScript+Canvas模拟实现支付宝画年兔游戏的详细内容,更多关于JavaScript Canvas画年兔游戏的资料请关注我们其它相关文章!

(0)

相关推荐

  • 一文教你用JavaScript制作个简单的大转盘游戏

    目录 背景 一.开始前的准备 二.画出大转盘 三.把奖励放上去 四.让大转盘滚起来 个人总结 背景 日常生活中,我们经常会见到形形色色的抽奖活动,例如九宫格.大转盘等等……以前都没去深入考虑过,如果让我去做这些小游戏,有哪些需要注意的事项,不试不知道,一试全是坑.正好最近有需求让我做一个大转盘游戏,那我也总结一下我的一些感想和经验. 一.开始前的准备 首先就是确定产品需求,仔细一看,emmm,就是正常的一个大转盘该有的东西,也没啥特殊要求,唯一需要注意的是大转盘的转盘个数需要动态变化,即用户设置

  • 使用JavaScript做一款无框架浏览器直接运行的益智类数字棋牌小游戏

    目录 一.游戏效果展示 二.游戏逻辑与交互设计 (一)游戏逻辑 (二)人机交互 (三)游戏界面设计 (四)游戏音乐设计 二.游戏制作过程 (一)游戏资源收集和制作 (二)游戏布局 (三)游戏响应开发 游戏界面 一.游戏效果展示 二.游戏逻辑与交互设计 由于技术有限不能做太复杂的游戏,所以做个休闲数字游戏是比较合适的,下手之前做了挺多准备,包括思考游戏逻辑.收集和制作游戏图片.音乐素材等,最后确定要完成一下几个游戏必备的内容.    (一)游戏逻辑 游戏玩法就是在原来“井字过三关”游戏的基础上加上

  • 基于Javascript开发连连看游戏小程序

    目录 01.程序设计的步骤 1. 设计点类Point 2. 设计游戏主逻辑 3. 编写函数代码 “连连看”是源自台湾的桌面小游戏,自从流入大陆以来风靡一时,也吸引众多程序员开发出多种版本的“连连看”.“连连看”考验的是各位的眼力,在有限的时间内,只要把所有能连接的相同图案,两个一对地找出来,每找出一对,它们就会自动消失,只要把所有的图案全部消完即可获得胜利.所谓能够连接,指得是:无论横向或者纵向,从一个图案到另一个图案之间的连线不能超过两个弯,其中,连线不能从尚未消去的图案上经过. 连连看游戏的

  • 基于JavaScript编写一个翻卡游戏

    目录 前言 翻卡动画 生成随机分布数组 均匀元素下的随机算法 不均匀元素下的随机算法 生成最终数组 点击事件 完整代码 前言 首先将这个游戏需求拆分成三个部分: 翻卡动画 生成随机分布数组 点击事件 翻卡动画 假如我们的盒子模型不是个二维的平面,而是有个三维的体积,让它可以有正反两面,那我们在做的时候是不是只要将它真实的翻个面就可以了.让我们来想想将它变成三维的方法. 之后发现了这个属性: transform: translateZ(1px); 使用了它,就可以把盒子内部的元素与盒子的底部撑出个

  • JavaScript html5 canvas实现图片上画超链接

    本文实例为大家分享了html5 canvas在图片上画超链接的具体代码,供大家参考,具体内容如下 1. html <canvas id="canvasFile" style="margin-top:15px;" width="500" height="400"></canvas> <input type="button" id="btnRedo" value

  • JavaScript Canvas编写炫彩的网页时钟

    本文实例为大家分享了JavaScript Canvas编写炫彩网页时钟的具体代码,供大家参考,具体内容如下 只是利用了Canvas制作的. 示意图如下: <!DOCTYPE html> <html> <head> <meta http-equiv = "Content-Type" content = "text/html"; charsert = "utf-8" /> <title> 网

  • javascript canvas实现雨滴效果

    本文实例为大家分享了javascript canvas实现雨滴效果的具体代码,供大家参考,具体内容如下 先看效果 看起来很炫酷,其实就是实现了雨滴的掉落还有最后的圆 还是看源码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=devi

  • JavaScript canvas实现动态点线效果

    本文实例为大家分享了JavaScript canvas实现动态点线效果的具体代码,供大家参考,具体内容如下 效果预览 1.实现效果 画彩色点 相近的点产生连线 点线运动,遇到边界反弹 选中点,可拖动点改变位置* 2.具体实现 初始化相关变量 var c = document.getElementById("myCanvas"); //设置canvas大小 c.height = document.body.offsetHeight; c.width = document.body.off

  • JavaScript Canvas绘制六边形网格

    本文实例为大家分享了JavaScript Canvas绘制六边形网格的具体代码,供大家参考,具体内容如下 使用Canvas绘制六边形网格. 主要思路是先画给定中心点的六边形,然后二重循环遍历所有中心点,画所有的六边形. <!DOCTYPE HTML> <html> <body> <canvas id="myCanvas" width="300" height="150">     <p>

  • 详解JavaScript+Canvas绘制环形进度条

    目录 效果图 思考 实现思路 具体代码实现 效果图 思考 移动端的场景里经常会出现环形进度条的功能,在实现这个功能前,我预想的解决方案大致有: echarts.antv.canvas.svg 前面两种第三方提供的解决方案当然是简单,拿到案例修整一下即可,但是需要下载依赖,而且代码量不小.有没有不需要依赖第三方包,采用原生的写法,独立封装成一个组件,降低耦合,而且性能优越? 当然,那就主要介绍canvas的使用 实现思路 可以展示整个圆.半圆以及任意角度弧形(左右对称)的进度条.整体思路如下: 1

  • JavaScript+canvas实现五子棋游戏

    本文实例为大家分享了JavaScript+canvas实现五子棋游戏的具体代码,供大家参考,具体内容如下 效果截图: 代码实现: <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initia

  • JavaScript canvas实现字符雨效果

    本文实例为大家分享了JavaScript canvas实现字符雨效果的具体代码,供大家参考,具体内容如下 字符雨效果 分析如何实现 字符雨从上往下逐渐消失: 这是canvas每次画字符的时候就画一遍黑色背景,但是这个背景是有透明度的,并且这个黑色背景的透明度还比较小,只有零点零八(经过测试,0.08比较合适,也可以更改查看效果):字符是从上往下落,上面的字符先出现,下面的字符后出现,程序重复地画黑色背景,就算有透明度,叠加起来,上面的字符就会先被覆盖,下面的后出现的字符还是还比较明显,就形成了逐

  • JavaScript canvas复刻苹果发布会环形进度条

    目录 前言 基础 Dom 结构 基本变量 画圆 画弧线 让画面动起来 总结 前言 canvas 真是一个好东西,它给前端插上了想象的翅膀,伴随着 h5 而来,将 web 代入了新的领域,基于canvas 技术实现的各种酷炫效果和2d.3d 游戏,也让浏览器能承载更加强大的功能.尤其是它性能还很好,搞游戏再合适不过了,我就喜欢用 canvas 写一些小游戏玩. 在线地址 最近无意中看到前段时间写的这个小效果,觉得挺有意思的,就分享出来:这是苹果ios 12 发布会上库克 ppt 里展示的内容,一个

  • JavaScript canvas 实现用代码画画

    目录 引言 第一部分:图形绘制 画画第一步:准备好画布和画笔 画画第二步:给画笔调个粗细 画画第三步:给画笔沾点颜料 画画第四步:描点画图 (1)画一个三角形 (2)画一个矩形 (3)画一个圆 (4)进阶:画一个笑脸 画画第五步:署名 第二部分:图片绘制 引言 canvas是HTML的一个绘图标签,与SVG用标签绘图不同,canvas是通过Js代码进行图形绘制,多用于移动端分享海报绘制以及照片裁剪等场景.本文将结合部分canvas API介绍在Vue项目中如何使用canvas进行简单的图形绘制和

随机推荐