マトリックスのアレを作ってみよう

12月 13th, 2011

Processing Advent Calendar 2011(13日目)

マトリックスのアレを作ってみよう


アプレットはこちら

Processingはプロトタイプ作成にうってつけの環境であるため、「あれ作ってみたいな」をいち早く表現することができます。
本日は、映画「マトリックス」でおなじみの、緑色のアレを作ってみました。(正式名称が分からないので、便宜上『マトリックスコード』と呼んでおきます)

マトリックスコードでは、画面全体に文字を敷き詰め、またそれぞれに透明度を持たせております。
そして、文字の打ち込み(コーディング?)を表すために、Coderというクラスを作成しました。このクラスは、「今どの位置を書いているか」という位置情報と、どれくらいの速度で描いていくかの速度を持っています。
このCoderを各列に対して作り、Coderがいる文字を不透明にする(そして、徐々に透明にしていく)、という処理をすることで、マトリックスコードを表現しました。
先頭の文字は、少し拡大した文字を半透明で重ねて描画することで輝きも表現しています。

また、映画ではそれぞれの文字は反転していたので、それも忘れずに実装します。
Processingでは、左右反転させるためには、scale(-1, 1)を行うだけで実現が可能です。

int textXCount;  //  横の文字数
int textYCount;  //  縦の文字数
final String STRING = "abcdefghijklmnopqrstuvwxyz0123456789アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン";
 
PFont font;
 
char[][] word;      //  それぞれの文字
int[][] wordAlpha;  //  文字の透明度
 
void setup() {
  size(400, 400);
 
  font = createFont("MS Gothic", 48);
  textFont(font, 20);
  textAlign(CENTER);
 
  textXCount = width / 10;
  textYCount = height / 16;
 
  word = new char[textXCount][textYCount];
  wordAlpha = new int[textXCount][textYCount];
 
  coders = new Coder[textXCount];
  for(int i = 0; i < textXCount; i++){
    coders[i] = new Coder(i);
    coders[i].live = false;
  }
 
  //  初期文字の決定
  for (int i = 0; i < textYCount; i++) {
    for (int j = 0; j < textXCount; j++) {
      word[j][i] = returnWord();
      wordAlpha[j][i] = 0;
    }
  }
}
 
 
void draw() {
  background(0);
 
  for (int i = 0; i < coders.length; i++) {
 
    //  描画する文字のαを最大にする
    if (coders[i].live) {
      wordAlpha[(int)coders[i].id][(int)coders[i].y] = 255;
      coders[i].move();
    }else{
      coders[i].revival();
    }
  }
 
  //  各文字の描画
  for (int y = 0; y < textYCount; y++) {
    for (int x = 0; x < textXCount; x++) {
      fill(167, 255, 180, wordAlpha[x][y]);
 
      //  文字の描画
      pushMatrix();
      translate(x * 10, y * 18);
      scale(-1, 1);  //  反転
      text(word[x][y], 0, 0);
      if(wordAlpha[x][y] == 255){
        fill(255, 192);
        scale(1.1, 1.1);
        text(word[x][y], 0, 0);
        fill(255, 160);
        scale(1.2, 1.2);
        text(word[x][y], 0, 0);
      }
      popMatrix();
 
      //  たまーに文字を置き換える
      if (random(1) < 0.02) {
        word[x][y] = returnWord();
      }
 
      //  だんだん透明にしていく
      wordAlpha[x][y] = max(wordAlpha[x][y] - 3, 0);
    }
  }
}
 
//  文字を一文字得る関数
char returnWord() {
  return STRING.charAt((int)random(STRING.length()));
}
 
//  コーダークラス
Coder[] coders;
class Coder{
  float y;      //  現在Y座標
  float speed;  //  移動スピード
  int id;       //  担当する列番号
  boolean live; //  画面内にいることを表すフラグ
 
  Coder(int id){
    this.id = id;
    init();
  }
 
  //  初期化
  void init(){
    y = 0;
    speed = random(1) * 0.3 + 0.1;  
    live = true;
  }
 
  //  移動
  void move(){
    y += speed;
 
    if((textYCount <= y)){
      live = false;
    }
  }
 
  //  復活
  void revival(){
    if(random(1) < 0.01){
      init();
    }
  }
}

