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

それじゃ今回から exmove マクロ(シンプル版)のスクリプトを見ていくね。
はーい。
…って言っても今回はスクリプトが結構複雑だから、まずレイヤ移動の流れをフローチャートで確認してみるね。

move タグ実行時の処理の流れを表すフローチャート>

※図の簡略化のため、delay 属性に 0 以外の値を指定した時に呼び出される onDelayTimer メソッドは省略しています。

これが move タグを実行した時のレイヤ移動処理の流れを表すフローチャートだよ。
なんかいっぱいメソッドが呼び出されてるね。
じゃあそれぞれどんなメソッドなのか簡単に見ていくね。
りょーかい。
move タグが実行された時にまず呼び出されるのが beginMove っていうメソッド。
beginMove メソッドは system フォルダにある KAGLayer.tjs 内で定義されています。
それってどんなメソッドなの?
前回、レイヤを動かすために LinearMover クラスとか SplineMover クラスが使われるって言ったでしょ。
うん、そーだったね。
beginMove メソッドは、その LinearMover クラスとか SplineMover クラスのオブジェクトを作るメソッドなんだ。
あ、そーなんだ。
ちなみにこのメソッドは LinearMover クラスや SplineMover クラスじゃなくって、KAGLayer クラスのメソッドだから注意してね。
KAGLayer クラス…って KAG システムで使われてるレイヤのことだったっけ?
ん、KAGLayer クラスは KAG で使われてるレイヤのベースになってるクラスだよ。
だから、背景レイヤとか前景レイヤとかメッセージレイヤとかは全部 KAGLayer クラスを継承して作られてるの。
つまり、beginMove メソッドを呼び出せば、 前景レイヤも動かせるしメッセージレイヤも動かせるわけね。
そっか、なるほどね。
んで、beginMove メソッドは LinearMover クラスとか SplineMover クラスのオブジェクトを作った後に、そのオブジェクトの startMove メソッドを呼び出すの。
さっきは beginMove メソッドで今度は startMove メソッドねぇ…
これどっちも「移動を始める」っていう意味だよね?
確かに意味的にはどっちもレイヤの移動を始めるってことなんだけど、 startMove メソッドは LinearMover クラスとか SplineMover クラスのメソッドだから、やってることは結構違ってるんだよ。
そーなの?
startMove メソッドは System.addContinuousHandler メソッドを呼び出してるんだ。
delay 属性に 0 以外の値が指定されている場合は startMove メソッド内でレイヤの移動開始を遅らせるためのタイマーオブジェクトが作成されますが、ここでは説明を割愛します。
あ、コンティニュアスハンドラだね。
※コンティニュアスハンドラについては §9.13 参照。
そ。ちなみに System.addContinuousHandler(handler); が実行されるから、LinearMover クラスとか SplineMover クラスの handler っていうメソッドがコンティニュアスハンドラとして呼び出されるようになるよ。
じゃあ handler メソッドが呼び出されるとレイヤが移動するんだね。
ん〜、確かに handler メソッドが呼び出されると、 レイヤが移動したり不透明度が変わったりするんだけど、 handler メソッドが直接レイヤを動かしてるってわけじゃないんだよね。
えっ、そーなの?
handler メソッドは経過時間を計算してるだけで、 実際にレイヤを動かしたり不透明度を設定してるのは handler メソッドの中で呼び出される move っていうメソッドなんだ。
わざわざレイヤを動かす専用のメソッドを作ってるってこと?
そうだよ。
経過時間を計算するメソッド(handler メソッド)とレイヤを動かすメソッド(move メソッド)が分かれてることで、 拡張するのがラクになるんだ。
そーなの?なんで?
んー、それはもうしばらくしたらわかると思うから、今はその話は置いとくね。
で、後はレイヤの移動が終わるまで handler メソッドと move メソッドが呼び出され続けるから、 その間はレイヤが移動したり不透明度が変化したりするわけね。
ちなみにどーなるとレイヤの移動が終わるんだった?
えっ?
えーっとね…まず time 属性に指定した時間が経ったら終わるよね。
だね。他には?
あとは、stopmove タグが実行されたり、 それから canskip 属性を true にして wm タグで待ってるときに画面がクリックされたり Enter キーとかが押されても終わるよね。
まぁ大体この図に書いてる通りだよね。
あ、今の図を見て言ったんじゃないよ?
わかってるよー。前回の内容をちゃんと覚えてたんだよね?
そーそー。
他にもレイヤの移動が終わる要因はいくつかあるけど、大抵はこの3つのどれかだね。
で、レイヤの移動が終わったら stopMove メソッドが呼び出されるんだ。
レイヤの移動が終わった後に呼び出されるのに stopMove メソッドっていう名前なの?
あー、そっか。ちょっと言い方が良くなかったかな。
えっと、stopMove メソッドは「レイヤの移動が終わった後に」呼び出されるんじゃなくて、「レイヤの移動を終わってもいい状態になったら」呼び出されるメソッドなの。
例えば、さっき handler メソッドが経過時間を計算してるって言ったでしょ。
うん。
経過時間が time 属性に指定した値以上になってたら、 レイヤの移動は終わりにしなくちゃいけないよね。
そだね。
handler メソッドは、 経過時間が time 属性に指定した値以上になってたら「レイヤの移動を終わってもいい状態になった」って判断して stopMove メソッドを呼び出すんだ。
だからレイヤの移動を止めるのは handler メソッドじゃなくて stopMove メソッドなの。
ふぅん…なるほどねぇ。
あと stopmove タグが実行されたり画面がクリックされたりしても stopMove メソッドが呼び出されてレイヤの移動が終わるようになってるんだ。
じゃあその場合もレイヤの移動を止めるのは stopMove メソッドってコト?
ん、そういうコト。
ってことは、stopMove メソッドで何をやればいいかはわかるよね?
レイヤの移動を止めるんだから、System.removeContinuousHandler メソッドを呼び出すんだよね。
そう。ただ、移動してる途中にクリックで移動が中断されたりした時のことも考えて、 System.removeContinuousHandler メソッドを呼び出す前に、 レイヤを最終的な位置に移動させて、不透明度も最終的な値に設定するの。
そっか、それも必要だね。
あともう1つやることがあったよね?
え、まだ何かあったっけ?
wm タグでレイヤの移動が終わるのを待ってた時に…
あ、そーだった。
確か KAG システムに wm タグで待つのをやめてシナリオの実行を再開してって伝えるんだったよね。
ん、そこまでやったら LinearMover クラスと SplineMover クラスの仕事はおしまいなわけね。
大体の流れは解った?
まーね。
んじゃ次は ExtendedMover クラスの流れを見てくね。
ExtendedMover クラスってレイヤを拡大・縮小・回転するクラスだったよね?
そだよ。フローチャートで表すとこんな感じ。

exmove マクロ(シンプル版)を実行した時の ExtendedMover クラスの処理の流れを表すフローチャート>

なんかさっきのフローチャートと似てるね。
似てるってゆーか、ほとんど同じだね。
違ってるのはレイヤを移動させるんじゃなくて、レイヤの拡大・縮小・回転をやるってことぐらいだね。
そーなんだ。
あ、あと startMove メソッドと handler メソッドのとこだけ色が暗くなってるけど、これどーゆー意味?
あー、それは ExtendedMover クラスを作る時に、 その2つのメソッドは作らなくていいよって意味だよ。
えっ、じゃあ startMove メソッドと handler メソッドはいらないの?
ううん、どっちとも必要だよ。
でも作らなくてもいいの。
え、どーゆーコト??
えっとね、前回は説明の都合上 LinearMover クラスと ExtendedMover クラスと LinearMoverEx クラスは、 それぞれ別々のクラスになってるように図とかを描いてたんだけど、 実際には LinearMover クラスと ExtendedMover クラスを継承して LinearMoverEx クラスを作ってるんだ。
つまり多重継承してるってことだね。
多重継承…?
さすがにもう忘れてるかなー。
§2.8§2.9 でしかやってないからねー。
あ〜、第2章のその辺って確かムズカシイ話が続いてたとこだよね…
確かに第2章で多重継承とかやるのはちょっとレベルが高かったかもね。
じゃあ、多重継承のおさらいも兼ねてカンタンにこのフローチャートの流れを見ていこっか。
そーだね。正直言うと多重継承ってほとんど覚えてないし…
じゃまずこのスクリプトを見てみて。

<多重継承のスクリプト>

// LinearMover クラス(スーパークラス1)
class LinearMover
{
    function LinearMover()
    {
        // 初期化処理
    }

    function finalize()
    {
        // 終了処理
    }

    function startMove()
    {
        System.addContinuousHandler(handler); // レイヤの移動を開始します
    }

    function handler()
    {
        // コンティニュアスハンドラ
        move();
    }

    function move()
    {
        // レイヤを移動したり不透明度を変更したりする処理
    }

    function stopMove()
    {
        System.removeContinuousHandler(handler); // レイヤの移動を止めます
        // 以下レイヤを最終的な位置に移動して不透明度を最終値に設定する処理
    }
}

// ExtendedMover クラス(スーパークラス2)
class ExtendedMover
{
    function ExtendedMover()
    {
        // 初期化処理
    }

    function finalize()
    {
        // 終了処理
    }

    function move()
    {
        // レイヤを拡大・縮小・回転する処理
    }

    function stopMove()
    {
        // レイヤの拡大率・回転角を最終値に設定する処理
    }
}

// LinearMoverEx クラス(サブクラス)
class LinearMoverEx extends LinearMover, ExtendedMover
{
    function LinearMoverEx()
    {
        // 各スーパークラスのコンストラクタを呼び出します
        LinearMover();
        ExtendedMover();
    }

    function finalize()
    {
        // 各スーパークラスのデストラクタを呼び出します
        // どちらも finalize という名前なので global.〜 をつけないといけないことに注意!
        global.LinearMover.finalize();
        global.ExtendedMover.finalize();
    }

    function move()
    {
        // 各スーパークラスの move メソッドを呼び出します
        // どちらも move という名前なのでこちらも global.〜 をつける必要あり
        global.LinearMover.move();
        global.ExtendedMover.move();
    }

    function stopMove()
    {
        // 各スーパークラスの stopMove メソッドを呼び出します
        // 同じく global.〜 が必要なことに注意
        global.LinearMover.stopMove();
        global.ExtendedMover.stopMove();
    }
}

カンタンにとか言うわりには長いよねぇ…
まぁ多重継承しようと思ったらクラスが最低3つ要るから、 ある程度長くなるのはしょうがないよ。
その代わりメソッドの中ではほとんど何もしてないからそんなに難しくはないでしょ?
まーそれはそーだけどね。
それに実際の ExtendedMover クラスとかは、 これよりメソッドの数が多くてメソッドの中身も複雑なんだから、 これで難しいって言ってたら後がタイヘンだよ?
…やっぱり今回は理解するの無理そーかも…
まぁとりあえずはそんな深く考えなくても大丈夫だよ。
で、このスクリプトLinearMover クラスと ExtendedMover クラスを継承して LinearMoverEx クラスを作るスクリプトをすごーく簡単化したものね。
えっと、ここ“extends LinearMover, ExtendedMover”ってゆーのが LinearMover クラスと ExtendedMover クラスを継承するって意味なんだよね?
そうそう。そこは覚えてたんだね。
継承する時は extends って書くからそうじゃないかなーって。
ん、extends の後にクラス名が1つだけ書いてあったら普通の継承で、 2つ以上クラス名が書いてあったら多重継承ってことだね。
そっか。
じゃここからはフローチャートと対応させながらスクリプトを見ていくね。
はーい。
まず最初に beginMove メソッドを呼び出して LinearMoverEx クラスのオブジェクトを作るわけだけど、 これは大体こんなことをやってるわけね。
exmove マクロの spline 属性を true にすると LinearMoverEx クラスの代わりに SplineMoverEx クラスのオブジェクトが作成されますが、 処理の内容は LinearMoverEx クラスと殆ど同じなので、以後は LinearMoverEx クラスについてのみ説明します。

LinearMoverEx クラスのオブジェクト作成>

var moveObject = new LinearMoverEx();

これは LinearMoverEx クラスのオブジェクトを作ってるだけだから問題ないよね?
うん。
で、LinearMoverEx クラスのオブジェクトを作ると、 まずコンストラクタが呼び出されるよね。
そーだね。
じゃ LinearMoverEx クラスのコンストラクタを見てみるね。
これってそれぞれのスーパークラス(LinearMover クラスExtendedMover クラス)のコンストラクタを呼び出してるんだよね?
そうだよ。
だから、beginMove メソッドが呼び出されると、 こんなふうに LinearMoverEx クラスと LinearMover クラス、ExtendedMover クラスのコンストラクタが呼び出されるわけね。

beginMove メソッド呼び出し時の各クラスのコンストラクタ呼び出し>

それじゃついでに LinearMoverEx クラスのデストラクタも見とこっか。
普通の継承の時は “super.finalize();” って書いてたと思うけど、 こっちは “global.LinearMover.finalize();” とか書いてあるね。
コンストラクタの名前はクラスの名前と同じだから、スーパークラスが2つ以上あっても見分けがつくんだけど、デストラクタは finalize っていう名前に決まってるから、 2つ以上スーパークラスがあると、“finalize();”だけじゃどのスーパークラスのデストラクタを呼び出せばいいのかわからなくなっちゃうよね。
そっか、だから LinearMover クラスのデストラクタを呼び出したい時は“global.LinearMover.finalize();” って書いて、 ExtendedMover クラスのデストラクタを呼び出したい時は “global.ExtendedMover.finalize();” って書けばいいんだね。
そういうこと。
ちなみに global を書かずに “LinearMover.finalize();” とか書くとエラーになっちゃうから注意してね。
どーしてエラーになっちゃうんだったっけ?
ちょっとわかりにくいんだけどね、 LinearMoverEx クラスのメソッドの中で単に“LinearMover”って書くと 「LinearMover クラスのコンストラクタ」って意味になって、 “global.LinearMover”って書くと「LinearMover クラスそのもの」って意味になるんだ。
それってどー違うの?
ん〜、そーだね…
じゃあ“global.LinearMover.LinearMover();”って書くとどーいう意味になるかわかる?
えっ? そんな書き方できるの?
できるよ。
さっきも言った通り、“global.LinearMover”LinearMover クラスそのものを表すから、 “global.LinearMover.LinearMover();”ってのは「LinearMover クラスの LinearMover っていうメソッドを呼び出す」ってことになるワケ。
LinearMover クラスの LinearMover メソッドって…コンストラクタのコト?
ん、そうだよ。
つまり、LinearMoverEx クラスのメソッドの中だと“LinearMover();”“global.LinearMover.LinearMover();”はどっちもコンストラクタを呼び出すことになるわけだね。
へぇ、そーなんだ。
だから、デストラクタの中で“LinearMover.finalize();”って書くと、 “global.LinearMover.LinearMover.finalize();”ってことになっちゃうの。これじゃおかしいでしょ?
そーだね。
コンストラクタ(global.LinearMover.LinearMover)の後ろにさらにデストラクタ(finalize)がついてるってことになっちゃうもんね。
ってワケだから、LinearMoverEx クラス(サブクラス)のデストラクタの中で LinearMover クラス(スーパークラス)のデストラクタを呼び出す時は“global.LinearMover.finalize();”って書かなくちゃいけないんだ。
“global.ExtendedMover.finalize();” の方も同じ理由で global がついてるわけね。
なるほどね…なんかややこしーけど。
まぁちゃんとした理由を考えるとややこしく感じるけど、 とりあえず「多重継承してたら、スーパークラスのデストラクタを呼び出す時は“global.クラス名.finalize();”って書く」ってことを覚えてれば OK だよ。
りょ〜かい。
じゃフローチャートの話に戻るね。
beginMove メソッドが呼び出されると LinearMoverEx クラスのオブジェクトが作られるわけだけど、 それだけじゃなくって、オブジェクトが作られた後に、こんなふうに startMove メソッドが呼び出されてるんだ。

beginMove メソッド内での startMove メソッドの呼び出し>

moveObject.startMove();

なるほど、それでレイヤが動き始めるんだね。
…ん? でも LinearMoverEx クラスstartMove メソッドって無いんだけど?
LinearMoverEx クラスには無いけど、スーパークラスにはあるでしょ?
スーパークラス…
あ、確かに LinearMover クラスには startMove メソッドがあるね。
本来は LinearMoverEx クラスの startMove メソッドが呼び出されるべきなんだけど、 LinearMoverEx クラスには startMove メソッドが無いから、 そういう場合はこんなふうにスーパークラス(LinearMover クラス)の startMove メソッドが呼び出されるようになってるの。

startMove メソッド呼び出し時の処理の流れ>

