7.8 制限時間付き選択肢(その2)

今回は制限時間付き選択肢プラグインの残りのメソッドを見ていくね。
うん。
じゃまずは onLinkClicked メソッドから。
onLinkClicked メソッドって、 選択肢がクリックされた時に呼び出されるメソッドだったよね?
onLinkClicked メソッドについては §7.5 参照。
そうだよ。
制限時間が付く場合は、選択肢がクリックされた時にトランジションを止めなくちゃいけないから、 そのためのスクリプトを追加する必要があるんだ。
なんで選択肢がクリックされたらトランジションを止めなくちゃいけないの?
トランジションを止めないと選択肢がクリックされた後もトランジションが続くから、ゲージがずっと減り続けちゃうでしょ。
あ、そっか。選択肢がクリックされたらゲージは消さなくちゃいけないんだ。
そういうこと。だから onLinkClicked メソッドの中で、 こうやってトランジションを止めるの。

onLinkClicked メソッド>

function onLinkClicked(link)
{
    
if(foreTimeLayer !== void)
    {
        // 制限時間が設定されている場合は
        // リンクがクリックされた時点でトランジションを強制終了します
        foreTimeLayer.stopTransition();
    }

    // 指定のシナリオファイル・ラベルにジャンプします
    kag.process(link.storage, link.target, link.countpage);

    // 選択肢・制限時間表示用レイヤをすべて破棄します
    clear();
}

stopTransition っていうのがトランジションを止めるメソッド?
そ。この場合 stopTransition メソッドを呼び出すのは stoptrans タグを実行するのとおんなじって思って OK だよ。
stoptrans タグはすべての背景・前景・メッセージレイヤに対して stopTransition メソッドを呼び出して、トランジションをすべて終了させます。
そーいえば stoptrans タグでもトランジションを止められるよね。
ここstopTransition メソッドを呼び出しとくと、 トランジションを終わらせてからジャンプできるわけね。
なるほどね。
あ、あとちょっと気になったんだけど、stopTransition メソッドを呼び出す前に foreTimeLayervoid じゃないかどうかチェックしてるのって何の意味があるの?
制限時間付き選択肢なんだから、foreTimeLayer って void にはならないんじゃないの?
まぁ制限時間を付けてる時は確かにそうなんだけど、 このプラグインは制限時間なしの普通の選択肢用にも使えるようにするつもりだから。
普通の選択肢を表示する時は foreTimeLayer は使わないから void になるの。
あ、そーなんだ。
制限時間なしの選択肢の時は foreTimeLayer も使わないし、 トランジションもしないから、stopTransition メソッドも呼び出す必要ないでしょ。
確かにそうだね。
あとは、トランジションが終わった後に制限時間のゲージ画像を消さなきゃいけないから、 clear メソッドはこんな感じになるね。

clear メソッド>

function clear()
{
    for(var i=links.count-1;i>=0;i--)
        invalidate links[i]; // 選択肢オブジェクトを無効化します
    links.clear(); // 配列の要素をすべて消去します

    // 制限時間が設定されている場合は制限時間表示用レイヤを無効化します
    if(foreTimeLayer !== void)
    {
        invalidate foreTimeLayer;
        foreTimeLayer = void;
        invalidate backTimeLayer;
        backTimeLayer = void;
    }
}

if ブロックの中で制限時間のゲージを表示してるレイヤを無効化してるんだね。
そ。もう制限時間を表示するレイヤは必要なくなってるからね。
えっと、無効化したあと foreTimeLayerbackTimeLayervoid にしてるのはなんで?
次に選択肢を表示する時は制限時間付きじゃないかもしれないから。
どーいうこと?
ここで void にしとかないと、 無効化した後も foreTimeLayerbackTimeLayervoid にならないから、次に制限時間なしの選択肢を作ると、 クリックされた時に onLinkClicked メソッドの if ブロックの中身が実行されてエラーになっちゃうの。
そうなの?
だって foreTimeLayer が無効化されてるのに foreTimeLayer.stopTransition(); を実行しようとするわけだから、 当然エラーになるでしょ。
あー、確かに無効化されたオブジェクトのメソッドは呼び出せないもんね。
っていうか invalidate で無効化したら foreTimeLayer って void になるんだと思ってた。
ん〜、まぁ確かに void になりそうな気もするけどね。
実際には invalidate 演算子でオブジェクトを無効化しても、 変数の値は変わらないんだ。
そっか。だから void にしとかなくちゃいけないんだね。
そういうこと。
あとは大丈夫?
うん、おっけー。
じゃ次行くね。
次は onMessageHiddenStateChanged メソッドなんだけど、 まぁこれは単に制限時間の表示をメッセージレイヤの表示状態に合わせてるだけ。

onMessageHiddenStateChanged メソッド>

