黑客帝国代码特效(一招让妹子尖叫)(2)
上面的代码中,行使了 CSI n;1m 的情势来界说颜色,着实是两种结果的,一个是详细颜色值,一个是加粗,一些呼吁行实现中会行使加粗结果来界说亮色。好比,假如直接界说 CSI 32 m 也许最终展示的是暗绿色,我们改成 CSI 32;1m 则将表现亮绿色。
颜色支持多种名目,上面的是 3-bit 和 4-bit 名目,同时尚有 8-bit 和 24-bit。代码中也有行使样例,这里不再赘述了。
矩阵渲染在 matrix-rain 的代码中,index.js 里的焦点成果是 MatrixRain 这个类:
class MatrixRain { constructor(opts) { this.transpose = opts.direction === `h`; this.color = opts.color; this.charRange = opts.charRange; this.maxSpeed = 20; this.colDroplets = []; this.numCols = 0; this.numRows = 0; // handle reading from file if (opts.filePath) { if (!fs.existsSync(opts.filePath)) { throw new Error(`${opts.filePath} doesn't exist`); } this.fileChars = fs.readFileSync(opts.filePath, `utf-8`).trim().split(``); this.filePos = 0; this.charRange = `file`; } } generateChars(len, charRange) { // by default charRange == ascii let chars = new Array(len); if (charRange === `ascii`) { for (let i = 0; i < len; i ) { chars[i] = String.fromCharCode(rand(0x21, 0x7E)); } } else if (charRange === `braille`) { for (let i = 0; i < len; i ) { chars[i] = String.fromCharCode(rand(0x2840, 0x28ff)); } } else if (charRange === `katakana`) { for (let i = 0; i < len; i ) { chars[i] = String.fromCharCode(rand(0x30a0, 0x30ff)); } } else if (charRange === `emoji`) { // emojis are two character widths, so use a prefix const emojiPrefix = String.fromCharCode(0xd83d); for (let i = 0; i < len; i ) { chars[i] = emojiPrefix String.fromCharCode(rand(0xde01, 0xde4a)); } } else if (charRange === `file`) { for (let i = 0; i < len; i , this.filePos ) { this.filePos = this.filePos < this.fileChars.length ? this.filePos : 0; chars[i] = this.fileChars[this.filePos]; } } return chars; } makeDroplet(col) { return { col, alive: 0, curRow: rand(0, this.numRows), height: rand(this.numRows / 2, this.numRows), speed: rand(1, this.maxSpeed), chars: this.generateChars(this.numRows, this.charRange), }; } resizeDroplets() { [this.numCols, this.numRows] = process.stdout.getWindowSize(); // transpose for direction if (this.transpose) { [this.numCols, this.numRows] = [this.numRows, this.numCols]; } // Create droplets per column // add/remove droplets to match column size if (this.numCols > this.colDroplets.length) { for (let col = this.colDroplets.length; col < this.numCols; col) { // make two droplets per row that start in random positions this.colDroplets.push([this.makeDroplet(col), this.makeDroplet(col)]); } } else { this.colDroplets.splice(this.numCols, this.colDroplets.length - this.numCols); } } writeAt(row, col, str, color) { // Only output if in viewport if (row >=0 && row < this.numRows && col >=0 && col < this.numCols) { const pos = this.transpose ? ansi.cursorPos(col, row) : ansi.cursorPos(row, col); write(`${pos}${color || ``}${str || ``}`); } } renderFrame() { const ansiColor = ansi.colors[`fg${this.color.charAt(0).toUpperCase()}${this.color.substr(1)}`](); for (const droplets of this.colDroplets) { for (const droplet of droplets) { const {curRow, col: curCol, height} = droplet; droplet.alive ; if (droplet.alive % droplet.speed === 0) { this.writeAt(curRow - 1, curCol, droplet.chars[curRow - 1], ansiColor); this.writeAt(curRow, curCol, droplet.chars[curRow], ansi.colors.fgWhite()); this.writeAt(curRow - height, curCol, ` `); droplet.curRow ; } if (curRow - height > this.numRows) { // reset droplet Object.assign(droplet, this.makeDroplet(droplet.col), {curRow: 0}); } } } flush(); } }
尚有几个器材要领:
(责任编辑:admin)