canvas(五角星碰撞)

马上9月份要找工作了,琢磨着要做个作品作为面试时的加分项。

本来打算仿一个淘宝网,但写完淘宝首页竟花了我一个星期!!!光html、css就有4000多行,看着首页都能想象出来后台数据的庞大,估计半年都写不完这个作业了,想罢果断放弃掉做淘宝的任务。

最终决定做一个尽量炫一点的个人网站。

在参考了liuyubobobo老师关于canvas的课程(这位老师的canvas课程真的炒鸡好~!!)后,我在这个个人网站的顶部横幅中添加了一个这样的效果,如下图


在canvas画布我添加了30个大小随机、运动方向随机、运动速度随机、碰到画布边缘会反弹回来的五角星。

作为一个从来没用过canvas画图的新手,在这个过程中也踩了不少坑。


实现:

html代码如下:

[html]  view plain  copy
  1. <div class="carouselBox">  
  2.         <canvas id="stars">请升级到最新的浏览器以观看最佳效果</canvas>  
  3.         <h1>兴趣使然的小站</h1>  
  4. </div>  
当canvas无法显示的时候,canvas标签内的字符就会显示出来。


css代码如下,这里我是用less表示的(不懂这种表示法的同学稍微百度一下,so easy):

[css]  view plain  copy
  1. .carouselBox{  
  2.     width100%;  
  3.     height300px;  
  4.     background-color: rgba(2002002550.3);  
  5.     positionrelative;  
  6.     text-aligncenter;  
  7.     #stars{  
  8.         positionabsolute;  
  9.         left: 0;  
  10.         top: 0;  
  11.         z-index5;  
  12.     }  
  13.     h1{  
  14.         positionrelative;  
  15.         z-index10;  
  16.         font-size50px;  
  17.         line-height300px;  
  18.         color: rgba(0000.7)  
  19.     }  
  20. }  
h1标签的字要在canvas画布的上方,不能被遮盖,因此设置了z-index,为了让z-index生效,设置了position:relative。

canvas画布的长度和宽度我放在了js文件中实现。


重点在JS代码上:

我这里在获取元素用到了jquery,你不用jqueyr来获取,改用document.getElementById之类的原生javascript方法当然也没有问题。

首先获取canvas对象和canvas上下文,并设置canvas画布的高宽。

[javascript]  view plain  copy
  1. //五角星画布  
  2.     var carouselBox = $('.carouselBox')  
  3.     var carouselHeight = carouselBox.height()//获取canvas外层的盒子高度  
  4.     var carouselWidth = carouselBox.width()//获取canvas外层的盒子高度  
  5.     var drawing2 = $('#stars').get(0)//通过jquery获得一个用jquery包装的canvas对象,由get(0)方法获取原生canvas对象  
  6.     //一定不能用jquery来设置高度与宽度,否则会出现莫名其妙的错误  
  7.     drawing2.height = carouselHeight//将canvas画布填满到外层盒子  
  8.     drawing2.width = carouselWidth  
  9.     var context2 = drawing2.getContext('2d')//获取canvas的上下文  

这其中要注意的是,canvas画布设置宽高一定要通过 canvas.height和canvas.width的方式来设置。

一定不能由canvas.style.height,canvas.style.width或者jquery方式$canvas.css({....})来设置宽高!!!否则会让画布里的坐标单位出现问题,导致你画的图像完全不在你预期的位置上。


接下来,先设置一个for循环来随机生成30个五角星的属性,每一组属性生成一个对象,并将生成的30个对象依次推入一个数组中。

[javascript]  view plain  copy
  1. var stars = []//用来装五角星的数组  
  2. for (var i = 0; i < 30; i++) {  
  3.     var R = Math.floor(Math.random()*100+155)  
  4.     var G = Math.floor(Math.random()*100+155)  
  5.     var B = Math.floor(Math.random()*100+155)  
  6.     var r = Math.random()*30 + 20  
  7.     var rot = Math.random()*360  
  8.     aStar = {  
  9.         color:'rgb('+R+','+G+','+B+')',  
  10.         r:r,  
  11.         x:Math.random()*(drawing2.width - 2*r) + r,  
  12.         y:Math.random()*(drawing2.height - 2*r) + r,  
  13.         rot:rot,  
  14.         vx:(Math.random()*2+2)*Math.pow(-1,Math.floor(Math.random()*100)),  
  15.         vy:(Math.random()*2+2)*Math.pow(-1,Math.floor(Math.random()*100)),  
  16.         wv:(Math.random()*2+2)*Math.pow(-1,Math.floor(Math.random()*100))  
  17.     }  
  18.     stars[i] = aStar  
  19. }  


用setInterval()方法来每隔30毫秒调用绘制函数,并调用函数更新每个五角星的位置状态和速度状态

[javascript]  view plain  copy
  1. setInterval(function(){  
  2.     draw(context2)//绘制函数  
  3.     update(drawing2.width,drawing2.height)//更新每个五角星的状态  
  4. },30)  


绘制函数如下:

将每个五角星的属性传入到drawStar()方法,从而创建大小、运动方向不同的五角星

[javascript]  view plain  copy
  1. function draw(context){  
  2.     var canvas = context.canvas  
  3.     context.clearRect(0,0,canvas.width,canvas.height)//设置一个矩形区域,将该矩形区域中的所有内容清除,会将背景一起清除掉  
  4.     context.globalCompositeOperation = 'xor'//全局设定,两图案相交处取空  
  5.     for (var i = 0; i < stars.length; i++) {  
  6.         context.fillStyle = stars[i].color//设置五角星填充颜色  
  7.         drawStar(context2,stars[i].r,stars[i].x,stars[i].y,stars[i].rot)  
  8.         context.fill()  
  9.     }  
  10. }  


drawStar方法如下

这里用图形变换的方法来绘制每个五角星,由于图形变换都是基于上次变换结果进行绘制的,因此需要设置“存储点”,在绘制完一个五角星之后回到“存储点”。

[javascript]  view plain  copy
  1. function drawStar(context,R,x,y,rot){  
  2.     context.save()//设置存储点  
  3.     context.translate(x,y)//平移变换  
  4.     context.rotate(rot/180*Math.PI)//旋转变换  
  5.     context.scale(R,R)//缩放变换  
  6.     starPath(context)//绘制五角星的边  
  7.     context.restore()//回到存储点  
  8. }  
五角星边按如下方法绘制:

由于context.scale()不仅会缩放图形大小,也会缩放图形的位置点和边框,因此在五角星边的绘制中,我们没有设置边的宽度和五角星的偏移。

在下列代码中,即XcanterP和YcenterP都没有设置。

[javascript]  view plain  copy
  1. function starPath(context){  
  2.     context.beginPath()  
  3.     for (var i = 0; i < 5; i++) {  
  4.         //x = Rcosθ + XcenterP  
  5.         //θ = α/180*π       其中α为度数表示的角度,θ为以π为单位表示的角度  
  6.         //y = -Rsinθ + YcenterP  
  7.         context.lineTo(Math.cos((18+i*72)/180*Math.PI),-Math.sin((18+i*72)/180*Math.PI))  
  8.         context.lineTo(Math.cos((54+i*72)/180*Math.PI)/1.8,-Math.sin((54+i*72)/180*Math.PI)/1.8)  
  9.     }  
  10.     context.closePath()  
  11. }  

最后,更新五角星状态的代码如下

这里更新了五角星的位移、角度,也检测了画布边缘碰撞,当碰触到边缘时,五角星的速度取反。

PS这里:五角星的X和Y坐标位于五角星的中心。

[javascript]  view plain  copy
  1. //更新小球的状态(属性)  
  2. function update(canvasWidth,canvasHeight){  
  3.     for (var i = 0; i < stars.length; i++) {  
  4.         stars[i].x += stars[i].vx  
  5.         stars[i].y += stars[i].vy  
  6.         stars[i].rot += stars[i].wv  
  7.   
  8.         if (stars[i].x - stars[i].r <= 0) {  
  9.             stars[i].vx = -stars[i].vx  
  10.             stars[i].x = stars[i].r  
  11.         }  
  12.         if (stars[i].x + stars[i].r >= canvasWidth) {  
  13.             stars[i].vx = -stars[i].vx  
  14.             stars[i].x = canvasWidth - stars[i].r  
  15.         }  
  16.         if (stars[i].y - stars[i].r <= 0) {  
  17.             stars[i].vy = -stars[i].vy  
  18.             stars[i].y = stars[i].r  
  19.         }  
  20.         if (stars[i].y + stars[i].r >= canvasHeight) {  
  21.             stars[i].vy = -stars[i].vy  
  22.             stars[i].y = canvasHeight - stars[i].r  
  23.         }  
  24.     }  
  25. }  

最后,等我网站写完了,我会附上链接让大家看看效果哦~!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值