背景:
一日在網上閑逛的之時,突然看到一個利用JQ插件實現canvas實現的電影黑客帝國的小Demo。覺得創意不錯,就下載下來研究一下。
網上瀏覽jQuery的寫法
$(document).ready(function() {
var s = window.screen;
var width = q.width = s.width;
var height = q.height;
var yPositions = Array(300).join(0).split('');
var ctx = q.getContext('2d');
var draw = function() {
ctx.fillStyle = 'rgba(0,0,0,.05)';
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = 'red';
ctx.font = '10pt Georgia';
yPositions.map(function(y, index) {
text = String.fromCharCode(1e2 + Math.random() * 33);
x = (index * 10) + 10;
q.getContext('2d').fillText(text, x, y);
if(y > Math.random() * 1e4) {
yPositions[index] = 0;
} else {
yPositions[index] = y + 10;
}
});
};
RunMatrix();
function RunMatrix() {
Game_Interval = setInterval(draw, 1000);
}
});
全程100行不到的代碼,主體的核心就是定時器調用canvas進行繪畫處理。要是讓我這種段子手來寫,估計我把敲爛鍵盤都想不出這樣營造效果。藝術細胞真的很重要咕~~(╯﹏╰)
老王:“等等大棒!不是說js+canvas實現黑客帝國矩形雨,可是你這個附上的代碼分明是jQ+canvas.”
老管:"就是!你這個標題汪,這是又要搞事情呀!"
我:“別急呀!這個jQ+canvas因為網上很多人博客都有寫,所以這邊只是附上一下jQ代碼供大家參考。下面才是我今天要通過for循環代替上面的map()來實現的!!
夫子:別凈扯理由,你是根本就不會map()用法!!”
老齊: "凈說什么大實話!大棒是根本看不懂......"
我:.........好吧!你們說對了,我的確是不會map()方法。(讓我蹲牆角哭會/((╥╯^╰╥)”
萬能for循環的寫法
好了不扯犢子了,言歸正傳。讓我們回到下面要講的代碼上面來。
1、基本准備工作
1.1、HTML骨架部分
<canvas id="hacker" width="500" height="500">請使用Google瀏覽器或者IE9以上</canvas>
1.2、JavaScript部分
var hacker = document.getElementById("hacker");
var width = hacker.width = screen.width; //screen.width拿到是當前屏幕寬度
var height = hacker.height;
var ctx = haceker.getContext('2d');
做完這幾步之后,我們就能夠拿到當前屏幕的寬度、以及canvas畫布的寬度和得到canvas畫布的上下文。
2、數組的准備
var num = Math.ceil(width / 10);
var y = Array(num).join(0).split('');
這里估計有人會詢問了,這里創建一個數組是干嘛。為什么數組的length >= num?
O(∩_∩)O哈哈~,別着急,后面的代碼就會個大家逐一解釋了。
3、定義一個重復調用核心draw()方法
var draw = function() {
ctx.fillStyle = 'rgba(0,0,0,.05)'; //創意核心語句之一
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = '#0f0';
ctx.font = '10px Microsoft YaHei';
for(i = 0; i < y.length; i++) {
var x = (i * 10) + 10;
text = String.fromCharCode(1e2 + Math.random() * 33);
var y1 = y[i];
ke.getContext('2d').fillText(text, x, y1);
console.log(height);
if(y1 > Math.random() * 10 * height) {
y[i] = 0;
} else {
y[i] = parseInt(y[i]) + 10;
}
}
}
3.1、ctx繪畫過程解釋
ctx.fillStyle = 'rgba(0,0,0,.05)'; //創意核心語句之一
ctx.fillRect(0, 0, width, height);
這里為設定的區域鋪上一個rgba(0,0,0,.05) 這樣黑色半透明的背景。
ctx.fillStyle = '#0f0';
ctx.font = '10px Microsoft YaHei';
這里就是畫出大小為 10px,字體為微軟雅黑的字體。
兩行代碼看起來就是很普通的代碼,但是組合起來卻發生一個質的變化。
為什么會有層次感呢?要知道getContext('2d')這句語句,就決定了canvas只能繪制2D圖像,不能繪制3D層次感的圖形!
答案就在 ctx.fillStyle = 'rgba(0,0,0,.05)';
上面,當重復調用方法的時候,這種半透明的灰黑色背景就會蓋在之前的畫好綠色文字上面。因此因此就造成了有文字是綠色,有的文字變成灰綠色。
各個文字之間形成一種視覺差,從而讓人感覺到3D立體矩形代碼陣效果。所以當我發現兩組這么普通的代碼組合起發生如此厲害效果,當即激動拍了拍鍵盤。大呼一聲!
“哇靠!這個真心666!”
3.2、for循環解釋
for(i = 0; i < num; i++) {
var x = (i * 10) + 10;
text = String.fromCharCode(65 + Math.random() * 62);
var y1 = y[i];
ctx.fillText(text, x, y1);
console.log(height);
if(y1 > Math.random() * 10 * height) {
y[i] = 0;
} else {
y[i] = parseInt(y[i]) + 10;
}
}
}
3.3、關於canvasX軸上面文字控制
因為前面每次畫的文字大小都是10px,那么如果我把canvasX軸平鋪滿。需要多少個文字呢。
答案 = Math.ceil(width / 10);
=> 即就是我前面的num
小說明:
為什么得用Math.ceil()向上取整,而不能用Math.floor向下取整,parseInt()之類。
因為假設num = 300.8樣子,那么使用Math.floor() 或者parseInt(),就好把這個數轉換成300
那么后面,繪制300個文字在canvasX軸,那么最右邊就還有0.8個文字,也就是8px空隙一種沒有字母出現。向上取整,就會鋪滿,多的部分超出canvas區域,就會消失。
text = String.fromCharCode(65 + Math.random() * 62);
這里就是每次for循環的時候產生65 - 127 的數字,之后將其轉換為大寫、小寫字母,以及一些符號
3.4關於canvasY軸的控制
這里前面定義的數組就派上用場了var y = Array(num).join(0).split('');
,這里就是用於記錄與控制每一次canvas文字的Y軸。
為什么要用數組去記錄呢?說實話,當初我也是這么認為的,所以我沒有嘗試控制每一個文字Y軸的數據,讓所以的Y軸依次累加,結果效果如下:
所以之后我就奇思妙想,讓每次文字是排列X軸平鋪數字隨機呈現。例如第一次平鋪300個,第二次平鋪100個,第三次平鋪200.......,但是我還是錯了:
錯誤的代碼示范:
所以多次失敗的嘗試之后,發現還是得控制利用一個數組控記錄與控制每一個數字Y軸的數據。
4、代碼的收尾
Run();
function Run() {
Game_Interval = setInterval(draw, 30);
}
之后設置一個定時器,每次間隔30ms調用一次,然后大功告成。一個炫酷的黑客帝國矩形雨效果就出來了。
當然前面JavaScript代碼可能太凌亂,所以這邊就把JavaScript的全部呈上:
window.onload = function() {
var kacker = document.getElementById("hacker");
var width = hacker.width = screen.width;
var height = kacker.height;
var ctx = hacker.getContext('2d');
var num = Math.ceil(width / 10);
var y = Array(num).join(0).split('');
var draw = function() {
ctx.fillStyle = 'rgba(0,0,0,.05)';
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = '#0f0';
ctx.font = '10px Microsoft YaHei';
for(i = 0; i < num; i++) {
var x = (i * 10) + 10;
text = String.fromCharCode(65 + Math.random() * 62);
//console.log(text); 用來檢測 text 的值
var y1 = y[i];
ctx.fillText(text, x, y1);
if(y1 > Math.random() * 10 * height) {
y[i] = 0;
} else {
y[i] = parseInt(y[i]) + 10;
}
}
}
Run();
function Run() {
Game_Interval = setInterval(draw, 100);
}
}
看到這里不要以為代碼就此結束了,好好吸收那個for循環之后。接下來再返回上面看一下map()方法,相信map()方法的用法是不是一下子清晰明了。一箭雙雕,既實現了5毛的特效,又幫助熟悉了一個map()方法用法.
效果預覽:黑客帝國矩形陣
(ps:效果圖掛在阿里雲上面,部分平台點擊進去可能會有提示,例如微信,請忽略.....)
對於里面完整blogDemo代碼感興趣的,可以從本人github上閱覽。
源碼demo傳送門地址
我是車大棒,深藏功與名!(滑稽臉)