用canvas绘制“具有碰撞检测效果的运动五角星”

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

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

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

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


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

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


实现:

html代码如下:

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


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

.carouselBox{
	width: 100%;
	height: 300px;
	background-color: rgba(200, 200, 255, 0.3);
	position: relative;
	text-align: center;
	#stars{
		position: absolute;
		left: 0;
		top: 0;
		z-index: 5;
	}
	h1{
		position: relative;
		z-index: 10;
		font-size: 50px;
		line-height: 300px;
		color: rgba(0, 0, 0, 0.7)
	}
}
h1标签的字要在canvas画布的上方,不能被遮盖,因此设置了z-index,为了让z-index生效,设置了position:relative。

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


重点在JS代码上:

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

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

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

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

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


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

	var stars = []//用来装五角星的数组
	for (var i = 0; i < 30; i++) {
		var R = Math.floor(Math.random()*100+155)
		var G = Math.floor(Math.random()*100+155)
		var B = Math.floor(Math.random()*100+155)
		var r = Math.random()*30 + 20
		var rot = Math.random()*360
		aStar = {
			color:'rgb('+R+','+G+','+B+')',
			r:r,
			x:Math.random()*(drawing2.width - 2*r) + r,
			y:Math.random()*(drawing2.height - 2*r) + r,
			rot:rot,
			vx:(Math.random()*2+2)*Math.pow(-1,Math.floor(Math.random()*100)),
			vy:(Math.random()*2+2)*Math.pow(-1,Math.floor(Math.random()*100)),
			wv:(Math.random()*2+2)*Math.pow(-1,Math.floor(Math.random()*100))
		}
		stars[i] = aStar
	}


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

	setInterval(function(){
		draw(context2)//绘制函数
		update(drawing2.width,drawing2.height)//更新每个五角星的状态
	},30)


绘制函数如下:

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

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


drawStar方法如下

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

	function drawStar(context,R,x,y,rot){
		context.save()//设置存储点
		context.translate(x,y)//平移变换
		context.rotate(rot/180*Math.PI)//旋转变换
		context.scale(R,R)//缩放变换
		starPath(context)//绘制五角星的边
		context.restore()//回到存储点
	}
五角星边按如下方法绘制:

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

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

	function starPath(context){
		context.beginPath()
		for (var i = 0; i < 5; i++) {
			//x = Rcosθ + XcenterP
			//θ = α/180*π		其中α为度数表示的角度,θ为以π为单位表示的角度
			//y = -Rsinθ + YcenterP
			context.lineTo(Math.cos((18+i*72)/180*Math.PI),-Math.sin((18+i*72)/180*Math.PI))
			context.lineTo(Math.cos((54+i*72)/180*Math.PI)/1.8,-Math.sin((54+i*72)/180*Math.PI)/1.8)
		}
		context.closePath()
	}

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

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

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

	//更新小球的状态(属性)
	function update(canvasWidth,canvasHeight){
		for (var i = 0; i < stars.length; i++) {
			stars[i].x += stars[i].vx
			stars[i].y += stars[i].vy
			stars[i].rot += stars[i].wv

			if (stars[i].x - stars[i].r <= 0) {
				stars[i].vx = -stars[i].vx
				stars[i].x = stars[i].r
			}
			if (stars[i].x + stars[i].r >= canvasWidth) {
				stars[i].vx = -stars[i].vx
				stars[i].x = canvasWidth - stars[i].r
			}
			if (stars[i].y - stars[i].r <= 0) {
				stars[i].vy = -stars[i].vy
				stars[i].y = stars[i].r
			}
			if (stars[i].y + stars[i].r >= canvasHeight) {
				stars[i].vy = -stars[i].vy
				stars[i].y = canvasHeight - stars[i].r
			}
		}
	}

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值