之前有介绍过canvas相关的基础知识,今天来分享一个有关canvas的小动画,先来说一下我们的基本思路,整体分为两步,首先画出背景,接下来开始实现动态效果,至于最终的结果是怎么样的,往下看就知道了
第一章 我是canvas你还记得我吗?
自从上次与canvas约会过后,总觉得他是一个有潜力的小家伙,只不过他的才能好像被埋没了,如果还能在见到他,我想给他个惊喜
说来也很巧,居然和他偶遇了……
<div id="wrap">
<canvas id="canvas" width="800" height="600"></canvas>
</div>
复制代码
我,当然还记得你啊……
第二章 猜猜我的背包里都有什么?
背包这么鼓,你都带什么啦?你猜呀……
- 建立基本的页面--- html
- 存放图片的文件 -- image
- 写逻辑的页面 ---- js文件
- 相关的图片文件,代码已上传到github上,地址在下下下下面,欢迎访问!
第三章 带你去个地方
- 背景搭建
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) 第一次调用几秒后再一次调用复制代码
这样我们的背景就画好了,像这样
- 来点特效
// 首先定义一个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