function onMessageHiddenStateChanged(hidden)
{
    // メッセージレイヤの表示状態にあわせて選択肢の表示状態を設定します
    setObjProp(links, 'visible', !hidden);

    // メッセージレイヤの表示状態にあわせて制限時間の表示状態も設定します
    if(foreTimeLayer !== void)
        foreTimeLayer.visible = backTimeLayer.visible = !hidden;
}

foreTimeLayervoid じゃなかったら、 foreTimeLayerbackTimeLayervisible を、 選択肢の visible と同じ !hidden にしてるんだね。
そ。hidden はメッセージレイヤが非表示になった時に true になるから、 !hidden でメッセージレイヤの表示状態に合わせてるわけね。
これは問題ないでしょ?
うん。
じゃ最後は時間切れになった時に呼び出される onTimeOut メソッド。
これは今回新しく作るメソッドだよ。

onTimeOut メソッド>

function onTimeOut()
{
    // 選択肢・制限時間表示用レイヤをすべて破棄します
    clear();
}

clear メソッドを呼び出してるだけだね。
まぁ時間切れになった時は選択肢を消せばいいだけだからね。
そうなの?
今作ってる制限時間付き選択肢のプラグインは、 時間切れになった時はジャンプせずにそのままシナリオの実行を続けるっていう仕様にしてるから、 時間切れになった時にやらなくちゃいけないのは選択肢を消すことだけだよ。
ふぅん。
あ、そーいえばこの onTimeOut メソッドってどこで呼び出すの?
マクロの中で呼び出すの。
マクロって… blink マクロのこと?
んーん、blink マクロじゃなくて、 今回新しく作る、制限時間表示のトランジションを開始するマクロから呼び出すの。
制限時間表示のトランジションを開始するマクロ?
blink マクロは選択肢の項目を追加するだけだから、 これだけだと制限時間表示のトランジションが実行できないでしょ。
確かにそうだね。
ってことは、制限時間表示のトランジションを実行するために、その新しく作るマクロで start メソッドを呼び出すってこと?
ん、そういうこと。
で、これが制限時間表示のトランジションを実行する startblink マクロだよ。

startblink マクロ>

[macro name=startblink]
; 制限時間表示のトランジションを開始します
[eval exp="buttonlink_object.start(mp)"]
; トランジションの終了を待ちます
[wt canskip=false]
; トランジションが終了した場合は時間切れなので onTimeOut メソッドを呼び出します
[eval exp="buttonlink_object.onTimeOut()"]
[endmacro]

確かに最初に start メソッドを呼び出してるね。
start メソッドを呼び出すと、その中で beginTransition メソッドが呼び出されてトランジションが始まるから、 次に wt タグでトランジションの終了を待つわけね。
canskip 属性を false にしてるのって何か意味があるんだよね?
まぁね。何でかわかる?
う〜ん…トランジションが終わった後に onTimeOut メソッドを呼び出してるみたいだから、 canskip 属性が true になってたら、 トランジション中にクリックすると時間切れになっちゃうのかな?
そう。トランジション中に選択肢以外の部分をクリックするとすぐ時間切れになっちゃうってのはマズイでしょ。
まぁそーだよねぇ。
制限時間内に選択肢がクリックされた場合は、onTimeOut メソッドが呼び出される前に onLinkClicked メソッドが呼び出されて、 その中で kag.process メソッドが呼び出されるから、 その選択肢を選んだ時のシナリオにジャンプできるわけね。
制限時間内に選択肢がクリックされなかったら、wt タグの次の eval タグが実行されるから、 onTimeOut メソッドが呼び出されるんだね。
ん、その場合は kag.process メソッドは呼び出されないから、 ジャンプせずにそのままシナリオの実行が再開されるの。
だから時間切れの時の処理は showblink マクロの後に書いとけば OK。
なるほどね。
じゃこれでプラグインのスクリプトは一通りチェックできたから、 実行して実際に制限時間付き選択肢を作ってみよっか。
うん!
とりあえず §7.1 の制限時間付き選択肢を作ってみることにするね。
first.ks はこんな感じ。

§7.1 の制限時間付き選択肢を作るための first.ks>

; プラグインを読み込みます
[call storage="ButtonLinkPluginEx.tjs"]

月まで歩いて行けるとすると、ずっと歩き続けたとして到着するまでにおよそ何年かかる?[r](制限時間10秒)

; 選択肢を表示します
[blink text="約1年" graphic="buttonlink_bg" left=50 top=83 target=*incorrect]
[blink text="約10年" graphic="buttonlink_bg" left=50 top=141 target=*correct]
[blink text="約100年" graphic="buttonlink_bg" left=50 top=199 target=*incorrect]
[blink text="約1000年" graphic="buttonlink_bg" left=50 top=257 target=*incorrect]
; 制限時間表示のトランジションを開始します
[startblink time=10000 forestorage="timelimit_fore" backstorage="timelimit_back" left=50 top=10 rule="timelimit_rule"]

; 時間切れになった場合はこれ以降のスクリプトが実行されます
[er]
時間切れ!
; 以下略

; 正解の場合はこれ以降のスクリプトが実行されます
*correct
[er]
正解!
; 以下略

; 不正解の場合はこれ以降のスクリプトが実行されます
*incorrect
[er]
不正解!
; 以下略

まずプラグインを読み込んで問題文を表示して
それから blink マクロで選択肢を表示してstartblink マクロで制限時間表示のトランジションをスタートしてるんだよね。
blink マクロに指定できる属性については §7.3startblink マクロに指定できる属性については §7.7 参照。
ん、そうそう。
ちなみに startblink マクロの forestorage 属性と backstorage 属性と rule 属性に指定されてる画像はそれぞれこんな感じだよ。

<制限時間表示に使用する画像>

forestorage 属性に残り時間が MAX の時の画像を指定して、 backstorage 属性に残り時間が 0 の時の画像を指定するんだったよね。
そ。
じゃ選択肢がクリックされた後の動作はわかる?
えっと、この問題って確か「10年」が正解だったから、 この選択肢を選んだ時は target 属性に指定されてる *correct っていう正解のラベルにジャンプして、 それ以外の選択肢を選んだ時は *incorrect っていう不正解のラベルにジャンプするってことだよね?
ん。じゃ時間切れの時は?
時間切れになるとどこにもジャンプしないから、 startblink マクロの次に書いてあるスクリプトが実行されて、 「時間切れ!」って表示されるよね。
そうだね。
んじゃ実際にやってみよっか。必要なスクリプトはここに置いとくね。
じゃあ実行してみるね。

<実行結果>

ちゃんと制限時間のゲージが短くなっていってるように見えるね。
…って言ってもこの画像じゃわかんないと思うけど。
んー、まぁそこは実際に実行して確かめてみてねってことで。
とりあえず選択肢をどれかクリックしてみて。
じゃあ最初は正解の「10年」をクリックしてみるね。

<「10年」をクリックした時の結果>

うん、ちゃんと「正解!」って表示されたね。
じゃもう一回実行して今度は違う選択肢を選んでみて。
わかった。
じゃあ今度は「1年」をクリックしてみるね。

<「1年」をクリックした時の結果>

これもおっけーだね。
んじゃ最後は時間切れのチェックね。
はーい。

<どの選択肢もクリックせずに10秒経過した時の結果>

これもだいじょぶだね。
ん、今回はうまくいったね!
だね。
それじゃ、第7章は今回でおしまい。
あ、もう終わりなんだ。
うん、まぁよく使いそうな選択肢って言ったら大体こんなところだと思うし、 選択肢についてはこれくらいでいいんじゃないかな。
そっか。
えっと、じゃあ次は何やるの?
次はドラッガブルレイヤを作ってみようと思うんだ。
ドラッガブルレイヤ?
マウスでドラッグすると動かせるレイヤって意味だよ。
一般的に何て呼ぶのかちょっとわからないから、 ドラッグできるって意味でドラッガブルレイヤ(draggable layer)って呼ぶことにしたの。
ドラッグすると動かせるレイヤねぇ…
あ、そーいえば position タグに draggable っていう属性があったと思うけど、コレと何か関係あるの?
ん、次に作ろうと思ってるのはソレのことだよ。
あ、そうなの?
メッセージレイヤは position タグで draggable 属性を true にするとドラッグして動かせるようになるわけだけど、 それをメッセージレイヤ以外のレイヤでも出来るようにしてみようって話。
なるほどね。
でもそれってどんな使い道があるの?
ん〜、一応ちょっとしたパズルゲームを作ってみるつもり。
パズルゲーム?
まず画像を細かく分割して、画面上にバラバラに配置するの。
で、その分割された画像をドラッグして、ジグソーパズルみたいにして画像を完成させるパズルだよ。
へぇ。じゃあその分割された画像がドラッガブルレイヤになってるってこと?
そうそう。
あと、ドラッグできるシステムボタンも作ってみるつもりだよ。
ドラッグできるシステムボタンって?
第5章でメッセージウィンドウの横に表示するシステムボタンを作ったよね。
§5.1 参照。
うん、作ったね。
あれをドラッグできるようにするの。
え、でもあのシステムボタンの位置って別に変える必要ないんじゃない?
確かにメッセージを表示するウィンドウを画像で指定してる時は動かす必要はないと思うんだけどね。
画像を使ってない時、つまり position タグの frame 属性が "" の時は、 好きな位置に動かせるとちょっと便利かなと思って。
ふぅん。
ま、詳しいことはまた次回話すことにするね。
うん、わかった。
それじゃ、次の章もがんばってついてきてね!


前へ | TOP | 次へ