[js高手之路]html5 canvas動畫教程 - 下雪效果


利用canvas,實現一個下雪的效果,我們先預覽下效果:

 

 

我們先分析下這個效果:

1,隨機產生雪花

2,雪花的產生不是同時產生,而是有先后順序的

3,雪花怎么表示

4,怎么源源不斷的下雪

5,雪花有大有小

搞清楚上面幾個問題之后,這個效果基本上就實現了,

首先,由於這個是全屏效果,我采用動態創建canvas,把整個瀏覽器的寬與高賦值給canvas

 1         var Canvas = function (w, h) {
 2                 this.width = w;
 3                 this.height = h;
 4             }
 5             Canvas.prototype = {
 6                 init: function () {
 7                     var oC = document.createElement("canvas");
 8                     oC.setAttribute('width', this.width);
 9                     oC.setAttribute('height', this.height);
10                     oC.setAttribute('id', 'canvas');
11                     oC.style.backgroundColor = '#000';
12                     document.body.appendChild(oC);
13                 }
14             }
15             var curWinWidth = window.innerWidth,
16                 curWinHeight = window.innerHeight;
17             var oCanvas = new Canvas(curWinWidth, curWinHeight);
18             oCanvas.init();

調用oCanvas對象的init方法之后,就會在body的最后面追加一個canvas,id為canvas,寬、高與瀏覽器的寬、高相同,背景為黑色,晚上下雪的效果

接下來,有了舞台,演員該上場了,怎么產生雪花呢?這里把下雪相關的操作,封裝成一個類,他的基本結構如下:

var Snow = function(){}

Snow.prototype = {

  init : function(){},

  draw : function( cxt ) {},

  update : function(){}

}

這個類一共有三個方法( init, draw, update ).

init:初始化雪花的位置( x, y 坐標 )、速度、半徑( 雪花的大小,在這里我們把雪花用半徑不同的圓表示 )

            function random(min, max) {
                return Math.random() * (max - min) + min;
            }

            init: function () {
                    this.x = random(0, width);
                    this.y = 0;
                    this.r = random(1, 5);
                    this.vy = random(3, 5);
                }

那么init 加上 這個random函數 就可以完成雪花的初始化

1,雪花出來的時候,一般是在屏幕的最上方出現的,所以雪花的y坐標都是0,  其次,雪花的x坐標是隨機的,他的范圍是從屏幕的左邊到右邊,那么就是 0 ~ width. 這個width就是canvas的寬度,也就是瀏覽器的寬度

2,雪花的半徑r, 設置為1 ~ 5之間的任意值

3,雪花下降的速度設置為3 ~ 5之間的隨機速度,這里我做的下雪是垂直方向往下飄,你可以拓展,考慮風力影響( 這個時候肯定有水平方向的速度 )

有了這些初始化的參數之后,我們完善draw方法,繪制雪花:

1                 draw: function (cxt) {
2                     cxt.beginPath();
3                     cxt.fillStyle = 'white';
4                     cxt.arc(this.x, this.y + this.r, this.r, 0, Math.PI * 2, false);
5                     cxt.fill();
6                     cxt.closePath();
7                     this.update(cxt);
8                 },

參數cxt就是canvas的上下文,這個函數很簡單,就是一個arc方法調用init中設置的值來畫圓(雪花),在該方法的最后調用了一個update方法,他是干嘛的?他是更新雪花在垂直方向的速度

             update: function (cxt) {
                    if (this.y < height - this.r) {
                        this.y += this.vy;
                    } else {
                        this.init();
                    }
                }

在update方法中,我們做了邊界判斷: 雪花往下飄落的時候,肯定會消失,消失之后怎么處理?沒有到達邊界怎么處理?

