これはなに
Processingというものをご存知ですか。
Processingとは、グラフィックに特化したプログラミング言語(&統合開発環境)で、高度な技術を使わなくても簡単にビジュアルプログラミングができるものです。ゲームだって作ることができます。
D言語くんライフゲームやこのゲームもProcessing製です。
今回はProcessing.jsというJavaScriptライブラリを用いて、Processingで制作したものをブラウザ上で動かす方法からDOMをいじる方法まで紹介します。
今回のデモはこちらにあります。
Processing.jsの使い方
Processing.jsの使い方の例として次の方法があります。
- Processingのコードを別ファイルで書き、それを読み込んで実行する方法
- Processingのコードを予めJavaScriptに変換してから、それを読み込んで実行する方法
- 直接JavaScriptで書いて、それを読み込んで実行する方法
この記事では1番の方法を採用します。
Processingのコードを書く
まずは簡単なProcessingのコードを書いてみましょう。
とりあえず、例として「クリックするとマウスの位置に円が表示されるプログラム」です。
void setup() {
size(640, 640);
background(0);
stroke(255);
fill(150);
strokeWeight(5);
}
void draw() {
}
void mouseClicked() {
ellipse(mouseX, mouseY, 50, 50);
}
Processing.jsを使ってみる
これをブラウザ上で動かすために次のファイルを同じフォルダに入れてください。(pathの設定によっては異なるディレクトリ構造でも大丈夫です)
- index.html
- processing.js: ここからダウンロードしてくる
- app.pde: ↑ のソースファイル
index.htmlは例えば以下のように記述してください。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Processing.js Demo</title>
</head>
<body>
<canvas data-processing-sources="app.pde"></canvas>
<script src="./processing.js"></script>
</body>
</html>
あとは、index.htmlをブラウザで開くだけです。
そう。これだけ。
Processing.jsを使えば、たったのこれだけでブラウザで動くようにできるのです。
注意: Chromeだとセキュリティの都合上
XMLHttpRequest cannot load file:hogehoge. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
のようなエラーが出て表示されないと思うので、ローカルサーバーを立ち上げてそこで開くか、別のブラウザを使うか、起動オプションに「--allow-file-access-from-files」をつけるかなどしてください。(詳しくはこことかこことかを見てください)
ちなみに複数の.pdeファイルを読み込みたい場合は
<canvas data-processing-sources="app.pde"></canvas>
のところを
<canvas data-processing-sources="app.pde hoge.pde poyo.pde"></canvas>
のように半角スペースで区切って書いてください。改行でもいいです。順番はどうでもいいです(たぶん)。
ツイート機能を追加する
ブラウザで公開するとなるとほしい機能といえば「ツイート機能」です。
これはProcessingのlink関数を使えば可能です。指定されたURLに飛ぶことができます。
さきほどのapp.pdeに以下のコードを加えてください。
void keyPressed() {
if (key == 't') {
link("https://twitter.com/intent/tweet?text=ツイートテスト", "_blank");
}
}
たったのこれだけで「tキーを押すとツイートできる」ようになりました!
これは、Twitterが提供しているTwitter Web Intentというサービスを利用しています。
詳しい使い方はここなどを参考にしてください。
JavaScript側からProcessingの変数や関数にアクセスする
例えば、さっきのProcessingのプログラムに「ボタンをクリックすると、円の色を変更する」機能を追加させるにはどうしたらよいか?
各ファイルを次のように書き換えてください。
app.pde
void setup() {
size(640, 640);
background(0);
stroke(255);
fill(200);
strokeWeight(5);
}
void draw() {
}
void mouseClicked() {
ellipse(mouseX, mouseY, 50, 50);
}
void keyPressed() {
if (key == 't') {
link("https://twitter.com/intent/tweet?text=ツイートテスト", "_blank");
}
}
void setColor(int r, int g, int b) {
fill(color(r, g, b));
}
- setColor関数を追加しただけです。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Processing.js Demo</title>
</head>
<body>
<canvas id="app" data-processing-sources="app.pde"></canvas>
<p>
<button onclick="setColor('app', 255, 255, 255)">White</button>
<button onclick="setColor('app', 255, 0, 0)">Red</button>
<button onclick="setColor('app', 0, 255, 0)">Green</button>
<button onclick="setColor('app', 0, 0, 255)">Blue</button>
<button onclick="setColor('app', 0, 0, 0)">Black</button>
</p>
<script src="./processing.js"></script>
<script type="text/javascript">
function setColor(id, r, g, b) {
var pjs = Processing.getInstanceById(id);
pjs.setColor(r, g, b);
}
</script>
</body>
</html>
編集したら実行してみてください。
このように新たなボタンがCanvasの下に表示され、各ボタンを押すと、円の色が対応した色に変化します。
やっていることは単純で、
- [app.pde 23-25] 円の色を変更するsetColor関数を定義する。
- [index.html 19-24] idとRGBを引数にとり、Processing内のsetColor関数を実行する関数を定義する。Processing.jsによって"コンパイル"されたProcessingプログラムのインスタンスはProcessing.getInstanceById(id)で取得することができる。
- [index.html 8] canvasタグにidを加える。(ここではid="app"としています。)
- [index.html 10-16] 各buttonを作成する。このときに各buttonのonclick属性にさきほど定義した関数を呼び出すように設定する。
同じようにして「画面をクリアするボタン」や「テキストエリアに書かれた文字をCanvas内に表示させるボタン」なども簡単に作ることができます。
Processing側から任意のタイミングでJavaScriptのコードを動かす
例えば、さっきのProcessingのプログラムに「描画した円の数を(Canvas内ではなく外で)表示させる」機能を追加させるにはどうしたらよいか?
Processingはもともとブラウザ上で動かすことを想定して作られてはいないのでgetElementByIdなどのDOMに関する命令はありません。(たぶんないはず)
しかし、JavaScript側からProcessingにアクセスすることはできるのでそれを利用します。
各ファイルを次のように書き換えてください。
app.pde
interface JavaScript {
void updateCount(int count);
}
void bindJavaScript(JavaScript js) {
javascript = js;
}
JavaScript javascript;
int ellipseCount = 0;
void setup() {
size(640, 640);
background(0);
stroke(255);
fill(200);
strokeWeight(5);
}
void draw() {
if (javascript != null) {
javascript.updateCount(ellipseCount);
}
}
void mouseClicked() {
ellipse(mouseX, mouseY, 50, 50);
ellipseCount++;
}
void keyPressed() {
if (key == 't') {
link("https://twitter.com/intent/tweet?text=ツイートテスト", "_blank");
}
}
void setColor(int r, int g, int b) {
fill(color(r, g, b));
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Processing.js Demo</title>
</head>
<body>
<canvas id="app" data-processing-sources="app.pde"></canvas>
<p>
<button onclick="setColor('app', 255, 255, 255)">White</button>
<button onclick="setColor('app', 255, 0, 0)">Red</button>
<button onclick="setColor('app', 0, 255, 0)">Green</button>
<button onclick="setColor('app', 0, 0, 255)">Blue</button>
<button onclick="setColor('app', 0, 0, 0)">Black</button>
</p>
<p>count: <span id="count"></span></p>
<script src="./processing.js"></script>
<script type="text/javascript">
function setColor(id, r, g, b) {
var pjs = Processing.getInstanceById(id);
pjs.setColor(r, g, b);
}
</script>
<script type="text/javascript">
function updateCount(count) {
document.getElementById('count').innerHTML = count;
}
</script>
<script type="text/javascript">
var bound = false;
function bindJavaScript() {
var pjs = Processing.getInstanceById('app');
if(pjs != null) {
pjs.bindJavaScript(this);
bound = true;
}
if(!bound) setTimeout(bindJavaScript, 250);
}
bindJavaScript();
</script>
</body>
</html>
編集したら実行してみてください。
こんな感じで、描画した円の個数が表示されます。
新たに追加した部分は次のとおりです。
- [app.pde 10] グローバルにellipseCountという変数を定義する。
- [app.pde 29] mouseClicked関数内でellipse関数を呼び出すたびにellipseCountをインクリメントさせる。
- [app.pde 1-3] 「updateCount関数をもつJavaScriptというインターフェース」を定義する。
- [app.pde 9] グローバルにjavascriptというJavaScript型の変数を定義する(初期値がnullであることに注意)。
- [app.pde 5-7] JavaScript側から呼び出すためのbindJavaScript関数を定義する。ここで、引数のjs変数を、さきほど定義したjavascript変数に代入している。
- [app.pde 22-24] 毎フレーム実行されるdraw関数内で、javascriptのupdateCountメソッドを呼ぶ。
- [index.html 18] 円の描画回数を表示するタグをつくる。(ここではid="count"のspanタグを用いている)
- [index.html 27-30] updateCount関数を定義する。
- [index.html 32-43] JavaScriptをProcessing側に†紐付けする†。Processing.jsの"コンパイル"が間に合わなかった場合は紐付けに失敗するので、その場合はsetTimeout関数で250ms間隔で紐付けさせるようにしている。
いえーい。これでProcessingをブラウザで思うがままに動かすことができるようになりました!!!
おわりに
ここまで読んでくださりありがとうございます。
今回のデモはこちらにあります。
以下は、今回の記事に関する補足情報ですが、興味ある方はぜひ読んで下さい。
補足情報
Java依存の命令について
PrcessingはもともとJavaの上で動いているので、Javaに依存した命令を使うことができます。しかし、そのような命令はProcessing.jsに対応していないものが多いので、使わないようにしましょう。
例えば、int型の値を文字列に変換するときにInteger.toStringを使うのではなくProcessingの組み込み関数であるstrやnfを使いましょう。(String.valueOfは使っても大丈夫みたいです。)
うっかりすると微妙にハマるので気をつけてください。
ちなみにArrayList、HashMapなどは対応しているみたいです(未検証ですが・・・)。
詳しくは公式のリファレンスを見てください。
Processing.jsの動作速度について
Processing.jsを使ってみての感想ですが、ぶっちゃけ"遅い"です。Processing上で普通にfps60で動いてたものがブラウザ上だとカクカク動くことが結構あります。(自分のコードが悪いだけかもしれませんが?)
そのような場合は、高速化を頑張ってするしかないです。JavaScriptが得意なのであれば、素直にJavaScriptを使ったほうがいいでしょう。
Processingの良さは、手軽にグラフィカルなものが作れるということにあると思うので、「ちょっと思い至ったものをぱぱっと作る」「短時間で"動く"ものを作る」目的で使うのに適している、というのが自分の考えです。
p5.jsとProcessing.jsについて
Processing.jsと似たものにp5.jsというライブラリがあります。
僕は使ったことがないので詳しいことは言えないですが、Processingの各便利関数をJavaScriptに移植したもののようです。つまり、JavaScriptで書くことを前提としているのでDOMとの親和性がProcessing.jsよりも高いです。(とは言ってもProcessing.jsでもJavaScriptで直接かけるし、あまり違いはないような気がします)
ちなみに昔は公式サイトはprocessing.orgではなくproce55ing.orgというドメインを使っていたらしく、その名残からか「p5」という略称が使われることがしばしばあります。p5.jsの命名もそこから来ているものかと。。。
Processingオンラインエディタ
Processing.jsやp5.jsについて調べてたらおもしろいオンラインエディタやツールが色々とありました。軽く紹介します。
- まほうのハコ - P5 Visual Editor - (alpha): ScratchのProcessing版みたいなもの。
- p5.Playground: 描画部分とコーディング部分があり、インタラクティブにプログラミングができる。(描画部分の図形を直接動かしたりできるのでおもしろい)
参考サイト
この記事を書くにあたって、以下のサイトを参考にしました。