KAGのクラスに関しては、KAG3のクラスと継承関係を参照。
主要クラス概要
KAGWindowクラス
ファイル
MainWindow.tjs
継承関係
Window←KAGWindow
概要
KAGそのものを意味するクラス。
ウィンドウの外観、ウィンドウへのイベント(例えばメニュー項目の選択など)の処理、セーブデータの管理、タグハンドラ…などなど役割は多岐に渡る。
また、多くの処理をメンバ変数の各オブジェクト(各種レイヤ、コンダクタなど)に委譲している。
なお、[ヘルプ‐このソフトについて]メニューで表示されるウィンドウもKAGWindowクラスのオブジェクトである(モーダル状態で表示している点が異なる)。*1
Conductorクラス
ファイル
Conductor.tjs
継承関係
KAGParser←BaseConductor←Conductor
概要
Conductor(指揮者、案内者といった意味)クラスは、KAGシナリオの解析および進行管理を担当している。本質的には「Timerオブジェクトを有するKAGParser」と言える。タイマーイベントの発行間隔をこまめに制御することで、次のタグを処理するタイミングを計っている。
- KAGは、メインコンダクタ(kag.mainConductor)と予備コンダクタ(kag.extraConductor)の2つのオブジェクトを保持し、状況に応じて適宜切り替えている
- メインコンダクタは右クリックサブルーチン以外の進行管理を担当している
- 予備コンダクタは右クリックサブルーチンの進行管理を担当している
- kag.mainConductorまたはkag.extraConductorの別名(エイリアス)として、kag.conductorというメンバ変数がある。平時はこのメンバ変数を介することで(透過的に)KAGシナリオの進行管理が行われている
コンダクタはタグハンドラの戻り値(整数)で、次のタグを処理するタイミングを計っている。戻り値の意味は以下の通り。
BaseConductor.timerCallback()の実装も参照のこと。例えば、[[後述のbgmoptタグハンドラ>#p2.1]]は0を返すので、ノーウェイトで次のタグが処理されることになる。
戻り値 | 意味 | 備考 |
-5 | いったんイベントを処理(現在のタグは後回し) | |
-4 | いったんイベントを処理 | |
-3 | 後回ししてブレーク | |
-2 | ブレーク | |
-1 | シナリオ終了 | sタグのみ |
0 | ウェイトを掛けずに次へ | |
1以上 | (その値だけウェイトを掛けて)次へ |
KAG(kagオブジェクト)のメソッド(タグハンドラ含む)を直接呼び出す場合、コンダクタに悪影響を与えないよう注意する必要がある。kag.close()など、安定(s、l、pタグで停止)していないと呼び出せないメソッドの多くは、これに関係している。
補足
アニメーション定義ファイル(.asd)を扱うコンダクタとしてAnimationConductorクラスがある。
AnimationConductorクラスはBaseConductorクラスを継承している。
また、AnimationConductorクラスのタグハンドラはAnimationLayerクラスが供給している。*2
MessageLayerクラス
ファイル
MessageLayer.tjs
継承関係
Layer←KAGLayer←MessageLayer
概要
メッセージレイヤを実現しているクラス。kag.currentは表画面または裏画面の別名(エイリアス)で、平時はkag.currentを通してメッセージレイヤを制御している。
- 表画面…kag.fore.meesages[n]
- 裏画面…kag.back.messages[n]
- カレントのメッセージレイヤ…kag.current
現在描画中の行(メッセージ)は、一旦、kag.current.lineLayer(KAGLayerオブジェクト)に描画され、改行などで確定したらメッセージレイヤに(描画した文字を)コピーしている。この様子は、Shift+F12でレイヤ構造をダンプするか、コンソールでkag.current.lineLayer.opacity=128などと入力してみると判る。
ハイパーリンクの情報、グラフィカルボタン(LinkButtonLayerオブジェクト)、チェックボックス(LinkCheckBoxLayerオブジェクト)、単一行エディット(LinkEditLayerオブジェクト)は配列kag.current.linksに保持されている。
ハイパーリンクはkag.current.highlightLayer(KAGLayerオブジェクト)1個で実現されている。メッセージレイヤ上にハイパーリンクが配置された場合、配列kag.current.linksの情報を元にkag.current.highlightLayerオブジェクトの座標・サイズなどを変更し、ハイパーリンクに見せかけている。
なお、メッセージの描画速度、スキップの状態、自動的に読み進むか否か…といった情報はKAGWindowオブジェクトが保持している:全メッセージレイヤで共通の値となってるのはこのため。
ButtonLayerクラス
ファイル
ButtonLayer.tjs
継承関係
Layer←KAGLayer←ButtonLayer
概要
ボタンを実現しているクラスで、KAGのグラフィカルボタン(LinkButtonLayer)のスーパークラス。
文字ボタン(例:確認ダイアログボックスの[はい][いいえ])、グラフィカルボタンの両方に対応している。
文字ボタンかグラフィカルボタンかによって多少動作が異なるが、以下の状態に応じて外観を変えている点では共通している。例えば、グラフィカルボタンの場合、以下の「状態」を横に並べた画像データを保持し、状況に応じてimageLeftプロパティで表示部分を変更している。
- 通常の状態
- ボタンが押された状態
- ボタンの上にマウスカーソルがある状態
- フォーカスがある状態(ButtonLayer.showFocusImageプロパティが真の場合のみ有効)
なお、現在のKAGで「フォーカスがある状態」は使用されていない。*3
HistoryLayerクラス
ファイル
HistoryLayer.tjs
継承関係
Layer←HistoryLayer
概要
履歴レイヤを実現しているクラスで、メッセージレイヤに描画した文字列は、chタグハンドラを通して履歴レイヤにも送られている。
履歴レイヤに送られたメッセージ/メッセージ履歴アクションは、共にリングバッファ(固定サイズのキューで上限を超えたら古いデータから破棄していく)で管理され、メッセージ履歴表示に備えている。
履歴レイヤの親は背景レイヤ表画面だが、トランジションを実行すると背景レイヤ裏画面が新たな背景レイヤ表画面となるため、メッセージ履歴を表示するたびに親レイヤを繋ぎ換えている。
履歴レイヤ改造のヒントも参照のこと。
KAGMenuItemクラス
ファイル
Menus.tjs
継承関係
MenuItem←KAGMenuItem
概要
コンストラクタ引数にハンドラまたは文字列を指定できるようにしたMenuItemクラス。メニュー選択時、指定されたハンドラを呼び出すか、指定された文字列をTJS式として評価する。
KAGのメニュー構造はkag.menuをルートメニューとし、以下のようなツリーを形成している(非フリーセーブモード時)。
なお、「―」はセパレータ(無名のMenuItemオブジェクト)を意味する。
この構造を変更するには、親子関係を繋ぎ換えたり、子メニューを追加/削除すれば良い(Config.tjsにも修正が必要になるが)。
- kag.systemMenu…[システム]
- kag.rightClickMenuItem…[メッセージを消す]
- kag.showHistoryMenuItem…[メッセージ履歴の表示]
- kag.skipToNextStopMenuItem…[次の選択肢/未読まで進む]または[次の選択肢まで進む]
- kag.autoModeMenuItem…[自動的に読み進む]
- kag.autoModeWaitMenu…[自動的に読み進むウェイト]
- kag.autoModeFastMenuItem…[短い]
- kag.autoModeFasterMenuItem…[やや短い]
- kag.autoModeMediumMenuItem…[普通]
- kag.autoModeSlowerMenuItem…[やや長い]
- kag.autoModeSlowMenuItem…[長い]
- ―
- kag.goBackMenuItem…[自動的に読み進む]
- kag.goToStartMenuItem…[最初に戻る]
- ―
- kag.exitMenuItem…[終了]
- kag.characterMenu…[文字表示]
- kag.chSpeedMenu…[表示速度]
- kag.chNoWaitMenuItem…[ノーウェイト]
- kag.chNoWaitMenuItem…[高速]
- kag.chNormalMenuItem…[普通]
- kag.chSlowMenuItem…[遅い]
- ―
- kag.chNonStopToPageBreakItem…[ページ末まで一気に]
- kag.ch2ndSpeedMenu…[一度読んだところは]
- kag.ch2ndNoWaitMenuItem…[ノーウェイト]
- kag.ch2ndFastMenuItem…[高速]
- kag.ch2ndNormalMenuItem…[普通]
- kag.ch2ndNoChangeMenuItem…[変えない]
- ―
- kag.ch2ndNonStopToPageBreakItem…[ページ末まで一気に]
- kag.chAntialiasMenuItem…[アンチエイリアス]
- kag.chChangeFontMenuItem…[フォント]
- kag.chSpeedMenu…[表示速度]
- kag.restoreMenu…[栞をたどる]
- kag.storeMenu…[栞をはさむ]
- kag.displayMenu…[画面]
- kag.windowedMenuItem…[ウィンドウ表示]
- kag.fullScreenMenuItem…[フルスクリーン]
- kag.helpMenu…[ヘルプ]
- kag.helpIndexMenuItem…[目次]
- kag.helpAboutMenuItem…[このソフトについて]
- kag.debugMenu…[デバッグ]
- kag.reloadScenarioMenuItem…[シナリオの再読込み]
- kag.showConsoleMenuItem…[コンソール]
- kag.showControllerMenuItem…[コントローラ]
例えば、吉里吉里/KAG実行中に[デバッグ]メニューを表示させるには、コンソールから以下の式を入力すれば良い。
kag.debugMenu.visible = true
コードリーディングのポイント
個人的なやり方をまとめたもの。
人によっては別のアプローチの方が読み取りやすいかも知れないので、あくまで参考程度に。
タグの内部処理を読み取る
タグのほとんどはKAGWindowクラス(MainWindow.tjs)のメソッドgetHandlers()で定義されているため、このメソッドを基点にタグの内部処理を読み取ることができる。
メソッドgetHandlers()はタグ名をキー、式中関数(匿名関数)を値とする辞書配列を返す。
この式中関数はタグハンドラとして扱われるもので、以下の仕様を満たす。
- 引数として辞書配列オブジェクトを1つ受け取る;タグの属性名をキー、属性値を値とする辞書配列(ただしcond属性は含まれない)
- 戻り値として整数を返す。戻り値はコンダクタの動作を制御する
例えばbgmoptタグなら、メソッドbgm.setOptions()を呼び出し、0を返す式中関数が結び付けられていることが判る。
この式中関数は、incontextof thisにより、KAGWindowオブジェクト(kag)自身のメソッドとして呼び出されている。
bgmopt : function(elm) { // BGM のオプション設定 bgm.setOptions(elm); return 0; } incontextof this,
更に、KAGWindow()クラスのコンストラクタから、メンバ変数bgmは、BGMクラス(BGM.tjs)のオブジェクトであることが判る…という感じで読み進めていけば、タグの内部動作が理解できる。
// BGM オブジェクトを作成 bgm = new BGM(this); add(bgm);
クラス名から読み取る
KAG3のクラスと継承関係を見れば、どのクラスが何を担当しているかの目星がつくので、そのクラスを基点に読み進めていけば内部処理を読み取ることができる。*4
startup.tjsから順に読み取る
KAG起動時の処理を読み取りたい場合は、素直にstartup.tjsから順にMainWindow.tjsまで読んでいく方法が理解しやすい。