この記事は Processing Advent Calendar 2015 の9日目の記事です。
クリエイティブコーディングのIDEとして名高い Processing を肴に、イケてる文章もしくは作品をシェアする場と解釈しています。
過去カレンダーを拝見したら皆さんとても素敵かつ技術力あふれるスケッチでいっぱいです。
そして今年はなんと女優の 池澤あやか さんも参加されている…。
そんな中、理系でもタレントでもない私がノリで参加してもいいのか迷いましたが、本当にノリで参加させていただきました。
主催者の @p5info さん、会を告知されていたp5のエバンジェリスト的存在の @p5Aholic さん ありがとうございます。
( openFrameworks の方がよく使っているとか言えない)
12月といえば、クリスマス。
今回の投稿もこの季節に便乗したいなと思い考えました。
ただ孤独な民にとっては少々辛いイベントであることも確かです。
私のロンリークリスマス歴もなかなかに年季入っています。
同年代のステータスが続々と婚約とか結婚とか出産とかなる中、自分もライフステージを真剣に考えなきゃなぁと思いをはせつつ、怠惰の力が僅差でまさり何も行動せず今に至ります。
話はそれましたが、Processingでカッコイイ作品でもつくれば、比較的低コストに女の子に振り向いてもらえるかも?と一縷の期待を抱き、クリスマスにぴったりのスケッチをつくろうと考えました。
みんながインタラクティブに遊べるのが良いなと思い、Processing の JavaScript 移植版である p5.js をチョイス。
ここからは実際に手を動かしながら考えます。
そうだ、雪だ!
パーティクルの雪をふわっと降らせよう。
ちょっとありきたりだけど…方向は間違っていない。
もしダメだったら、全部、雪のせいだ。
1 2 3 4 5 6 7 8 9 10 |
function setup() { ... img.loadImage(“雪の画像.png”); } function draw() { for (var i = 0; i < たくさん; i++) { img.draw(pos[i].x, pos[i].y); } } |
うーん、ありきたりすぎる…
というか、我々が本当に見たいもの・得たいものは雪なのか?
いや違う。
愛だ。
愛が欲しい。
愛が欲しい、本気(マジ)で。
無償の愛で包まれたいなぁ… という願望を Processing で唱えてみましょう。
1 2 3 4 5 |
function draw() { for (var i = 0; i < 欲しい数; i++) { text("愛", pos[i].x, pos[i].y); } } |
おおおお!
無限の愛をどしゃどしゃ降らせることができます!
アガりますね!
いや、愛だけじゃなく 欲しいもの全部 降らせられる!
そう Processing ならね!
1 2 3 4 5 6 7 8 9 10 11 |
var 願望; function 願いを唱える(e) { 願望 = e.value; } function draw() { for (var i = 0; i < num; i++) { text(願望, pos[i].x, pos[i].pos.y); } } |
ついにできた!
こちらが完成版!!
スマホ、PC各種ブラウザで動作しますが、PCのFireFoxがお勧めです。
まずは「愛」が降り注ぎます。
無償の愛があなたを包み込みます。
テキストボックスには欲しいものを何でも入力することができます。
やってみよう!
…まずは…
カネ。
Chromeだと絵文字も入る…!
嬉しい!
顔文字!
これはおもしろいぞ!
…
…
ふと我にかえります。
虚しい…。
なぜか一段と虚しい。
虚しい気持ちですよね?しかしそれを見越してのOne More Thing!
隠し機能があります!
端末に向かってデス声で怒鳴りつけてみましょう。
マイク入力に反応して破壊的な色調になります!
ですが、ゴメンナサイ…この機能については、
iOS 未対応
IE 未対応
Chrome 未対応…
HTML5のgetUserMediaというマイクなどにアクセスする機能を、iOSやChromeなどで使えないためです。。
FireFoxでお楽しみください…!(本当の隠しコマンド感…)
最後に
最後に少々マジメな気づきを
- p5.jsによるマイクアクセスにほんの少し触れてみましたが、上述のようにブラウザでの統一的な普及が待たれるところです。
- 文字をテクスチャにしたパーティクルを飛ばすのは効果としておもしろいです
- パーティクルというと、位置ベクトル、速度ベクトルを実装した粒子クラスを想像しますが、Tween.jsのようなイージングを実現するライブラリを使うことで楽してアニメーションを実装することができます。変数も少ないし軽い。
Processing は魔法!
ですがやはり若干拭えない虚しさと寂しさを胸にソースを全て掲載します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <title>あ、降ってきたね…</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.19/p5.min.js"></script> <script src="<?php bloginfo('template_url'); ?>/js/libs/Tween.js"></script> <script src="<?php bloginfo('template_url'); ?>/js/libs/p5.sound.js"></script> </head> <style type="text/css"> body { margin: 0; padding: 0; overflow: hidden; width: 100%; } #container { background: -moz-linear-gradient(top, #202, #066); /* Firefox用 */ background: -webkit-gradient(linear, left top, left bottom, from(#202), to(#044)); /* Safari,Google Chrome用 */ } .textArea { font-family: 'ヒラギノ明朝 ProN W3', 'Hiragino Mincho ProN', 'georgia'; position: absolute; top: 200px; background: rgba(100, 100, 100, 0.7); height: 200px; width: 100%; color: #fff; text-align:center; vertical-align: middle; z-index: 1; font-size: 1.5em; } #textInput { font-family: 'ヒラギノ明朝 ProN W3', 'Hiragino Mincho ProN', 'georgia'; text-align:center; font-size: 2em; max-width: 180px; margin: 0 10px; color: #fff; background: rgba(100, 100, 100, 0.5); border: none; border-bottom: 2px #fff solid; } </style> <body> <div id="container"></div> <div class="textArea"> <p>あ、<input type="text" value="愛" id="textInput">。</p> <p>降ってきたね...</p> </div> <script> var textInput = document.getElementById('textInput'); textInput.addEventListener('change', function() { letter = textInput.value; }); var letter = "愛"; var partNum; var particles = []; var mic; var micLevel = 0.0; var sizeSd; function setup() { var canvas = createCanvas(window.innerWidth, window.innerHeight); canvas.parent("container"); if (window.innerWidth < 400) { partNum = 100; sizeSd = 10; } else { partNum = 150; sizeSd = 20; } for (var i = 0; i < partNum; i++) { particles[i] = new node(); initParticle(particles[i], i * 30); } // getUseMediaが使えればマイク入力の取得開始 if (hasGetUserMedia()) { mic = new p5.AudioIn(); mic.start(); } else { alert('getUserMedia() is not supported in your browser'); } textFont("Georgia"); frameRate(30); textAlign(CENTER, TOP); } function draw() { clear(); TWEEN.update(); // マイクからの音量を更新 if (mic) micLevel = mic.getLevel(); if (micLevel > 0.1) { push(); translate(random(micLevel * 200), random(micLevel * 200)); scale(1.0 + micLevel); background(255, 0, 0); } for (var i = 0; i < partNum; i++) { particles[i].draw(); } if (micLevel > 0.1) { pop(); } } // 粒子のクラス function node() { this.position = createVector(0.0, 0.0); this.size = 10 + Math.abs(randomGaussian(0, sizeSd)); this.col = color(100 + this.size * 3); this.draw = function() { textSize(this.size); fill(this.col); text(letter, this.position.x, this.position.y); } } // TWEEN.jsを使ってy座標を更新。特定の周期で再帰 function initParticle(particle, delay) { var particle = this instanceof node ? this : particle; var delay = delay !== undefined ? delay : 0; particle.position.x = random(window.innerWidth); particle.position.y = -100; new TWEEN.Tween( particle ) .delay( delay ) .to({}, 10000 / (particle.size / 20)) .onComplete( initParticle ) .start(); new TWEEN.Tween(particle.position) .delay( delay ) .to({ y: window.innerHeight + 100 }, 10000 / (particle.size / 20)) .start(); } function windowResized() { resizeCanvas(window.innerWidth, window.innerHeight); textFont("Georgia"); frameRate(30); } function hasGetUserMedia() { // getUseMedia系メソッドが使えるかチェック return !!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); } </script> </body> </html> |
完