アニメ「学戦都市アスタリスク」の2期オープニングのクレジット表示をProcessingで真似してみました
このアニメのCGなどによるエフェクトは、結構気に入っています。その中で目をひかれた、2期オープニングのクレジットタイトル(監督、出演者、スタッフ名など)の表現を、Processingで真似してみました。公式の動画は見当たらず直接紹介できませんが、気になる方はYouTubeなどで探してみてください。
環境
PFont font_;
HexagonLine hline_;
CyberText[] ctext_;
void setup(){
size(640,480);
font_ = createFont("Meiryo", 32);
hline_ = new HexagonLine(16, 17);
ctext_ = new CyberText[3];
for (int i = 0; i < ctext_.length; i++ ) {
ctext_[i] = new CyberText();
}
startAnimation();
}
void draw(){
background(0,0,0);
pushMatrix();
translate( 50,100);
drawCredit();
popMatrix();
}
void drawCredit() {
textFont(font_);
fill(185,255,255);
textAlign(LEFT, CENTER);
textSize(18);
ctext_[0].setText("Programming language");
ctext_[0].draw(20,-30);
textSize(36);
ctext_[1].setText("Processing");
ctext_[1].draw(20,5);
textSize(12);
ctext_[2].setText("initiated by Ben Fry and Casey Reas.");
ctext_[2].draw(20,45);
hline_.draw();
}
void keyPressed(){
startAnimation();
}
void startAnimation() {
ctext_[0].start( 0,200);
ctext_[1].start(200,250);
ctext_[2].start(500,150);
hline_.start(150, 15);
}
class Hexagon {
float x_;
float y_;
float size_;
boolean enable_ = true;
int time_start_ = 0;
int time_disp_ = 0;
int time_hide_ = 0;
int time_end_ = 0;
Hexagon(float x, float y, float size) {
x_ = x;
y_ = y;
size_ = size;
}
void display(boolean enable) {
enable_ = enable;
}
void start(int delay_ms, int priod_show_ms, int priod_hide_ms ) {
time_start_ = millis();
time_disp_ = delay_ms;
time_hide_ = time_disp_ + priod_show_ms;
time_end_ = time_hide_ + priod_hide_ms;
}
void draw() {
if ( !enable_ ) return;
int time = millis() - time_start_;
if ( time < time_disp_ ) {
}
else if (time < time_hide_ ) {
stroke(92,128,128,100);
fill(44,104,96,100);
glowhexagon(x_, y_, size_);
}
else if (time < time_end_ ) {
stroke(255,255,255,192);
noFill();
strokeWeight(1.0f);
hexagon(x_, y_, size_);
}
else {
}
}
void glowhexagon(float x, float y, float size) {
blendMode(SCREEN);
for ( int i = 0; i < 6; i++ ) {
strokeWeight(2.0f*i);
hexagon( x, y, size);
}
blendMode(BLEND);
}
void hexagon(float x, float y, float size){
beginShape();
for ( int i = 0; i < 6; i++ ) {
float rad = 2*PI*i/6 + PI/2;
vertex(x + size * cos(rad), y + size * sin(rad));
}
endShape(CLOSE);
}
}
class HexagonLine {
Hexagon[] hex_;
HexagonLine(float size, int n) {
hex_ = new Hexagon[n];
float hexagon_width = size*sqrt(3);
for ( int i = 0; i < hex_.length; i++ ) {
if ( i%2 == 0 ) {
hex_[i] = new Hexagon( i*hexagon_width/2, 0, size);
} else {
hex_[i] = new Hexagon( i*hexagon_width/2, size*1.5, size);
}
}
for( int i = int(random(3,6)) + 1; i < (hex_.length - 1); i+=int(random(3,6)) ) {
hex_[i].display(false);
}
}
void start(int delay_ms, int interval_ms) {
for ( int i = 0; i < hex_.length; i++ ) {
hex_[i].start(delay_ms + interval_ms * i, 80, 50);
}
}
void draw() {
for ( int i = 0; i < hex_.length; i++ ) {
hex_[i].draw();
}
}
}
class CyberText {
final String RANDOM_CHAR = "!#$%&=~|QWERTYUIOP`ASDFGHJKL+*ZXCVBNM<>?_";
String text_ = "";
int time_start_ = -1;
int time_disp_ = 0;
int priod_ = 0;
void setText(String text) {
text_ = text;
}
void start(int delay_ms, int priod_ms) {
time_start_ = millis();
time_disp_ = delay_ms;
priod_ = priod_ms;
}
void draw(float x, float y) {
int time = millis() - time_start_;
if ( time_start_ == -1 ) return;
if ( time < time_disp_ ) return;
int len = 0;
if ( time < (time_disp_ + priod_) ) {
float coef = (float(time) - float(time_disp_)) / float(priod_);
len = int(float(text_.length()) * coef);
}
else {
len = text_.length();
}
String str = text_.substring(0, len);
if ( len < text_.length() ) {
str += str(RANDOM_CHAR.charAt(int(random(0, RANDOM_CHAR.length()))));
}
text(str, x, y);
}
}
プロジェクト一式は、こちら
ポイント
1.アニメーションの作り方
Processingの時計関数 millis()
を使って現在時刻を取得。時間経過によって draw()
関数の描画内容を変化させる事で、アニメーションを行います。
6角形Haxagon
クラスを例にとって説明すると、下記の通りです。
- start()関数は、アニメーション開始を指示する関数です。
この関数では time_start_
変数にアニメーション開始時間を保存しておきます。
void start(int delay_ms, int priod_show_ms, int priod_hide_ms ) {
time_start_ = millis();
・・・
}
- draw()関数は、各フレーム毎に呼び出す描画関数です。
time = millis() - time_start_
で、アニメーション開始からの時間経過を取得(a)
- 時間経過に応じて、表示内容を4通りに変更
(b)表示なし→(c)6角形表示(塗りつぶしあり)→(d)6角形表示(枠のみ)→(e)消去
int time = millis() - time_start_;
if ( time < time_disp_ ) {
}
else if (time < time_hide_ ) {
・・・
}
else if (time < time_end_ ) {
・・・
}
else {
}
以上で、start()関数を呼び出すと、時間経過によってdraw()関数の描画内容が変化し、6角形が表示・消滅するアニメーションになります。
この6角形クラスを複数個まとめたものが HexagonLine
クラスで、各6角形の表示位置・アニメーション開始タイミングをずらす事でライン状にスキャンするアニメーションとしてます。
2.サイバーテキストの利用
スローで再生するとわかるのですが、クレジットの名前は一時的に違う文字が表示され、徐々に正しい名前に置き換わっていく表現になっています。
尚→小釘→小野敦→小野学
今回は、類似表現を工学ナビさんのサイトにあるWatch Dogs Profilerで見つけたので、これを改造して利用しました。ただ、表示速度を早くした結果、ほとんど効果が分からなくなってしまいました・・・オリジナルは、かなりカッコいいです。
参考にした情報
- deconbatch さん - ぼんやり光る効果を出す簡単な方法 その2 : Processing Tips
- 工学ナビ さん - BACK YARD
- おもちゃラボ さん - はてなブログでソースコードを折りたたむ方法