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

前回exmove マクロを使ってみたから、 今回からは exmove マクロの作り方を見てくことにするね。
えっと、確か exmove マクロは難しいから、 もっとシンプルなのを見てくって言ってたよね?
ん、これがそのスクリプトだよ。
exmove_simple.ks っていうファイル?
そ。前回の exmove.ks よりはシンプルでしょ?
…確かにそーみたいだけど、コレはコレですごい長いし複雑そうだよ?
んー、できるだけシンプルにしようとは思ったんだけど、この辺が限界だったんだよね。
ちなみにこれでもかなりシンプルにしてるから、その分色んな制約がついちゃってるよ。
え、そーなの?
exmove_simple.ks の最後の方にどんな制約があるか書いてるから、一応見といてね。
はーい。
…ホントだ、なんか色々書いてあるね。
ま、そんなワケだから、実用する時には前回使った exmove.ks の方を使うようにしてね。
りょーかい。
さて、それじゃスクリプトの前に、まずは move タグを実行するとどうやってレイヤが動くのかってのを確認しとくね。
え? それ前にやったじゃない?
コンティニュアスハンドラを使ってレイヤを動かしてるんでしょ?
§9.13§9.14 参照。
まぁそうなんだけどね。
あの時は SimpleMover クラスを使ってレイヤを動かしたよね。
うん、そーだったね。
move タグでレイヤを動かす時もやり方は似てるんだけど、 move タグの場合は SimpleMover クラスの代わりに LinerMover クラスとか SplineMover クラスのオブジェクトがレイヤを動かしてるんだ。
LinearMover クラスと SplineMover クラスは system フォルダ内の DefaultMover.tjs で定義されています。
2つもクラスがあるの?
両方のクラスのオブジェクトを同時に使うんじゃなくて、レイヤの動かし方によって LinerMover クラスのオブジェクトと SplineMover クラスのオブジェクトを使い分けてるの。
どーやって使い分けてるの?
move タグに spline っていう属性があるでしょ。
spline 属性…ってゆーと、 レイヤをカーブさせたい時に true にする属性だっけ?
そうだね。デフォルトだと spline 属性は false だから、 普通に move タグを実行するとレイヤは直線的に移動するんだけど、 spline 属性を true にすると、 こんなふうに曲線的に移動するようになるよね。

move タグ実行時のレイヤの移動軌跡>

spline 属性が false の時と true の時でレイヤの位置を計算する方法が違うから、 spline 属性が false だと LinearMover クラスのオブジェクトが使われて、 true だと SplineMover クラスのオブジェクトが使われるんだ。
なるほど、そーやって使い分けてるんだ。
ちなみに LinearMover クラスと SplineMover クラスは、 レイヤの位置の計算の仕方が違ってる以外はほとんど同じだから、こっから先は LinearMover クラスの方だけを見ていくことにするね。
そーなんだ。わかった。
じゃまずこの図を見てみて。

LinearMover クラスの概念図(その1)>

なに? この図?
LinearMover クラスは大体こういうものってのを表した図だよ。
ちなみにこの図は…

[move layer=0 page=fore time=2000 path="(100,350,255)"]

こんなふうに move タグを実行した時の例ね。
あと図にも描いてある通り、レイヤの初期位置は (300,200) だよ。
これって 0 番の前景レイヤを 2000 ミリ秒(2秒)かけて (100,350) の位置に動かして、あと opacity255 にするってことだよね?
そうそう。
ただ説明を簡単にするために、元々画像の opacity255 ってことにしてるから、move タグを実行するとレイヤの位置だけが変わるよ。
そーなんだ。
で、この move タグを実行すると、KAG システムが 0 番の前景レイヤを動かすために LinearMover クラスのオブジェクトを作るの。
KAGLayer クラスの beginMove メソッド内で LinearMover/SplineMover クラスのオブジェクトが作られます。
LinearMover クラスのオブジェクトって、 あの人の形みたいなの()のこと?
ん、LinearMover クラスのオブジェクトは、 イメージ的にはレイヤを動かす人みたいな感じだからね。
ちなみにこれはあくまでイメージだから、ホントに人の形をしたものが出てきてレイヤを動かしてるわけじゃないよ。
まーそりゃそーだよねぇ。
move タグを実行してもそんなの見えないし。
LinearMover クラスのオブジェクトは目に見えないからね。
んで、KAG システムは move タグが実行されると「2000ミリ秒(2秒)かけて 0 番の前景レイヤを (100,350) の位置まで動かしてね」って LinearMover クラスのオブジェクトに頼むの。
それから…

