Replicating the screen from the movie 'The Matrix'
A Pen by Kurt Schwind on CodePen.
| <!-- | |
| Thanks to Emily Xie and her version available here: | |
| http://xie-emily.com/generative_art/green_rain.html | |
| And her youtube tutorial available here: | |
| https://www.youtube.com/watch?v=S1TQCi9axzg | |
| Differences of note: | |
| The code is organied a bit differently but close enough that if you follow the tutorial and other | |
| examples you can see it's VERY similar. | |
| For the 'setToRandomSymbol' though I use a modulo operator instead of random after the first selection is made. | |
| I do this because random is a lot more 'costly' in terms of CPU than modulo is and the effect is close enough | |
| that most won't notice that there is actually a pattern to the changing letters. It is rather subtle. | |
| --> |
Replicating the screen from the movie 'The Matrix'
A Pen by Kurt Schwind on CodePen.
| // "Globals" | |
| var config = { | |
| failsafe: 5000, | |
| symbol_size: 20, | |
| items: [] | |
| }; | |
| function setup() { | |
| var my_width = windowWidth; | |
| var my_height = windowHeight; | |
| var canvas = createCanvas(my_width, my_height); | |
| textSize(config.symbol_size); | |
| var y = 0; | |
| var cols = my_width/config.symbol_size; | |
| for (var i = 0;i < cols; i++) { | |
| s = new Stream(i*config.symbol_size,y,1 + int_rand(10)); | |
| s.init(); | |
| config.items.push(s); | |
| } | |
| } | |
| function draw() { | |
| background(0,90); | |
| config.items.forEach(function(i){i.render();}); | |
| } | |
| function Symbol(x_, y_, speed_,tip_) { | |
| this.pos = createVector(x_, y_); | |
| this.value = undefined; | |
| this.speed = speed_; | |
| this.switch_interval = round(random(10, 40)); | |
| this.tip = tip_; | |
| this.setToRandomSymbol = function() { | |
| if (frameCount===0) { | |
| this.value = String.fromCharCode(0x30A0 + int_rand(96)); | |
| } else if (frameCount % this.switch_interval === 0) { | |
| // Use modulo instead of random to reduce CPU hit | |
| var n = this.value.charCodeAt(0); // converts back to integer value based on unicode | |
| n-=0x30A0; // shift it back to the base | |
| n=(n+this.speed)%96; // modulo over the range | |
| this.value = String.fromCharCode(0x30A0 + n); // add the base back and set the new char | |
| // this.value = String.fromCharCode(0x30A0 + int_rand(96)); // Katakana display | |
| } | |
| }; | |
| this.render = function() { | |
| if (this.tip) { | |
| fill(180, 255, 180); | |
| } else { | |
| fill(0, 200, 70); | |
| } | |
| text(this.value, this.pos.x, this.pos.y); | |
| this.rain(); | |
| this.setToRandomSymbol(); | |
| // my Method for this Obj | |
| }; | |
| // Scroll back to top | |
| this.rain = function() { | |
| this.pos.y = (this.pos.y > (height + 10)) ? 0 : this.pos.y + this.speed; | |
| }; | |
| } // end Symbol | |
| function Stream(x_,y_,speed_) { | |
| this.symbols = []; | |
| this.x = x_; | |
| this.y = round(random(-400,0)); | |
| this.size = round(random(5,height/config.symbol_size)); | |
| //this.size = 4; | |
| this.speed = speed_; | |
| this.init = function() { | |
| var y = this.y; | |
| for (var i = 0; i < this.size; i++) { | |
| var s = new Symbol(this.x, y, this.speed,(i === 0) && (this.size % 5 ===0)); | |
| s.setToRandomSymbol(); | |
| this.symbols.push(s); | |
| y -= config.symbol_size; | |
| } | |
| // this.symbols[0].glow(); | |
| console.log("Stream(x,y,speed) = (" + this.x + "," + this.y + "," + this.speed + ")"); | |
| }; // init | |
| this.render = function() { | |
| this.symbols.forEach(function(s) { | |
| s.render(); | |
| }); | |
| }; // this.render | |
| } // Stream | |
| function int_rand(x) { | |
| return floor(random(x)); | |
| } // int_rand |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.6/p5.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.6/addons/p5.dom.min.js"></script> |