横に動かす

単に模倣するだけではつまらないのですね。せっかくのプロトタイプなので、ちょっと改造してみることにします。

マトリックスコードが「横に動いたらどうなるか」と思いましたので、そのように拡張してみました。


アプレットはこちら

int textXCount;  //  横の文字数
int textYCount;  //  縦の文字数
final String STRING = "abcdefghijklmnopqrstuvwxyz0123456789アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン";
 
PFont font;
 
char[][] word;      //  それぞれの文字
int[][] wordAlpha;  //  文字の透明度
 
void setup() {
  size(400, 400);
 
  font = createFont("MS Gothic", 48);
  textFont(font, 20);
  textAlign(CENTER);
 
  textXCount = width / 10;
  textYCount = height / 16;
 
  word = new char[textXCount][textYCount];
  wordAlpha = new int[textXCount][textYCount];
 
  coders = new Coder[textXCount];
  for(int i = 0; i < textXCount; i++){
    coders[i] = new Coder(i);
    coders[i].live = false;
  }
 
  //  初期文字の決定
  for (int i = 0; i < textYCount; i++) {
    for (int j = 0; j < textXCount; j++) {
      word[j][i] = returnWord();
      wordAlpha[j][i] = 0;
    }
  }
}
 
 
 
void draw() {
  background(0);
 
  for (int i = 0; i < coders.length; i++) {
 
    //  描画する文字のαを最大にする
    if (coders[i].live) {
      wordAlpha[(int)coders[i].x][(int)coders[i].y] = 255;
      coders[i].move();
    }else{
      coders[i].revival();
    }
  }
 
  //  各文字の描画
  for (int y = 0; y < textYCount; y++) {
    for (int x = 0; x < textXCount; x++) {
      fill(167, 255, 180, wordAlpha[x][y]);
 
      //  文字の描画
      pushMatrix();
      translate(x * 10, y * 18);
      scale(-1, 1);  //  反転
      text(word[x][y], 0, 0);
      if(wordAlpha[x][y] == 255){
        fill(255, 192);
        scale(1.1, 1.1);
        text(word[x][y], 0, 0);
        fill(255, 160);
        scale(1.2, 1.2);
        text(word[x][y], 0, 0);
      }
      popMatrix();
 
      //  たまーに文字を置き換える
      if (random(1) < 0.02) {
        word[x][y] = returnWord();
      }
 
      //  だんだん透明にしていく
      wordAlpha[x][y] = max(wordAlpha[x][y] - 3, 0);
    }
  }
}
 
//  文字を一文字得る関数
char returnWord() {
  return STRING.charAt((int)random(STRING.length()));
}
 
//  コーダークラス
Coder[] coders;
class Coder{
  static final int MODE_DOWN = 0;  //  描画モード:下に進む
  static final int MODE_LEFT = 1;  //  描画モード:左に進む
  static final int MODE_RIGHT = 2; //  描画モード:右に進む
  float x;      //  現在X座標
  float y;      //  現在Y座標
  float speed;  //  移動スピード
  int mode;     //  描画モード(MODE_xxxを使う)
  int id;       //  担当する列番号
  boolean live; //  画面内にいることを表すフラグ
 
  Coder(int id){
    this.id = id;
    init();
  }
 
  //  初期化
  void init(){
    x = id;
    y = 0;
    speed = random(1) * 0.3 + 0.1;  
    mode = MODE_DOWN;
    live = true;
  }
 
  //  移動
  void move(){
    switch(mode){
      case MODE_DOWN:
      y += speed;
      if(random(1) < 0.01){
        if(random(1) < 0.5){
          mode = MODE_RIGHT;
        }else{
          mode = MODE_LEFT;
        }
      }
      break;
      case MODE_RIGHT:
      x -= speed;
      break;
      case MODE_LEFT:
      x += speed;
      break;
    }
 
    if((x < 0) || (textXCount <= x) || (textYCount <= y)){
      live = false;
    }
  }
 
  //  復活
  void revival(){
    if(random(1) < 0.01){
      init();
    }
  }
}

Tags: ,
Posted in Processing Advent Calendar2011 | No Comments »

Comments

Leave a Reply

 Comment Form