canvas的高度減去雪花的半徑,這就是雪花要消失時候的邊界,所以this.y  < height - this.r  如果這個條件成立,那么說明雪花一直在飄着,我們就要把雪花的y方向的位置更新,雪花看起來(‘正在下雪’),當一個雪花快要消失的時候,我們再把他移動到初始的位置,這樣看起來就是在圓圓不斷的下雪,而不需要重新繪制雪花(如果這樣做,肯定會影響性能,這個特效最后肯定會被卡死,這個小技巧很多類似的特效都會用到)。至此核心的流程已經搞定,接下來,我們就要大量的生成雪花了。

1             var snow = [];
2             for (var i = 0; i < 500; i++) {
3                 setTimeout(function () {
4                     var oSnow = new Snow();
5                     oSnow.init();
6                     snow.push(oSnow);
7                 }, 10 * i);
8             }

生成500個雪花,不是同時生成的,然后把這些雪花保存到數組snow中.

然后,開啟定時器,讓雪花不斷的飄落吧,

關於requestAnimationFrame的使用,可以參考我的這篇文章:[js高手之路] html5新增的定時器requestAnimationFrame實戰進度條

1              (function move() {
2                 oGc.clearRect(0, 0, width, height);
3                 for (var i = 0; i < snow.length; i++) {
4                     snow[i].draw(oGc);
5                 }
6                 requestAnimationFrame(move);
7             })();

完整的demo代碼:

 1 <head>
 2     <meta charset="UTF-8">
 3     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 4     <meta http-equiv="X-UA-Compatible" content="ie=edge">
 5     <title>雪花效果 - by ghostwu</title>
 6     <!-- <script src="lib.js"></script> -->
 7     <style>
 8         * {
 9             margin: 0;
10             padding: 0;
11         }
12 
13         body {
14             overflow: hidden;
15         }
16     </style>
17 </head>
18 
19 <body>
20     <script>
21         window.onload = function () {
22             var Canvas = function (w, h) {
23                 this.width = w;
24                 this.height = h;
25             }
26             Canvas.prototype = {
27                 init: function () {
28                     var oC = document.createElement("canvas");
29                     oC.setAttribute('width', this.width);
30                     oC.setAttribute('height', this.height);
31                     oC.setAttribute('id', 'canvas');
32                     oC.style.backgroundColor = '#000';
33                     document.body.appendChild(oC);
34                 }
35             }
36             var curWinWidth = window.innerWidth,
37                 curWinHeight = window.innerHeight;
38             var oCanvas = new Canvas(curWinWidth, curWinHeight);
39             oCanvas.init();
40 
41             var oC = document.querySelector('#canvas');
42             var width = oC.width, height = oC.height, oGc = oC.getContext('2d');
43 
44             function random(min, max) {
45                 return Math.random() * (max - min) + min;
46             }
47             var Snow = function () {
48 
49             }
50             Snow.prototype = {
51                 init: function () {
52                     this.x = random(0, width);
53                     this.y = 0;
54                     this.r = random(1, 5);
55                     this.vy = random(3, 5);
56                 },
57                 draw: function (cxt) {
58                     cxt.beginPath();
59                     cxt.fillStyle = 'white';
60                     cxt.arc(this.x, this.y + this.r, this.r, 0, Math.PI * 2, false);
61                     cxt.fill();
62                     cxt.closePath();
63                     this.update(cxt);
64                 },
65                 update: function (cxt) {
66                     if (this.y < height - this.r) {
67                         this.y += this.vy;
68                     } else {
69                         this.init();
70                     }
71                 }
72             }
73 
74             var snow = [];
75             for (var i = 0; i < 500; i++) {
76                 setTimeout(function () {
77                     var oSnow = new Snow();
78                     oSnow.init();
79                     snow.push(oSnow);
80                 }, 10 * i);
81             }
82 
83             (function move() {
84                 oGc.clearRect(0, 0, width, height);
85                 for (var i = 0; i < snow.length; i++) {
86                     snow[i].draw(oGc);
87                 }
88                 requestAnimationFrame(move);
89             })();
90         }
91     </script>
92 </body>
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM