阅读 717

Canvas 动画初体验

之前有介绍过canvas相关的基础知识,今天来分享一个有关canvas的小动画,先来说一下我们的基本思路,整体分为两步,首先画出背景,接下来开始实现动态效果,至于最终的结果是怎么样的,往下看就知道了

第一章  我是canvas你还记得我吗?

自从上次与canvas约会过后,总觉得他是一个有潜力的小家伙,只不过他的才能好像被埋没了,如果还能在见到他,我想给他个惊喜

说来也很巧,居然和他偶遇了……

<div id="wrap">
   <canvas id="canvas" width="800" height="600"></canvas>		
</div>
复制代码

我,当然还记得你啊……

第二章  猜猜我的背包里都有什么?

背包这么鼓,你都带什么啦?你猜呀……

  • 建立基本的页面--- html
  • 存放图片的文件 -- image
  • 写逻辑的页面  ---- js文件
  • 相关的图片文件,代码已上传到github上,地址在下下下下面,欢迎访问!

第三章   带你去个地方

  • 背景搭建
   我们在对应的js(main.js)文件中,引入背景图片

var can,ctx,w,h
var img=new Image()
var star=new Image()
function init(){
	can=document.getElementById('canvas')
	ctx=can.getContext('2d')
	w=can.width
	h=can.height
	img.src="image/girl.jpg"
	star.src="image/star.png"
	gameloop()
}

function gameloop(){
/* 做兼容, 循环调用gameloop,这里的requestAnimationFrame 方法封装在commonFunctions.js中*/ 
       window.requestAnimationFrame(gameloop)
	drawImage()
}
document.body.onload=init
// 绘制图片
function drawImage(){
	ctx.drawImage(img,0,0,w,h)
}
复制代码

循环调用 gameloop的三种方法:                             
 requestAnimFrame(function(){})  根据性能确定时间,间隔时间不固定
 setTimeout(function(){},time)   几秒后第一次调用
 setInterval(function(){},time)  第一次调用几秒后再一次调用复制代码

这样我们的背景就画好了,像这样


  • 来点特效
    先画一个小星星,这里我们新建一个js文件(stars.js)

  

// 首先定义一个star的类
var starObj=function(){
	this.x;
	this.y;
}
// 先来绘制一个看看效果
function drawStar(){
     ctx.drawImage(star,300,400)
}
// 把上面的drarStar() 方法在之前的main.js调用,后面在stars.js中方法都在main.js中调用  复制代码

function gameloop(){
	window.requestAnimationFrame(gameloop)/* 做兼容, 循环调用gameloop*/
	drawImage()
	drawStar()	
}
复制代码

然后我们看效果,出现了一排小星星,那按照刚才的逻辑,我们要展示出很多的小星星


在定义好的main.js中,定义要展示星星的数量,

// 数量
var num=100
var starts=[]  // 存放星星的数组
function init(){
	can=document.getElementById('canvas')
	ctx=can.getContext('2d')
	w=can.width
	h=can.height
	img.src="image/girl.jpg"
	star.src="image/star.png"
	// 初始化星星
	for(var i=0;i<num;i++){
	  starts[i]=new starObj()
	  starts[i].init()
	}
	gameloop()
}
复制代码

同样的在stars.js中也初始化一下

starObj.prototype.init=function(){
// 给星星一个随机位置
	this.x=Math.random()*800
	this.y=Math.random()*600
}
starObj.prototype.draw=function(){
	/*context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
	 使用的图片,开始剪切的x位置,开始剪切的y的位置,被剪切的图片的宽,被剪切的图片的高,
         在画布上的x位置,在画布上的y的位置,要使用的图像的宽,要使用的图像的高*/
	ctx.drawImage(star,this.x,this.y)
}
// 绘制一个
function drawStar(){
	for(var i=0;i<num;i++){
		starts[i].draw()
	}
}复制代码
我们现在绘制了100个,来看看现在的效果


距离目标已经实现了一大步了,接下来我们来随机截取要显示的星星,就像下面这样


要实现上面的效果,其实很简单只需这样(starts.js)

var starObj=function(){
	this.x;
	this.y;
	this.picnum; // 定义一个随机数
}
starObj.prototype.init=function(){
	this.x=Math.random()*800
	this.y=Math.random()*600
	//随机位置
	this.picnum=Math.floor(Math.random()*7)	
}
starObj.prototype.draw=function(){
	/*context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
	 使用的图片,开始剪切的x位置,开始剪切的y的位置,被剪切的图片的宽,被剪切的图片的高,
         在画布上的x位置,在画布上的y的位置,要使用的图像的宽,要使用的图像的高*/
	//ctx.drawImage(star,this.x,this.y)
	ctx.save()
	ctx.drawImage(star,this.picnum*7,0,7,7,this.x,this.y,7,7)
	ctx.restore()
}复制代码
在上面的代码中我们使用到了之前说过的save() , restore() 如果不太记得了,可以稍稍的去复习一下,然后我们要做的就是让星星闪起来,由于我们 使用的requestAnimationFrame 时间间隔不固定,这里我们可以利用这个时间差来实现星星的闪动效果

// main中定义上一帧的时间,和事件差
var lastTime
var deltaTime
function init(){
	can=document.getElementById('canvas')
	ctx=can.getContext('2d')
	w=can.width
	h=can.height
	img.src="image/girl.jpg"
	star.src="image/star.png"
	// 初始化星星
	for(var i=0;i<num;i++){
		//push
		starts[i]=new starObj()
		starts[i].init()
	}
      // 初始化上一帧的时间为当前时间
	lastTime=Date.now()    
	gameloop()
}
function gameloop(){
	window.requestAnimationFrame(gameloop)
	var now=Date.now()  // 当前时间
	deltaTime=now-lastTime  // 时间差
	lastTime=now  // 上一帧等于当前时间
	drawImage()
	drawStar()	
}
复制代码

// 在stars中实现闪动
var starObj=function(){
	this.x;
	this.y;
	this.picnum
	this.timer // 定义一个时间值
}
starObj.prototype.init=function(){
	this.x=Math.random()*800
	this.y=Math.random()*600
	this.picnum=Math.floor(Math.random()*7)
	this.timer=0  // 初始化为0
}
starObj.prototype.update=function(){
	this.timer+=deltaTime
        // 当时间值大于50毫秒后,动画帧加1,且不超过7个
	if(this.timer>50){
		this.picnum+=1
		this.picnum%=7
		this.timer=0
	}
	// 这里由于星星图片只有7个动画帧效果
	if(this.picnum>=7){
		this.picnum=0
	}
}复制代码
这样小星星就随机的闪起来了有没有,怎么样这个地方还是很美的是不是,耐心的等一下

第四章  我会魔法哦

挥一挥魔法棒,让小星星动起来

// 依旧是在stars中操作
var starObj=function(){
	this.x;
	this.y;
	this.picnum
	this.timer
       // 定义个初速度
	this.xSpd
	this.ySpd
}
starObj.prototype.init=function(){
	this.x=Math.random()*800
	this.y=Math.random()*600
	this.picnum=Math.floor(Math.random()*7)
	this.timer=0
	// 位移,来个随机的上下左右
	this.xSpd=Math.random()*3-1.5 // [-1.5,1.5]
	this.ySpd=Math.random()*3-1.5
}
starObj.prototype.update=function(){
	// 星星移动
	this.x+=this.xSpd*deltaTime*0.002
	this.y+=this.ySpd*deltaTime*0.002
	// 超出边界的星星重生
	if(this.x<0||this.x>800){
		this.init()
		return
	}
	if(this.y<0||this.y>600){
		this.init()
		return
	}
	this.timer+=deltaTime
	if(this.timer>50){
		this.picnum+=1
		this.picnum%=7
		this.timer=0
	}
	if(this.picnum>=7){
		this.picnum=0
	}
}
function drawStar(){
    for(var i=0;i<num;i++){
	starts[i].draw()
	starts[i].update()  // 别忘了这里
   }
}
复制代码

是不是很神奇,别急,我还有一个魔法,来个鼠标滑过显示

// mian中定义如下
var switchy=false
var alive=0  // 星星的显示状态,初始化为0
var px,py
function init(){
	can=document.getElementById('canvas')
	ctx=can.getContext('2d')
	w=can.width
	h=can.height
	// 初始化鼠标滑过事件
	document.addEventListener('mousemove',mousemove,false)
	img.src="image/girl.jpg"
	star.src="image/star.png"
	for(var i=0;i<num;i++){
		//push
		starts[i]=new starObj()
		starts[i].init()
	}
	lastTime=Date.now()
        
	gameloop()
}
function mousemove(e){
  if(e.offsetX||e.layerX){
	px=e.offsetX==undefined?e.layerX:e.offsetX
	py=e.offsetY==undefined?e.layerY:e.offsetY
	// 判断鼠标是否在画布内
	if(px>0 && px<800 && py>0 && py<600){
	  switchy=true
	}else{
	  switchy=false
	}		
  }
}复制代码
stars中的更新逻辑

starObj.prototype.draw=function(){
  ctx.save()
// 这里使用使用全局透明度,它会控制整个画布的透明度,也就是为什么要把这部分内容写在save和restore中
  ctx.globalAlpha=alive
  ctx.drawImage(star,this.picnum*7,0,7,7,this.x,this.y,7,7)
  ctx.restore()
}
// aliveUpdate 方法不要忘了在main中调用哦
function aliveUpdate(){
	if(switchy){
		alive+=0.03*deltaTime*0.05
		if(alive>1){
			alive=1
		}
	}else{
		alive-=0.03*deltaTime*0.05
		if(alive<0){
			alive=0
		}
	}
}复制代码

这样当鼠标滑过的时候就会看到神奇的效果了,
这里要感谢Daisy老师的课程讲解,下面是github的地址

    https://github.com/aurora-polaris/canvas-2


文章分类
前端