イベントシステム

# イベントシステムについて

吉里吉里で TJS スクリプトを記述する場合、イベント駆動型のプログラミングモデルを採る必要があります。
イベントは「何かが起こった」ときに、他のオブジェクトや、自分のオブジェクト内にそれを通知するために発生します。イベントハンドラにはこれに応答する処理を書くことになります。
吉里吉里では一つのイベントハンドラで必要以上に長い時間がかかることは好ましくありません。時間を待ちたいときは Timer クラスを用いることをおすすめします。

# 同期イベントと非同期イベント

同期イベントとは、たとえばサウンドバッファで再生を開始した場合に、その play メソッド内で onStatusChanged イベントが発生するように、オブジェクトの操作を行うとすぐにその場で発生するイベントです。
これに対し、非同期イベントとは、吉里吉里内部にあるイベントキュー ( 発生させるイベントを一時保管している場所 ) に一時的に蓄積されます。このイベントはすべての他のイベントハンドラの処理が終わるまで発生せず、他のイベントハンドラ内では発生しません(ただし例外があるので下記 note を参照してください)。タイマー周期が来て発生する onTimer イベントなどや、ユーザからの入力により発生するすべてのイベントは非同期イベントです。
Note
Window.showModal のような一部の、ユーザからの入力を得ようとするような機能は、イベントキューを動作させる (イベントを配信する) ことがあります。これにより、イベントハンドラ中で別の非同期イベントが発生する可能性はあります。
非同期イベントをスクリプトの操作で発生させるために AsyncTrigger クラスがあります。

# 画面反映のタイミング

ウィンドウにレイヤを表示するための画面反映のタイミングは非同期イベントと同じで、すべての他のイベントハンドラの処理が行われたあとです。一つのイベントハンドラ内で何度描画を行っても、内部的な画像バッファには描画されていますが、画面にはすぐに反映はされません。イベントハンドラからぬけて、吉里吉里が描画のタイミングを得たときに初めてウィンドウに内容が描画され、反映されます。

# クラス内でのイベントハンドラ

クラス内で発生したイベントはそのクラス内で、スーパークラスのイベントハンドラをオーバーライドすることによりハンドリングする事ができます。
たとえば、Timer クラスからサブクラスを作成し、以下のようにイベントハンドラを作成することができます。
`class MyTimer extends Timer
{
function MyTimer()
{
super.Timer(...);
}
function onTimer()
{
// ( ここに onTimer の処理 )
super.onTimer(...); // スーパークラスのメソッドは一応呼び出す
}
}
`
スーパークラスのメソッドは呼び出す必要はありませんが、一般的には呼び出します。また、スーパークラスのメソッドは呼ばないと後述の action メソッドによるイベントハンドリングができません。

# actionメソッド

Layer クラスや WaveSoundBuffer クラスなどは、コンストラクタに指定したオーナーの action メソッドにイベントを発生する機能があります。
action メソッドには辞書配列オブジェクトの引数が一つ渡され、ここにイベントの情報が入っています。
辞書配列のメンバのうち、 target はイベントの発生元オブジェクトを表しています。type はイベント名を表しています。
その他のメンバはイベントによって異なります。たとえば、Layer.onClick イベントならば、x と y というメンバがあり、レイヤ上をクリックされた場所を表します。
`例:
class MyWindow extends Window
{
var layer;
(略)
function MyWindow()
{
super.Window(...);
add(layer = new Layer(this /* this = オーナー */, null));
layer.visible = true;
}
(略)
function action(ev)
{
if(ev.type == "onClick" && ev.target == layer)
{
// layer がクリックされた
System.inform(ev.x, ev.y);
}
}
}
`