2011年6月30日木曜日

ScratchとProcessingの通信に成功

以前書いた、Scratchの「遠隔センサー接続」で、Processingのプログラムとの間で相互通信できることを確認しました。

まず、Scratchのスクリプトはこんな感じ。わりと適当。


Processing側から"mew"というメッセージが届いたら、「ニャー」と鳴きます。
また、ステージ上ではスクリプト1が回転していて、上を向いたらProcessing側へ"Turned!"というメッセージを送ります。

Processingのプログラムは以下の通り。

import processing.net.*;
Client ScratchClient;
PFont f;
int cnt = 0;
void sendtoscratch(String dataOut) {
byte [] sizeBytes = { 0, 0, 0, 0 };
  sizeBytes[3] = byte(dataOut.length());
  for (int i=0; i<4; i++) {
    ScratchClient.write(sizeBytes[i]);
  }
  ScratchClient.write(dataOut);
}
String recieveFromScratch() {
  String inString = ScratchClient.readString();
  return inString;
}
void setup() {
  ScratchClient = new Client (this, "127.0.0.1", 42001);
  f = loadFont("HiraKakuProN-W3-16.vlw");
  textFont(f);
  size(640, 480);
  background(255);
  fill(0);
}
void draw() {
  sendtoscratch("sensor-update " + "\"mouseX\"" + str(mouseX));
  sendtoscratch("sensor-update " + "\"mouseY\"" + str(mouseY));
  delay(50);
  if (ScratchClient.available() > 0) {
    text(recieveFromScratch(), 10, (cnt++)*20);
  }
}
void mouseClicked() {
  sendtoscratch("broadcast " + "\"mew\"");
}
やってることは、127.0.0.1(local loopbackですな)の42001ポートに接続して、Scratch側に送信するフォーマット(32bit長の、メッセージのバイト数+実際の文字列)を作ってやる「sendtoscratch()」という関数と、Scratch側からは単純に文字列が送られてくるのでそれを受け取る「recieveFromScratch()」という関数を用意しただけ。

で、センサ名「mouseX」と「mouseY」を用意して、Processingのウインドウ上のマウスの座標をScratch側に送りつつ、また、ウインドウ上でマウスクリックすると「mew」というメッセージを送るというお仕事。また、もしScratch側からデータがきていたら、それをウインドウ上に描くというお仕事。

動かす手順は先にScratchで「遠隔センサー接続を許可する」してポートを開いてから、Processingのほうを起動します。でないと、クライアント接続のエラーチェックしていないので、接続できないままdraw()のループに入り、Javaのexceptionが出まくってしまいます。

Scratch側でも一応センサ値も表示しておきました。これは「センサーボード」ではなくて、「[スライダー▼]の値」ブロックのセンサー名をmouseXにして、右のチェックボックスをチェックするとステージ上に現れます。mouseYも同様にすると、以下のような画面になります。

でもって、猫が回転して上向きになると、Processingのウインドウに届いたメッセージが出ます。
よくわからないけれど、日本語のメッセージはScratch側からは出せない仕様なのか、受け取ると文字化けします。ProcessingはJavaベースなのでUTF-8ならいいのかと思いましたし、Scratchの国際化もUTF-8ベースらしいので大丈夫なはずなんですが、なにかが間違っているみたい。.readString()をいろいろ変えてみたりしたけどうまくない。ヒラギノを指定したけどそれでもだめ。わからん。