へぇ、そーなんだ…
んで、LinearMover クラスの startMove メソッド“System.addContinuousHandler(handler);”が実行されるから、 この後は handler メソッド(コンティニュアスハンドラ)ができるだけ頻繁に呼び出されるようになるわけね。
handler メソッドも LinearMover クラスにしかないんだね。
ん、handler メソッドは(今回は説明を簡単にするためにメソッドの中身を省略してるけど、実際には)経過時間を計算するメソッドだから、別にオーバーライドする必要ないんだ。
そーなんだ。
じゃここで一つ問題ね。
えっ、な、何?
handler メソッドの中で move メソッドを呼び出してるよね。
うん、呼び出してるね。
で、move メソッドは LinearMoverEx クラスにもあるし、 LinearMover クラスにも ExtendedMover クラスにもあるよね。
確かに全部のクラスにあるみたいだね。
じゃあ、ここmove メソッドを呼び出すと、 どのクラスの move メソッドが呼び出されると思う?
えっ? えーっと…ここって LinearMover クラスの handler メソッドの中なんだから、 LinearMover クラスの move メソッドが呼び出されるんじゃないの?
確かにそんな気がするんだけど、実はそーじゃないんだよね。
え、違うの?
サブクラスの中でスーパークラスにもサブクラスにもあるメソッドを呼び出すと、 スーパークラスのメソッドが呼び出されるようになってるんだ。
ってことは…LinearMoverEx クラスの move メソッドが呼び出されるってコト?
そういうこと。
ちなみに多重継承してる時だけじゃなくて、普通の継承をしてる時もそうなるよ。
そーなんだ…なんか難しいね。
まぁね。
…ってワケだから、handler メソッドの中で move メソッドが呼び出されると、 LinearMoverEx クラスの move メソッドが呼び出されるのね。
じゃ今度は LinearMoverEx クラスの move メソッドを見てみて。
なんかデストラクタの時とおんなじような書き方になってるね。
じゃあ LinearMoverEx クラスの move メソッドが呼び出されたらどうなるか大体わかるんじゃない?
ん〜…最初に LinearMover クラスの move メソッドが呼び出されて、 その後 ExtendedMover クラスの move メソッドが呼び出されるのかなぁ?
ん、そのとーり。
つまり、コンティニュアスハンドラ(handler メソッド)が呼び出されると、 こんなふうにそれぞれのクラスの move メソッドが呼び出されるわけだね。

<コンティニュアスハンドラ呼び出し時の処理の流れ>

うわ、なんか矢印がややこし…
カンタンに言うと、コンティニュアスハンドラが呼び出されたら、 LinearMoverEx クラスが LinearMover クラスと ExtendedMover クラスに指示を出して(つまりそれぞれのクラスの move メソッドを呼び出して)レイヤを移動したり拡大・縮小・回転させてるってことだね。
なるほどねぇ。
ここまで見てきてわかったと思うんだけど、 startMove メソッドと handler メソッドが必要なのは、元から KAG システムに組み込まれてる LinearMover クラスだけで、 ExtendedMover クラスとか LinearMoverEx クラスには、この2つのメソッドは作らなくてもいいの。
あ、だからさっきのフローチャートを見たときに startMove メソッドと handler メソッドは作らなくていいって言ってたんだね。
そ。あとその前に言った「handler メソッドと move メソッドが分かれてた方がラク」ってのもこれが理由なわけね。
そっか、move メソッドは作らなくちゃいけないけど handler メソッドの方は作らなくてもいいんだもんね。
そーゆーこと。
じゃ最後は stopMove メソッドを見てくね。
これは普通に LinearMoverEx クラスの stopMove メソッドが呼び出されるわけだけど、 呼び出された後どうなるかはわかる?
これもデストラクタとか move メソッドと似てるよねぇ。
ってことは?
ってことは…LinearMover クラスの stopMove メソッドが呼び出されてから ExtendedMover クラスの stopMove メソッドが呼び出されるってことだよね?
ん、そう。つまりこんな感じになるわけだね。

<レイヤの移動・拡大等の終了時の処理の流れ>

さて、これで exmove マクロの処理の流れと多重継承の関係を一通り見てきたわけだけど、大体わかったかな?
ん〜…何となく、ってくらいかな。
そっか。まぁ大体の感じがつかめてれば OK だと思うよ。
それじゃ今回はこれくらいにして、 次回はそれぞれのメソッドの中身を詳しく見ていくことにするね。
は〜い。
それじゃ、また次回ね。


前へ | TOP | 次へ