9.21 レイヤ移動機能を拡張する(その7)

今回は exmove マクロ関係でまだ残ってるメソッドとかクラスを全部見ていくことにするね。
じゃあ今回で9章は終わりってこと?
ん、そうなるね。
そーなんだ。
ところで、さっき残ってるメソッドとクラスを全部見てくって言ったよね?
うん。
ちなみに残ってるのは ExtendedMover クラスの beginMove メソッドと、 あと LinearMoverEx クラスと SplineMoverEx クラス(それぞれ LinearMover クラスと SplineMover クラスを拡張したクラスのことね)だよ。
LinearMover クラスと SplineMover クラスについては §9.16 参照。
そんなにあるの?
っていうか、それホントに今回だけで見ていけるの?
どれも結構シンプルだから、今回だけでいけると思うよ。
んじゃまずは前回ちょっと中途半端になっちゃった beginMove メソッドからね。
このメソッドってどんな時に呼び出されるんだったかは覚えてる?
確か exmove マクロの中で呼び出されてるんだったよね。
あと、静的メソッドだからオブジェクトを作らなくても呼び出せるんだよね。
§9.20 参照。
そうそう。
それじゃメソッドの中身の方を見てくね。
まずここの getLayerFromElm メソッドは前にも出てきたから大丈夫だよね?
getLayerFromElm メソッドについては §9.8 参照。
えっと、引数の辞書配列 elmpage 要素と layer 要素をチェックして…
例えば elm.page"fore"elm.layer"0" だったら、 表画面の 0 番の前景レイヤへの参照を返す、って感じじゃなかったっけ?
そ。で、getLayerFromElm メソッドには elm が指定されてるから…
elm って exmove マクロに指定されてる属性が記録されてる辞書配列だよね?
ん、つまり mp ってことだね。
だからここで移動したり画像を拡大・縮小・回転させたりする対象のレイヤへの参照を layer に代入してるってことね。
mp については §4.8 参照。
その次に stopMove メソッドを呼び出してるみたいだけど…
ここで stopMove メソッドを呼び出す意味あるの?
んー、まぁ念のため、かな。
例えば exmove マクロでレイヤが動いてる途中にもう一回 exmove マクロを実行したりした時に、 一旦移動を止めてから次の移動を始めた方がいいから一応ここで stopMove メソッドを呼び出してるって感じかな。
そーなんだ。
あ、今気づいたんだけど、“layer.stopMove()”ってことは ExtendedMover クラスの stopMove メソッドじゃなくって レイヤの stopMove メソッドを呼び出してるってことだよね?
レイヤにも stopMove メソッドがあるの?
うん、あるよ。
ちなみにこれが前景レイヤとかメッセージレイヤとかの stopMove メソッドだよ。

KAGLayer クラスの stopMove メソッド(KAGLayer.tjs より抜粋)>

function stopMove()
{
    if(moveObject !== voidinvalidate moveObject, moveObject = void;
}

moveObject ってのが void じゃなかったら無効化してるみたいだけど…
moveObject ってなに?
moveObject は普通は LinearMover クラスか SplineMover クラスのオブジェクトだよ。
レイヤの移動が終わったら(つまりこの stopMove メソッドが呼び出されたらってことね)オブジェクトが必要なくなるから、ここで無効化してるの。
spline 属性を true に指定して move タグを実行した場合は SplineMover クラス、それ以外の場合は LinearMover クラスのオブジェクトになります(spline 属性については §9.16 参照)。
なるほどね。
じゃあ LinearMover クラスとか SplineMover クラスのオブジェクトってレイヤが持ってるんだ?
まぁレイヤごとに必要なオブジェクトだからね。
そっか。
…ところで、さっき“普通は” LinearMover クラスか SplineMover クラスのオブジェクトになるって言ってたけど、 普通じゃない場合もあるってコト?
“普通は”ってのは “move タグを使えば”っていう意味だよ。
だから、exmove マクロを使うと moveObject は別のクラスのオブジェクトになるの。
別のクラスって?
LinearMover クラスの拡張版の LinearMoverEx クラスか SplineMover クラスの拡張版の SplineMoverEx クラスのどっちかだね。
この辺にそう書いてあるでしょ。
ホントだ。LinearMoverEx クラスとか SplineMoverEx クラスのオブジェクト作ってるね。
ここの if の条件を見てもらうとわかると思うんだけど、 exmove マクロの spline 属性に true が指定されてたら SplineMoverEx クラス、 spline 属性が省略されてるか false が指定されてたら LinearMoverEx クラスのオブジェクトを作るわけね。
LinearMoverEx クラスと SplineMoverEx クラスってまだ見てないよね?
ん、それはこの後見てくつもりだよ。
そーなんだ。わかった。
で、オブジェクトを作り終わったら、beginMove メソッドでレイヤの移動を始めるんだけど、その前に…
“layer.window.moveCount++;”ってのを実行してるね。
layer.window.moveCount の値を1増やしてるみたいだけど、 これって何かの変数?
“moveCount”ってのは kag オブジェクトが管理してる変数で、 今動いてるレイヤの数を表してるんだ。
ちなみに“layer.window”はこの場合前景レイヤが所属してるウィンドウだから、 kag オブジェクトなわけね。
moveCountKAGWindow クラスのメンバ変数で、KAGWindow.tjs で定義されています。
今動いてるレイヤの数?
そ。だからレイヤが動き始める時(beginMove メソッドが呼び出された時)に moveCount が1増えて、 逆にレイヤの移動が終わった時(stopMove メソッドが呼び出された時)に moveCount が1減るようにする必要があるの。
へぇ…だからここで値を1増やしてるんだね。
あ、でも前回の stopMove メソッドの中には moveCount の値を1減らしてるとこなんてなかったよね?
moveCount の値を1減らすのは他のメソッドでやってるからね。
この辺は LinearMoverEx クラスとかに関係してるとこだから、 詳しくはもうちょっと後で説明するね。
りょーかい。
後は最後に startMove メソッドを呼び出せばレイヤの移動が始まるの。
引数の“+elm.delay”って move タグの delay 属性のこと?
そだよ。
startMove メソッドは拡張とかしてないから、 “layer.moveObject.startMove(+elm.delay);”を実行すると LinearMover クラスか SplineMover クラスの startMove メソッドが呼び出されるんだ。
で、その startMove メソッドの中で delay 属性の処理をやってくれてるの。
えっと、delay 属性ってレイヤが動き始めるまでの時間だから、 例えば“delay=1000”って指定したら、 move タグを実行してから1秒後にレイヤが動き始めるんだったよね?
そうそう。
delay0 じゃない時は LinearMover クラスの中でタイマーを作って移動開始の時間を調整してるんだけど、 その辺の詳しい話はパスさせてもらうね。
さて、じゃこれで ExtendedMover クラスのメソッドは全部チェックできたね。
なんか色んなメソッドがあって、全部見てくのタイヘンだったよねぇ…
まだあと2つクラスが残ってるんだけどね。
あー、LinearMoverEx クラスと SplineMoverEx クラスだよね。
まぁこの2つのクラスはシンプルだから、ExtendedMover クラスに比べたらずっと簡単だよ。
そーなの?
スクリプトを見てみればシンプルだってのがわかると思うよ。
まずこれが LinearMoverEx クラスのスクリプトね。

LinearMoverEx クラス>

class LinearMoverEx extends LinearMover, ExtendedMover
{
    // コンストラクタ
    function LinearMoverEx(layer, elm, finalfunction)
    {
        // スーパークラス(ExtendedMover, LinearMover)のコンストラクタを呼び出します
        var time = +elm.time;
        var accel = elm.accel !== void ? +elm.accel : 0;
        ExtendedMover(layer, elm);
        LinearMover(layer, _path, time, accel, finalfunction);
    }

    // デストラクタ
    function finalize()
    {
        // スーパークラスのデストラクタを呼び出します
        // ※多重継承している時は global.クラス名.finalize となる点に注意(superは使えません)
        global.LinearMover.finalize();
        global.ExtendedMover.finalize();
    }

    // レイヤの移動を停止します
    function stopMove()
    {
        if(moving)
        {
            // レイヤが移動している場合はスーパークラスの stopMove メソッドを呼び出します
            // 同名のメソッドを呼び出すのでここでも global.クラス名.stopMove となります
            global.LinearMover.stopMove();
            global.ExtendedMover.stopMove();
        }
    }

    // コンティニュアスハンドラから呼び出されるメソッド
    function move(tickCount)
    {
        // スーパークラスの move メソッドを呼び出します
        global.LinearMover.move(...); // 位置と不透明度を設定します
        global.ExtendedMover.move(...); // 拡大・縮小・回転を行います
    }
}

LinearMoverEx クラスが LinearMover クラスと ExtendedMover クラスを継承してるってのはわかるよね?
“class LinearMoverEx extends LinearMover, ExtendedMover”って書いてあるもんね。
こーいうのって多重継承って言うんだよね。
※多重継承については §2.8§2.9 参照。
ん、そうそう。
じゃいつも通りコンストラクタから見てくね。
えっと、これって ExtendedMover クラスと LinearMover クラスのコンストラクタを呼び出してるんだよね?
多重継承してるクラスのコンストラクタの中でスーパークラスのコンストラクタを呼び出さなくちゃいけないからね。
ExtendedMover クラスと LinearMover クラスのコンストラクタの引数は §9.18 で確認してるから特に問題ないと思うんだけど、どうかな?
ん〜、ちょっと微妙なとこもあるから一応確認していい?
ん、もちろん。
まず ExtendedMover クラスのコンストラクタの引数の layerelm って、 それぞれ動かすレイヤへの参照と exmove マクロに指定されてる属性の値が記録されてる辞書配列だよね?
そうだよ。
じゃあ LinearMover クラスのコンストラクタの引数の _pathtimeaccel って、それぞれ path 属性と time 属性と accel 属性ってこと?
timeaccel についてはそうだね。
ちなみに accel 属性は省略すると 0 になるから、 elm.accelvoid だったら(つまり省略されてたら) accel0 に設定してるわけね。
_pathpath 属性とはちょっと違うね。
どー違うの?
前にも言ったけど、LinearMover クラスのコンストラクタに指定するのは path 属性の文字列じゃなくって、 path 属性の文字列を配列にしたものなんだ。
§9.18 参照。
あ、そーいえばそんなふうに言ってたね。
それと、もう一つ気になるのは、“_path” って LinearMoverEx クラスの引数の中にも無いし、 コンストラクタの中でも宣言されてないよね?
_pathExtendedMover クラスのメンバ変数だよ。
ExtendedMover クラスのコンストラクタの中(正確には parsePath メソッドの中だけどね)で pathpathex っていう配列を作ったのは覚えてる?
確か path がレイヤの位置と不透明度の変化を表す配列で pathex が拡大率と回転角の変化を表す配列じゃなかったっけ?
そうそう。
で、この“_path”ってのはその時作った“path”の方のことだよ。
え、でも変数の名前が違ってるじゃない?
あ、そっか。それ parsePath メソッドでちゃんと説明してなかったね。
parsePath メソッドのここんとこpath っていう変数に _path を代入してるでしょ。
だから path_path はおんなじなの。
あ、ホントだ。
でもなんでメンバ変数の名前をわざわざ“_path”にしてるの?
LinearMoverEx クラスのもう一つのスーパークラスになってる LinearMover クラスの方に“path”っていうメンバ変数があるから、 一応それと名前がかぶらないようにしたんだ。
名前がかぶっちゃダメなの?
2つのスーパークラス(つまり LinearMover クラスと ExtendedMover クラスのことね)に両方“path”っていうメンバ変数を作ると、 LinearMover クラスの path の中身を書き換えると ExtendedMover クラスの path の中身も書き換わっちゃうの。
あ、そーなんだ。
あとは大丈夫かな?
えっと、finalfunction ってなんだったっけ?
wm タグのためのメソッドだよ。
あ、そーだ。KAG システムに「wm タグで待つのを止めてシナリオの実行を再開して」って伝えるメソッドだったね。
そ。ちなみに ExtendedMover クラスの beginMove メソッドのこの辺を見てもらえばわかると思うけど、 finalfunctionKAGLayer クラス(背景レイヤとか前景レイヤとかメッセージレイヤのクラスのスーパークラスになってるクラスね)の moveFinalFunction っていうメソッドへの参照になってるんだ。
moveFinalFunction ねぇ…聞いたことないメソッドだね。
moveFinalFunction メソッドはシンプルなメソッドだからちょっと中身を見とこっか。

KAGLayer クラスの moveFinalFunction メソッド(KAGLayer.tjs より抜粋)>

function moveFinalFunction()
{
    // 自動移動が終了するときに呼ばれる関数
    window.moveCount--;
    window.onLayerMoveStop();
}

この window.moveCount ってさっき出てきた“layer.window.moveCount”のこと?
ん、そうだよ。
レイヤの移動が始まる時に beginMove メソッドの中で値が1増えて、 レイヤの移動が終わる時にここで値が1減るようになってるんだ。
これで moveCount の値、つまり今動いてるレイヤの数がちゃんと合うようになるよね。
なるほど、確かにね。
あと、“window.onLayerMoveStop”っていうのは何のメソッドなの?
onLayerMoveStopKAGWindow クラス(kag オブジェクトのクラスのことね)のメソッドだよ。
これがそのスクリプトね。

KAGWindow クラスの onLayerMoveStop クラス(MainWindow.tjs より抜粋)>

function onLayerMoveStop()
{
    // レイヤの自動移動が終了した
    conductor.trigger('move');
}

これもシンプルなメソッドなんだね。
“conductor.trigger”ってゆーのがどんなメソッドなのかは知らないけど。
conductor ってのはシナリオの実行を管理してるオブジェクトなんだけど、 詳しく説明するとすごーく長くなっちゃうから、とりあえず「“conductor.trigger('move');”を実行したら wm タグで待つのを止めてシナリオの実行が再開される」って思っといて。
そーなんだ。りょーかい。
ちょっとややこしい話になっちゃったけど、finalfunction についてはこんなとこかな。
んー、とりあえずわかったような気がする…けど、すぐ忘れちゃうかも。
まぁこの辺のことはそんなに詳しく知らなくても大丈夫だと思うよ。
そっか。ならよかった。
じゃ次はデストラクタね。
これは見ての通り、スーパークラスのデストラクタを呼び出してるだけだよ。
§2.9 で言ったように、多重継承してる時は super が使えないから“super.finalize();”じゃなくて“global.クラス名.finalize();”って書くことに注意してね。
う〜ん、2章の後半のことってあんまり覚えてないんだけど…
とりあえずそう書くってゆー決まりがあるんだよね?
まぁ一応ちゃんと理由はあるんだけど、そういう決まりがあるって思っといてもらっても OK だよ。
わかった。
んじゃ次は move メソッドね。
このメソッドはどんな時に呼び出されるんだったか覚えてる?
確かレイヤが動いてる間コンティニュアスハンドラから呼び出されるんじゃなかったっけ?
そうそう。
実際にレイヤを動かすのは LinearMover クラスの move メソッドがやってくれるし、 拡大・縮小・回転するのは ExtendedMover クラスの move メソッドがやってくれるから、 ここでやらなくちゃいけないのはその2つの move メソッドを呼び出すことだけなんだ。
確かに LinearMover クラスと ExtendedMover クラスの move メソッドを呼び出してるだけみたいだけど…
move メソッドを呼び出す時にも“global”をつけなきゃいけないんだね。
LinearMover クラスにも ExtendedMover クラスにも move メソッドがあるから、 単に“super.move(...);”って書いただけじゃどっちの move メソッドを呼び出したらいいかわからないでしょ?
あ、そっか。
デストラクタ以外でも、スーパークラスにおんなじ名前のメソッドがあったら“global.クラス名.メソッド名();”になるの。
ふぅん、そーなんだ。
後は大丈夫だよね?
えっと、引数の“...”ってどーいう意味だったっけ?
move メソッドには tickCount っていう引数があるよね。
うん。
この引数には、レイヤが動き始めてからの経過時間がミリ秒単位で代入されてるんだけど、 2つのスーパークラスの move メソッドを呼び出す時に、 その tickCount の値をそのまま引数に指定するよ、って意味ね。
じゃあ“global.LinerMover.move(tickCount);”“global.ExtendedMover.move(tickCount);”を実行するのとおんなじってことかな。
ん、この場合はそうなるね。
あとは OK ?
※引数の省略については §1.17 参照。
うん。
じゃ最後は stopMove メソッドね。
まぁこれも LinearMover クラスと ExtendedMover クラスの stopMove メソッドを呼び出すだけだから特に問題ないよね。
でもその前に“moving”っていう変数? の値をチェックしてるよね?
movingLinearMover クラスのメンバ変数で、 レイヤが動いてる時に真になって、レイヤが移動する前とか移動が終わった後は偽になるの。
ってことは、レイヤが動いてる時だけ if ブロックの中身を実行するってことだよね?
レイヤが動いてなかったら stopMove メソッドを呼び出す必要ないからね。
そっか。
じゃこれで LinearMoverEx クラスのメソッドは一通りチェックできたね。
基本的にスーパークラスのメソッドを呼び出してるだけだからそんなに難しくないでしょ?
確かに難しくはないけど、スーパークラスのメソッドを呼び出すだけだったら、 わざわざ多重継承しなくてもよさそーな気がするんだけど…
拡張するのが LinerMover クラスだけだったらそうかもしれないけど、 もう一つ SplineMover クラスも拡張しなきゃいけないからね。
SplineMover クラスって spline 属性が true の時に使われるクラス、だったよね?
そ。で、これが SplineMover クラスを拡張した SplineMoverEx クラスのスクリプトね。

SplineMoverEx クラス>

class SplineMoverEx extends SplineMover, ExtendedMover
{
    function SplineMoverEx(layer, elm, finalfunction)
    {
        var time = +elm.time;
        var accel = elm.accel !== void ? +elm.accel : 0;
        ExtendedMover(layer, elm);
        SplineMover(layer, _path, time, accel, finalfunction);
    }

    function finalize()
    {
        global.SplineMover.finalize();
        global.ExtendedMover.finalize();
    }

    function stopMove()
    {
        if(moving)
        {
            global.SplineMover.stopMove();
            global.ExtendedMover.stopMove();
        }
    }

    function move(tickCount)
    {
        global.SplineMover.move(...);
        global.ExtendedMover.move(...);
    }
}

LinearMoverEx クラスとほとんど同じでしょ?
ホントだ…
ExtendedMover クラス、つまり画像の拡大・縮小・回転処理をするクラスは spline 属性が true でも false でも中身は変わらないから、多重継承するようにしたんだ。
え、どーゆーコト?
もし LinearMover クラスと SplineMover クラスを別々に(多重継承せずに)拡張したら…

<多重継承せずに LinearMoverEx クラスと SplineMoverEx クラスを作る場合>

こんなふうに、LinerMoverEx クラスと SplineMoverEx クラスの両方に画像を拡大・縮小・回転する処理を書かなくちゃいけなくなるの。
しかも、どっちの処理も内容は全く同じだから、ムダが多いわけね。
確かにそーだね。
でも、ExtendedMover クラスを作って多重継承すれば…

<多重継承して LinearMoverEx クラスと SplineMoverEx クラスを作る場合>

こんなふうに、ExtendedMover クラスのメソッド、 つまり拡大・縮小・回転の処理は LinearMoverEx クラスからも使えるし SplineMoverEx クラスからも使えるから、 同じ処理をするスクリプトを2つ書かなくてもよくなって効率的なんだ。
そっか…多重継承してるのにはちゃんと意味があったんだね。
まぁもっと良いやり方はあるかもしれないけど、 とりあえず多重継承を使えばそれなりに効率的にはなるからね。
なるほどね。
さて、それじゃこれで exmove マクロ関係の話はおしまい。
長い間お疲れさま。
ホントに長かったよねぇ…
しかも難しかったし。
まぁそんなワケだから、9章の内容は余裕があったら理解してみてってことで。
りょ〜かい。
それで、次の章は何やるの?
10章はメッセージ履歴のカスタマイズをやるつもりだよ。
メッセージ履歴…って、メニューの「システム」−「メッセージ履歴の表示」をクリックしたら表示される画面のことだよね?
そ。それまでにメッセージレイヤに表示した文章が表示される画面のことね。
あれってカスタマイズとかできるの?
ん、やろうと思えば結構色々できるよ。
まぁ次の章ではそんなに色んなことはやらないと思うけどね。
なんかそれも結構むずかしそーだよね…
まぁもう10章だしね。ある程度は難しいことにも挑戦してみようってコトで。
ちなみに exmove よりはちょっとは簡単だと思うよ。
ちょっとは、ね…
まーでもメッセージ履歴のシステムってどーなってるか知らないから、ちょっと興味はあるかも。
ん、その辺もそれなりに理解できれば色々自分でカスタマイズできるようになるんじゃないかな。
だといーんだけどねー。
ってワケで、次の章もがんばってついてきてね!


前へ | TOP | 次へ