LinearMover クラスの概念図(その2)>

LinearMover クラスのオブジェクトは KAG システムに「レイヤを動かしてる間は“できるだけ頻繁に”経過時間を教えて」って頼むの。
…ってことは、コンティニュアスハンドラを使うってことだよね?
そ。だから LinearMover クラスのオブジェクトが System.addContinuousHandler メソッドを呼び出すわけね。
で、コンティニュアスハンドラが呼び出されるごとにレイヤを動かしていくの。
addContinuousHandler メソッドについては §9.13 参照。

LinearMover クラスの概念図(その3)>


※説明の都合上、上図では KAG システムが1秒経ったことを LinearMover クラスのオブジェクトに通知しているように描いていますが、 実際には KAG システムが通知しているのは経過時間ではなく現在時刻(System.getTickCount メソッドの戻り値)です。 LinearMover クラスのオブジェクト自身がレイヤを動かし始めた時刻を記録していて、 KAG システムから通知される現在時刻からレイヤを動かし始めた時刻を引き算することで1秒経ったことを判断しています。

例えば、上の図は move タグが実行されて 1 秒後にコンティニュアスハンドラが呼び出された時の状態を表してるんだけど、 コンティニュアスハンドラが呼び出されると 1 秒経ったってことが判るから、 LinearMover クラスのオブジェクトは 1 秒後のレイヤの位置を計算して、レイヤをその位置に動かすんだ。
じゃあ (200,275) の位置が 1 秒後のレイヤの位置ってこと?
うん。1 秒後ってことは、初期位置 (300,200) と移動後の位置 (100,350) のちょうど中間の位置ってことになるからね。
※ x = 300+(100−300) × (1÷2)=200
  y = 200+(350−200)×(1÷2)=275 と計算されます。
そっか。
ところで、この図だと初期位置 (300,200) から一気に (200,275) の位置に動かしてるように見えるけど、 コンティニュアスハンドラは 1 秒の間にたくさん呼び出されるから、 実際にはレイヤはちょっとずつ動いていくってとこに注意してね。
確かにコンティニュアスハンドラって前に使った時はかなりたくさん呼び出されてたよね。
§9.13 参照。
コンティニュアスハンドラを使うとレイヤの位置を細かく更新できるから、 レイヤが滑らかに動いてるように見えるわけだね。
なるほどね。
で、2 秒経つまではコンティニュアスハンドラが呼び出され続けて、 コンティニュアスハンドラが呼び出されるたびにレイヤを動かしていくわけだけど、 2 秒経ったらレイヤを動かすのをやめなくちゃいけないよね。
そーだね。
あと、stopmove タグが実行されたり画面がクリックされたりしてもレイヤを動かすのをやめなくちゃいけないよね。
canskip=truewm タグを実行した場合
あ、そっか。それもあるね。
レイヤを動かすのをやめる時にはどうすればいいんだったか覚えてる?
えっと… System.removeContinuousHandler っていうメソッドを呼び出すんだったっけ?
removeContinuousHandler メソッドについては §9.13 参照。
そうそう。だから 2 秒経ったり stopmove タグが実行されたりすると LinearMover クラスのオブジェクトは System.removeContinuousHandler メソッドを呼び出すの。
これでレイヤの移動は止められるんだけど、あともう一つやらなくちゃいけないことがあるんだ。
どんなこと?
wm タグは知ってるよね?
レイヤが移動し終わるのを待つタグだよね。
ん、そうだね。
もう一つのやらなきゃいけないことってのは、 KAG システムに「wm タグのとこで待つのをやめて、 次のタグを実行して」って伝えることなんだ。 これやらないと、レイヤが動き終わってもずーっと wm タグのとこで待ったままになって、シナリオの実行が先に進まなくなっちゃうからね。
なるほどねぇ…
あ、でも stopmove タグでレイヤの移動を止めたら普通 wm タグは実行しないよね?
あと、もし move タグを実行した後 wm タグを実行してなかったらどーなるの?
そういう場合でも LinearMover クラスのオブジェクトは、 レイヤの移動が終わったら KAG システムに「wm タグのとこで待つのをやめて」っていうメッセージを伝えるんだけど、 wm タグを実行してなかったら KAG システム側では何もする必要ないから、そのメッセージは無視されるの。
あ、そーなんだ。
これで LinerMover クラスのオブジェクトの仕事はおしまい。
LinerMover クラスのオブジェクトがやってることをまとめるとこうなるね。

