-
Notifications
You must be signed in to change notification settings - Fork 183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
canvas+vue实现60帧每秒的抢金币动画(类天猫红包雨) #70
Labels
Comments
没源码吗 |
@TigerLiv 源码混杂囤太多其他东西 核心代码都在文章里了 参考摸索做一遍 理解会更深刻一点 |
请问randomRound这个随机生成金币的方法在哪 没有找到 |
好东西,点赞,期待彻底开源 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
先看看我们要做的效果
一、canvas动画核心概念
重点是理解canvas动画的基本步骤
在MDN canvas 动画文档上的是4步
初学者可以再简单一些,我们先不管状态保存,直接两步走:
用定时器或者window.requestAnimationFrame定时重复以上两步即可
二、抢金币核心原理
想象一下整个业务场景,我们先梳理出3个要解决的核心问题:
1、生成红包,这里有两种解决方案
* 1、统一生成所有的红包对象,从上到下分布在y轴,触发运动后后整体向下运动
* 2、在屏幕上方持续生成新红包对象,红包一旦生成,立刻开始运动(本次选择此方案)
2、运动,canvas动画原理
3、用户点击红包,计算是否点中红包(事件只能绑定在canvas这一层,需要根据点击位置进行计算)
三、核心功能
1、预缓存图片/离屏canvas
2、canvas绘制多图,改变每一帧形成动画
3、判断点击位置,冒泡+1效果
下面都是基于vue的代码,不能直接跑的,用于理解核心就好了
最好是自己理解核心原理后动手做个最简单的demo
1、预缓存图片/离屏canvas
页面上感觉有很多很多金币在按各种角度掉落
其实页面上一共就4种金币图片,只是他们的大小、速度不一样,看起来有每一个都不一样
我们可以先把这4张图片全都加载好
创建离屏canvas的方法如下
2、canvas绘制多图,改变每一帧形成动画
首先初始化canvas
这里我们直接把canvas的上下文ctx存在data里面,方便在各个方法里面读取。
毕竟这里不像单独的一个JS模块,可以用闭包来封装一个独立的上下文,而在vue里面也不建议声明全局变量
绘制多图,其实就是循环遍历上面创建好的图片数组imgArr,然后对于每个图片对象,都调用this.ctx.drawImage()方法即可
下面我们把图片转变化金币对象
把图片数组imgArr替换成金币对象数组coinArr,这个数组是由一个个的金币对象Coin组成,金币对象自身除了有图片,还有大小、物理位置、下落速度等参数,也就是说,每个金币对象缓存自己的所有绘制信息,这里用的是面向对象的思维
每一帧,循环这个金币数组,然后绘制出所有的金币对象
如果要运动起来,每一帧让每个金币的y轴位置往下掉一点,就是这句y: coin.y + coin.speed,那么绘制下一帧时,其他信息都不变,每个金币都往下移动了一点点,连贯起来,这不同的一帧一帧组合起来就成了运动的动画了
先看绘制的代码
那么怎么连贯运动起来呢,不断的执行this.drawCoins()方法即可,既然做动画,我们肯定知道window.requestAnimationFrame这个api,不知道的可以看看文档window.requestAnimationFrame - Web API 接口参考 | MDN
还记得刚开始说的动画核心两步走吗
到这里,我们其实已经能让金币运动起来了,不过我们要做的是让很多很多金币不断的往下掉,所以我们选择在运动的过程中,不断生成新的金币对象,然后push到this.coinArr中
因为每个金币的初始y的位置都是屏幕上方,所以看起来都是不断生成金币然后往下掉的
至于计算大小的方法,这个比较随意了
最后,把上面的汇总起来,开启动画的方法是这样的
到这里,我们先总结一下上面的内容
1、初始化canvas
2、缓存金币图片,生成金币对象,每个金币对象包含自身信息
3、不断生成金币对象,并增加到要遍历运动的数组this.coinArr
4、通过window.requestAnimationFrame,每一帧都用canvas重新遍历绘制this.coinArr,每一帧都改变this.coinArr里面的每一个对象的y值大小,形成运动感
3、判断点击位置,冒泡+1效果
通过上面的效果图,我们可以看到,点击金币时,对应的这个金币会消失(如果有重叠,只会消失最上面的那个金币),而且还会有个+1的效果,并缓慢上移消失
先思考一下逻辑
1、绑定点击事件
2、计算位置,遍历当前整个金币数组,看看点击在哪个金币上,找出最上面那个,然后删除这个金币对象
3、在点击位置上,绘制一个+1效果
首先,canvas本身就是一个DOM对象,绘制在它上面的金币并不是dom对象,无法绑定点击事件,所以只能绑定在canvas上面,通过event拿到点击位置,有点事件代理的味道吧
既然拿到此刻的点击位置,而当前的金币数组this.coinArr也知道,数组里面的每个金币对象都维护了自身的信息,其中就包括了位置和金币大小
那么,只要遍历一下,如果点击位置在这个金币的大小范围之内,那么是不是可以认为点击中了这个金币?
但,同一时刻,有可能点中了很多个重叠的金币,那么我们遍历时,把这几个金币都拿出来,只要最上面那个就好了
既然拿到了此刻的位置,在当前位置绘制一个冒泡效果应该不是难事,只要处理好冒泡的移动和消失即可,本质上就跟上面绘制金币是一样的
1、存一个this.bubbleArr数组,动画中循环遍历绘制它里面的对象bubble
2、bubble有位置信息,加多一个透明度opacity,运动的过程中,不断减小透明度,直到变为0,就把这个bubble从数组上删除即可
性能测试
到这里,整个运动的核心原理就讲完了,我们测试一下动画的性能
在chrome的性能测试里面可以看到,整个运动过程的fps稳稳保持在60帧每秒,可以说是性能很不错了
The text was updated successfully, but these errors were encountered: