車大棒淺談for循環+canvas實現黑客帝國矩形陣


背景:
一日在網上閑逛的之時,突然看到一個利用JQ插件實現canvas實現的電影黑客帝國的小Demo。覺得創意不錯,就下載下來研究一下。

黑客帝國開場動畫效果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 的數字,之后將其轉換為大寫、小寫字母,以及一些符號

控制台檢測text

3.4關於canvasY軸的控制

這里前面定義的數組就派上用場了var y = Array(num).join(0).split('');,這里就是用於記錄與控制每一次canvas文字的Y軸。

為什么要用數組去記錄呢?說實話,當初我也是這么認為的,所以我沒有嘗試控制每一個文字Y軸的數據,讓所以的Y軸依次累加,結果效果如下:

讓所有的文字共用Y軸,然后依次累加

所以之后我就奇思妙想,讓每次文字是排列X軸平鋪數字隨機呈現。例如第一次平鋪300個,第二次平鋪100個,第三次平鋪200.......,但是我還是錯了:

讓X軸隨機平鋪數量

錯誤的代碼示范:

失敗的代碼嘗試

所以多次失敗的嘗試之后,發現還是得控制利用一個數組控記錄與控制每一個數字Y軸的數據。

用Y軸分配每一個X軸點之后,后面產生如此的效果

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傳送門地址

動次!打次!鐺!

動次!打次!鐺!
我是車大棒,深藏功與名!(滑稽臉)


免責聲明!

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



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