LinerMover クラスのオブジェクトがやっていること>

※最終的な位置と不透明度の最終値とは path 属性の最後の区間に指定されている位置・不透明度の値を指します。例えば、path="(100,200,128)(200,300,255)" であれば、最終的な位置は (200,300)、不透明度の最終値は 255 となります。

どう?そんなにムズカシイことはやってないでしょ?
まー確かにね。
じゃここからが本題。
今回はレイヤを動かしたり不透明度を変えたりするだけじゃなくて、 拡大・縮小・回転もできるように拡張しなくちゃいけないよね。
そだね。
じゃどーすれば拡張できると思う?
えっ…?
う〜ん、そーだね…例えば、LinearMover クラスのオブジェクトに拡大・縮小・回転もやってもらうとか?
ん、そういうやり方もあるよね。
じゃあこのやり方じゃないってコト?
いや、最初はそうしようと思ったんだけど、それだとスクリプト的にちょっとややこしくなりそうだったから、 他の方法を使うことにしたんだ。
どんな方法?
LinearMover クラスとか SplineMover クラスとは別に、 拡大・縮小・回転処理専用のクラスを新しく作るの。
拡大・縮小・回転処理専用のクラス?
そ。で、コンティニュアスハンドラが呼び出された時に、まず LinearMover クラスとか SplineMover クラスのオブジェクトにレイヤを移動してもらって、 それから拡大・縮小・回転処理専用のクラスのオブジェクトに拡大・縮小・回転処理をやってもらうの。
なんかややこしそーだね…
そーでもないよ。
例えば…

[exmove layer=0 page=fore time=2000 path="(100,350,255,200,90)"]

こんな感じに exmove マクロを実行する場合を考えてみるね。
これって 0 番の前景レイヤを 2 秒で (100,350) の位置に動かして、 あと 200% に拡大して時計回りに 90°回転させるってことだよね?
そうそう。さっきの move タグでやった移動に拡大と回転を追加してるわけね。
ホントだ。移動する位置と不透明度はさっきとおんなじだね。
で、この exmove マクロを実行する時は、 さっきみたいに図にするとこんな感じになるの。

exmove マクロ実行時の概念図(その1)>

なんか2人も増えてるみたいなんだけど…?
まず、さっき言った拡大・縮小・回転処理専用のクラスのオブジェクトは“ExtendedMover オブジェクト”って書いてあるオブジェクトだよ。
赤い人のこと?
そ。んで、“LinearMoverEx オブジェクト”って書いてある方(緑の人のことね)は、 LinearMover クラスのオブジェクト(紫の人)と ExtendedMover クラスのオブジェクト(赤い人)に指示を出す係なんだ。
指示を出すって…?
を見てもらうとわかると思うんだけど、 exmove マクロを実行すると、 まず KAG システム側から「レイヤを移動・拡大・回転して」っていう指示がくるわけね。
うん、確かにそー書いてあるね。
で、その指示はまず LinearMoverEx クラスのオブジェクト(緑の人)が受けて、 その後「レイヤを移動させて」っていう指示を LinearMover クラスのオブジェクト(紫の人)の方に出して、 「レイヤを拡大・回転して」っていう指示を ExtendedMover クラスのオブジェクト(赤い人)の方に出すの。
じゃあその LinearMoverEx っていうクラスのオブジェクト(緑の人)は指示を出すだけってコト?
そうだよ。
指示を出すためだけにわざわざクラスを作る意味なんてあるの?
ん、意味はちゃんとあるよ。
もし LinearMoverEx クラスのオブジェクト(緑の人)がなかったら…

LinearMoverEx クラスを使わない場合exmove マクロ実行時の概念図>

こんなふうに、LinearMover クラスのオブジェクト(紫の人)と ExtendedMover クラスのオブジェクト(赤い人)が別々に KAG システムから指示を受けて、別々にコンティニュアスハンドラを登録しなくちゃいけなくなるんだよね。
それって何か問題でもあるの?
どっちかってゆーとさっきのやり方の方が複雑っぽいけど?
…まぁ、別々にコンティニュアスハンドラを登録すること自体は別に問題ってワケでもないんだけどね。
なーんだ。じゃあやっぱりこっちでいいんじゃない?
いやいや、他にも理由があるから。
どんな理由なの?
exmove マクロを実行した時も move タグを実行した時と同じように stopmove タグと wm タグが使えるって言ったのは覚えてる?
うん、確か前回そう言ってたよね。
LinearMoverEx クラスのオブジェクト(緑の人)が無いと、 exmove マクロを実行した時に stopmove タグが使えなくなっちゃうんだ。
あと wm タグは canskip 属性を true にしても、クリックでレイヤの移動を止められなくなっちゃうの。
LinearMoverEx クラスのオブジェクトが無くても stopmove タグ、 wm タグを使えるように設計することはできますが、 LinearMoverEx クラスのオブジェクトを使う場合と比べてスクリプトが煩雑になります。
え、そーなの。なんで?
詳しいことは今度スクリプトの説明する時に話すつもりなんだけど、 KAG システムから指示を受けるオブジェクトが2個以上あると(この図の場合は 赤い人紫の人 ね) stopmove タグと wm タグがちゃんと使えなくなっちゃうんだ。
へぇ、そーなんだ。
これで LinearMoverEx クラスのオブジェクト(緑の人)を使う理由は納得してもらえた?
うん、まーね。
それじゃ LinearMoverEx クラスのオブジェクトを使う方の話に戻るね。
はーい。
まず、LinearMover クラスのオブジェクト(紫の人)がレイヤの移動と不透明度(opacity)の変更を担当してて、 ExtendedMover クラスのオブジェクト(赤い人)がレイヤの拡大・縮小・回転を担当してるってとこまでは OK?
うん、そこまではおっけーだよ。
だから、こうやって exmove マクロを実行した場合は、 コンティニュアスハンドラが呼び出された時に、まず LinearMover クラスのオブジェクト(紫の人)がレイヤを移動させて…

exmove マクロ実行時の概念図(その2)>

※上図は exmove マクロ実行から1秒後にコンティニュアスハンドラが呼び出された時の状態を表しています。

んで、その後 ExtendedMover クラスのオブジェクト(赤い人)がレイヤを拡大・回転するんだ。

exmove マクロ実行時の概念図(その3)>

※拡大率は 100+(200−100)×1÷2=150%、回転角は 0+(90−0)×1÷2=45°と計算されます。
 また、上図は exmove_simple.ks での動作を表しています(exmove.ks を使うと画像の拡大・回転の中心点が (200,275) の位置に来ます)

これでちゃんとレイヤが移動・拡大・回転できるわけね。
なるほどねぇ…
それじゃ最後に exmove マクロが実行された時の処理の流れをまとめとくね。

exmove マクロが実行された時の処理の流れ>

レイヤを拡大・縮小・回転するための処理が増えたってこと以外は move タグが実行された時の処理の流れとそんなに変わってないよ。
確かに結構共通してるとこはあるみたいだね。
あと、spline 属性を true にすると LinearMoverEx クラスの代わりに SplineMoverEx クラスが使われるんだけど、 やってることは基本的に LinearMoverEx クラスとほとんどおんなじだから、 今回は説明は省略するね。
りょーかい。
ホントは他にもやらなくちゃいけない事がいくつかあるんだけど、まぁそれは追々説明していくとして、 exmove マクロでやることは大体こんなとこだから、 次回からはスクリプトの方を見ていくことにするね。
は〜い。
それじゃ、また次回ね。


前へ | TOP | 次へ