狠狠撸

狠狠撸Share a Scribd company logo
プログラムの構造
理解支援機能を
Processingとして実装する
情報科学科4年
秋山 耀
免責事項
? 書いてあることにミスがあるかもしれません
? 間違ってたらごめんなさいm(_ _)m
なぜ作れたか?
? ProcessingのToolの作り方の記事
(http://blog.livedoor.jp/reona396/archives/55030723.html)
? 運良くProcessingのmodeのテンプレートもみっかった
? しかもコンパイルできた
? KwzrくんのBasho(https://github.com/kvvzr/Basho)
? processingのグローバル変数を監視
? Processingでも出来るんだ!
Processingのモードとは
? ProcessingのIDEの挙動を変更できる!
? 応用すればProcessingをpythonでかけたりする
? 日本ではあまりやられていない?
? やられてないことをすり抜けて作った感じ
? 作り方はここを見てね
https://sites.google.com/site/gutugutu30/other/processingnomodew
ozuoru
リフレクションとは?
? コンパイル後に動的に関数呼び出しできたり
? JavaでJavaをコンパイルしたり
? しかもコンパイルしたものをそのまま利用できたり
今まで作ったモード
? Basho Mode
? Realtime Mode
? Realtime Tweak Mode
? Realtime Tweak Picker Mode
Realtime ~ Modeのミソ
? 他の学習支援との差
? インストールがクソ簡単! ← 基本的にはコピーしてくるだけ!
? ProcessingのIDEの中で動く → mode切り替えるだけで使える!
? コレに尽きる
これからRealtime ~ Modeの仕組みの説明
? 順序立てて説明します
? 機能が肥大化してきたので作った順に説明
Basho Mode
Basho Mode
? まずProcessingのモードで何が出来るのか?
? 最初に作ったMode
? テストで作ってみた
? というか普通に便利そう
Processing Java Modeの仕組み
Processing Java
前処理 コンパイル
基本的にProcessingはJava
なのでJavaのソースコードに変換する
その後Javaとして実行
Processing Java Modeの仕組み
Processing Java
前処理 コンパイル
Modeならばここに処理を突っ込める!
Basho Modeの仕組み
Processing Java
追加
ソースコード
Kwzrくんの作ったソースコード
そのまま
前処理 コンパイル
まとめ
? Modeなら,コンパイル前のソースコードを操作できる
? Mode すごい
? 追加するだけで使えるようにしてくれたkwzrくんに感謝
Realtime Mode
Realtime Mode
? 一番の難関
? ここさえ理解できれば残りの机能は书くだけ(ほぼ考える必要なし)
Basho Modeの仕組み
Processing Java
追加
ソースコード
Kwzrくんの作ったソースコード
そのまま
前処理 コンパイル
Realtime Modeの仕組み
Processing Java
グローバル変数と
Setup文だけ引用 コンパイル
予め用意した
ソースコード
リフレクションのソースコード
実行するソースを
すり替える!
Realtime Modeの仕組み
Processing Java
グローバル変数と
Setup文だけ引用
コンパイル
予め用意した
ソースコード
リフレクションのソースコード
1秒に1回書き出し
適当にJavaのコードに
Realtime Modeの仕組み
Processing
リフレクションで読み込み
コンパイル 実行!
1秒に1回書き出し
適当にJavaのコードに
Realtime Modeの仕組み
Processing
はたから見ると
常に反映しているように見える!
Realtime Mode 実装の要
1.Processingの実行をするときはリフレクションのコードにすり替えて実
行
2.Processingのコードは常にどっかに書き出しておく(ディレクトリ固定)
3.リフレクションのコードが書きだしたコードをコンパイル
? 2,3を高速で行うことでリアルタイムっぽく见せてる
Javaからprocessingへ変換する
import processing.core.*;
public class TempPApplet extends PApplet {
public PApplet apa;
public void setup() {
size(600, 600);
}
public void draw() {
background(0); rect(100, 100, 100, 100);
}
}
public PApplet apa;
public void setup() {
size(600, 600);
}
void draw() {
background(0); rect(100, 100, 100, 100);
}
Processing Java
Javaからprocessingへ変換する
import processing.core.*;
public class TempPApplet extends PApplet {
public PApplet apa;
public void setup() {
size(600, 600);
}
public void draw() {
background(0); rect(100, 100, 100, 100);
}
}
public PApplet apa;
public void setup() {
size(600, 600);
}
void draw() {
background(0); rect(100, 100, 100, 100);
}
Processing Java
Javaからprocessingへ変換する
import processing.core.*;
public class TempPApplet extends PApplet {
public PApplet apa;
public void setup() {
size(600, 600);
}
public void draw() {
background(0); rect(100, 100, 100, 100);
}
}
public PApplet apa;
public void setup() {
size(600, 600);
}
void draw() {
background(0); rect(100, 100, 100, 100);
}
Processing Java? 基本的にProcessingはJava
? 単純化のためpublicなどはない構文にしているぐらい
? Javaへの変換はProcessingの前処理機構が普通はやってくれている
? PdePreprocessorクラス
? PdePreprocessorクラスの引っ張り方,使い方がわからない
? なので文字列を解析して挿入をしていく
Javaからprocessingへ変換する
import processing.core.*;
public class TempPApplet extends PApplet {
public PApplet apa;
public void setup() {
size(600, 600);
}
public void draw() {
background(0); rect(100, 100, 100, 100);
}
}
public PApplet apa;
public void setup() {
size(600, 600);
}
void draw() {
background(0); rect(100, 100, 100, 100);
}
Processing Java? 基本的にProcessingはJava
? 単純化のためpublicなどはない構文にしているぐらい
? Javaへの変換はProcessingの前処理機構が普通はやってくれている
? PdePreprocessorクラス
? PdePreprocessorクラスの引っ張り方,使い方がわからない
? なので文字列を解析して挿入をしていく
が,
Javaからprocessingへ変換する
import processing.core.*;
public class TempPApplet extends PApplet {
public PApplet apa;
public void setup() {
size(600, 600);
}
public void draw() {
background(0); rect(100, 100, 100, 100);
}
}
public PApplet apa;
public void setup() {
size(600, 600);
}
void draw() {
background(0); rect(100, 100, 100, 100);
}
Processing Java? 基本的にProcessingはJava
? 単純化のためpublicなどはない構文にしているぐらい
? Javaへの変換はProcessingの前処理機構が普通はやってくれている
? PdePreprocessorクラス
? PdePreprocessorクラスの引っ張り方,使い方がわからない
? なので文字列を解析して挿入をしていく
が,
? やる気が出た(というか自分で書くのめんどくさくなった)のでトライ
? PdePreprocessorクラスを外から使うことに成功!
? めちゃくちゃ簡単だった
Pdepreprocessor preproc=new Pdepreprocessor(”書き出すクラス名”);
PrintWriter stream = new PrintWriter(new FileWriter(”書き出す場所”));
try {
preproc.write(stream,”Processingのプログラム”);
} finally {
stream.close();
}
変数どうする?
? Processingで実行した実体Aと毎回コンパイルしている実体Bが違う
? 実体Aから実体Bを呼び出してるだけ
? どうやって統合するか?
実行
プログラム
A
新しい
プログラム
B アクセス
新しい
ソースコード
コンパイル
変数どうする?
? Processingで実行した実体Aと毎回コンパイルしている実体Bが違う
? 実体Aから実体Bを呼び出してるだけ
? どうやって統合するか?
void setup() Processingで実行した実体A
void draw() 毎回コンパイルしている実体B
関数 毎回コンパイルしている実体B
キー入力 Processingで実行した実体A
変数どうする?
? void setup()文とグローバル変数だけ実体A
? 残りは実体Bにお任せ
void setup() Processingで実行した実体A
void draw() 毎回コンパイルしている実体B
関数 毎回コンパイルしている実体B
キー入力 Processingで実行した実体A
普通に呼び出してるだけなら問題なし
? 実態に変化がなければ普通に2つのProcessingのプログラムが動い
てるのと同じ
? しかも実際の挙動が関わるのは各種関数とvoid draw()ぐらい
? 両方毎回コンパイルしている実体Bに存在
? キー入力だけProcessingで実行した実体Aから毎回コンパイルしてい
る実体Bに渡してやればいい
問題はソースコードが新しくなった時
? 1秒に1回ソースコードが新しくなる
? この時に変数の値を覚えておかないと毎回リセットされてしまう
? どうするか?
そこでリフレクション(マッピング)
? getClass().getDeclaredFields() 対象のクラスがもつすべてのメンバ変
数を取得
? setAcesstable(true) privateだろうがなんだろうがアクセス可能にす
る
? これでクラスが持っているすべてのメンバの参照を書き換える!
実行
プログラム
古い
プログラム
プログラムが起動中
実行
プログラム
新しい
ソースコード
古い
プログラム
新しいソースコードが来た!
プログラムが起動中,
プログラムが変更された
実行
プログラム
新しい
ソースコード
古い
プログラム
新しいソースコードが来た!
もういらない!
プログラムが起動中,
プログラムが変更された
実行
プログラム
新しい
ソースコード
古い
プログラム
新しいソースコードが来た!
変数の退行
g
width
sketchPath
まず今動いてるプログラム
からデータをすべて
持ってくる
実行
プログラム
新しい
ソースコード
新しいソースコードが来た!
古いプログラムは廃棄
新しい
ソースコード
実行
プログラム
新しい
ソースコード
実行
プログラム
新しい
プログラム
コンパイル
新しいプログラムを
コンパイル
実行
プログラム
新しい
プログラム
変数の復元
g
width
sketchPath
データをすべてコンパイル
したものに移す
実行
プログラム
新しい
プログラム
更新完了!
実行
プログラム
新しい
プログラム
もっと
新しい
ソースコード
新しいソースコードが来た!
以下繰り返し
変数の受け渡し
? 描画とは別スレッドでソースコードの更新を行う(1秒に1回)
? そのときに変数の値を常に書き出す
? mouseX,mouseYなどの値はdraw文の中で受け渡す
? システムから取ってくる値は毎回渡す
描画はどっちでやっているのか?
? Processingで実行した実体Aの(PGraphics)gに毎回コンパイルしてい
る実体Bの(PGraphics)gを代入
? Processingで実行した実体Aでの描画が毎回コンパイルしている実体
Bに反映される
実行
プログラム
A
新しい
プログラム
B アクセス
新しい
ソースコード
コンパイル
まだ残ってる问题
プログラムの更新の一幕
まだ残ってる问题
まだ残ってる问题
なぜ廃棄されないか?
? Javaはガベージコレクション(GC)でメモリ管理
? 参照がされてない実体は自動で破棄される
? 参照が残ってると要らなくても残る!(あたりまえ)
? どっかで参照が残っている
? リフレクションでメンバ変数いじってるため,特定が困難
? というかそれ以前(クラスローダとか)が問題な気もする…
? 残念ながら未解決
なぜ廃棄されないか?
? Javaはガベージコレクション(GC)でメモリ管理
? 参照がされてない実体は自動で破棄される
? 参照が残ってると要らなくても残る!(あたりまえ)
? どっかで参照が残っている
? リフレクションでメンバ変数いじってるため,特定が困難
? というかそれ以前(クラスローダとか)が問題な気もする…
? 残念ながら未解決
よくわからないけど,
現時点でのバージョンでは
起こらないようです
まとめ
? 最初に実行するプログラムはリフレクションのプログラム
? 実際に動かしたいプログラムは1秒に1回別ファイルで出力
? リフレクションで1秒に1回ソースをコンパイル
? 変数の更新もリフレクションで
? リフレクション最強!
? JavaはGCのお陰で基本メモリ管理しなくて良い
? しかし,メモリリークが起きると地獄
RealtimeTweak Mode
RealtimeTweak Mode
? リアルタイムでソースコードを更新する基盤はできた
? あとはtweak modeの実装をちゃかちゃかするだけ
? http://galsasson.com/tweakmode/
カラーピッカーコンポーネント
ドラッグコンポーネント
Tweak Modeって何やってんの?(推測)
? プログラム実行時,プログラムをtweak独自のプリプロセッサに投げ
て構文解析
? 数値のところにドラッグコンポーネントを設置(Swingらしい)
? 色のところにカラーピッカーコンポーネントを設置
? プログラムをすり替え 数値部分をすべて変数にして変更できるよう
に
? 数値が変わったらそれをosc通信で飛ばして教える
? 多分,これやってられない
なんでosc通信?
? Processingエディタ自体と実行プログラムは別プログラム(別プロセ
ス)
? 普通は干渉しあえない
? そこで鲍顿笔通信である辞蝉肠通信を使っている
RealtimeModeが干渉できてる理由
? 実行プログラムが鑑賞しているのは,動いてないプログラムだから
? 動いてるプログラム同士は基本的に無理なはず
Processing
エディタのプログラム
動いてる
書きだされたソースコード
動いてない
実行プログラム
動いてない
コンポーネントの正体
? ProcessingのIDE上にウインドウの枠のないフレームを作成
? 一つ一つのコンポーネントが違うフレーム
? やってられない
? 画像には14つのコンポーネント=14つのフレーム
実装できたのはカラーピッカーだけ
? Swingのフレームを一つ余分に作る→カラーピッカー
? エディタ上で選択された文字列がfill,stroke,backgroundならカラー
ピッカーを起動
? その行ごと置换してしまう
EditorクラスでIDEを自分好みに
? Editorクラス:ProcessingのIDEの機能を統括する
? これがいじれればどうにかなる
? でもまともなドキュメントとメソッドが無い
? やる気がなくなる最大の理由
まとめ
? Tweakはosc通信を使用
? Realtimeはリフレクションを使用
? Tweakは構文解析で意味分かんないソースコードに
? Realtimeはリフレクションで思考停止しているソースコードに
? Editorクラスが鬼門
? Tweak Modeすごい
RealtimeTweakPicker Mode
Pickerライブラリ
? 図形に番号を登録する
? どの座標にどの番号の図形が描かれてるかがわかるライブラリ
例)何をマウスオーバーしているかが取れる
? Processing 1.x時代では1番使われてたライブラリ(俺に)
? Processing 2.xだと動かない(頑張れば動くらしい)
? 何より便利 当たり判定とか書く必要がなくなる
Pickingライブラリ 実際の使い方
picker.start(1);
ellipse(100,100,100,100);
picker.start(2);
rect(0,0,100,100);
picker.stop();
println(picker.get(mouseX,mouseY));
Pickingライブラリ 今回の使い方
picker.start(1);
ellipse(100,100,100,100);
picker.start(2);
rect(0,0,100,100);
picker.stop();
println(picker.get(mouseX,mouseY));
ここを行数にしただけ
ソースコードにpicker.startを挿入しまくる
? 名前がピカ?ュウっぽいのは変数名が重ならないようにするため
問題はどうやってエディタにデータを送るか
? リフレクションはコンパイルして利用してるだけ 一方通行
Processing
エディタのプログラム
書きだされたソースコード 実行プログラム
問題はどうやってエディタにデータを送るか
? リフレクションはコンパイルして利用してるだけ 一方通行
Processing
エディタのプログラム
書きだされたソースコード 実行プログラム
プロセス間通信
? Tweak Modeと同じ手法
? osc通信
? リフレクションを使った旨味が減ってしまった
osc通信
? Open Sound Control
? 音を飛ばす規格らしい
? Processingでプロセス間通信!といったらosc通信
? Javaもライブラリがあるので楽に書ける
双方向の通信が可能に
? 実行プログラムはエディタプログラムをコンパイルして呼び出す
? エディタプログラムは実行プログラムから状況を受け取る
Processing
エディタのプログラム
書きだされたソースコード 実行プログラム
まとめ
? 結局プロセス間通信
? oscはProcessing使いなら覚えとくと楽
? 笔颈肠办颈苍驳ライブラリの復活はいつなの?
問題点
クラスのお話
クラスが使えない
? 致命傷
? 理由がイマイチ分からない
おさらい
? void setup()文とグローバル変数だけ実体A
? 残りは実体Bにお任せ
void setup() Processingで実行した実体A
void draw() 毎回コンパイルしている実体B
関数 毎回コンパイルしている実体B
キー入力 Processingで実行した実体A
おさらい
? void setup()文とグローバル変数だけ実体A
? 残りは実体Bにお任せ
void setup() Processingで実行した実体A
void draw() 毎回コンパイルしている実体B
関数 毎回コンパイルしている実体B
キー入力 Processingで実行した実体A
ちょっと待て!
クラスの定義はどちらに含めるか?
Processingで実行した実体A
? こちらに外部ライブラリのインポートやらなんやらが入る
? 初期化とかこっち void setup()
? 基本的に弄りたくないものをこちらに依存させる
毎回コンパイルしている実体B
? 描画処理こっち(嘘)
? 実行時編集したいものをこちらに依存させる
両方の実体に含まれるもの
? 変数の定義
実行
プログラム
A
新しい
プログラム
B アクセス
新しい
ソースコード
コンパイル
书き方によって依存する実体が変わる
书き方によって依存する実体が変わる
书き方によって依存する実体が変わる
书き方によって依存する実体が変わる
初期化の処理は実体Aに記述
书き方によって依存する実体が変わる
初期化の処理は実体Aに記述
つまり実体Aの時の定義
=実行時の定義
が呼ばれる
书き方によって依存する実体が変わる
実行時に変更を加えても
変更は反映されない
つまり実体Aの時の定義
=実行時の定義
が呼ばれる
书き方によって依存する実体が変わる
呼び出しはできるのか?(謎)
定義が違ってくる
A.Test
B.Test
书き方によって依存する実体が変わる
呼び出しはできるのか?(謎)
定義が違ってくる
A.Test
B.Test
? 実体BをAのサブクラスとして登録
? 実体Aにclass Testを記述
? 実体Bにはclass Testの記述を行わない
? 実体B上でnew TestされるとスーパークラスであるAで定義されたTest
が動く
书き方によって依存する実体が変わる
?
初期化の処理は変数の宣言と同時
书き方によって依存する実体が変わる
初期化の処理は実体A?実体B
両方に記述
书き方によって依存する実体が変わる
初期化の処理は実体A?実体B
両方に記述
クラスの定義は実体A?実体B
両方に記述
书き方によって依存する実体が変わる
クラスの定義は実体A?実体B
両方に記述
幸い実体Aには記述されてない
书き方によって依存する実体が変わる
クラスの定義は実体Bの
記述が使われると考えて良さそう
幸い実体Aには記述されてない
书き方によって依存する実体が変わる
こんなこと考えなくて良さそう
书き方によって依存する実体が変わる
実体Bコンパイル時,
testのコンストラクタが呼ばれる
书き方によって依存する実体が変わる
つまり実体Bの時の定義
=変更後の定義
が呼ばれる
実体Bコンパイル時,
testのコンストラクタが呼ばれる
おなじ問題が起こる
実際の挙動
コンパイルすらできない
ぬるぽで止まる
謎
予想通り
値がコンパイルごとにリセットされる
「そもそも」 void setup()を実体Aにした理由
? 最初に1回しか呼ばれない はず
? つまりリアルタイムに変更しても意味が無い
? というかリアルタイムに変更したら理解の妨げになるのでは?
? void setup()は初期化の意味合いがある(と勝手に思ってる)
? グローバル変数の追加に対応しない理由
初期化処理をリアルタイムにすべきではな
い
? クラスの場合:コンストラクタ≒初期化処理
? インナークラスを書き換えた場合,どう処理するか?
? コンストラクタが呼ばれるタイミングが任意になる
? 変更を反映するのはどこまで?
? コンストラクタの変更は?
? void draw()は?
結論
? クラスは非対応にしたほうが良さげ?
? 頭おかしくなりそう

More Related Content

RealtimeTweakPickerMode