之前有介紹過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