GenericFlipの機能を利用すると環境レイヤに独自の属性を追加できます。特殊な画像やエフェクトなどをtjsで描画したいときに便利です。初期状態のKAGEXでも動画を再生するGFX_Movie, フラッシュを再生するGFX_Flash, パーティクルを表示するGFX_Particleなどが用意されています。今回は自前でGenericFlipを作成してみます。
GenericFlipの実装例
今回作成するGenericFlipは、指定された画像をインターバルごとに繰り返し表示するものです。以下がそのスクリプトとその使用例です。
/**
* 指定された画像を一定時間ごとに切り替えて表示するGenericFlip
* layerタグにswitch属性とinterval属性を追加します。
* switch : 表示する画像をコンマで区切って指定します
* interval : 画像を切り替える間隔をms単位で指定します
* 例) @layer name="テスト" switch="image1,image2" interval=1000
*/
// 必ずGenericFlipクラスを継承する
class ImageSwitcherGenericFlip extends GenericFlip
{
var interval; // 画像を切り替える間隔
var files; // 切り替えて表示する画像ファイルが入った配列
var startTick; // 開始時の時間
var currentFileIndex; // 現在読み込んでいるファイルの番号
var targetLayer; // 画像を読み込むレイヤ
// コンストラクタにはKAGWindowオブジェクト(kag)が渡される
function ImageSwitcherGenericFlip(window) {
super.GenericFlip(window);
targetLayer = new Layer(window, window.primaryLayer);
}
// フリップ開始時に呼ばれる
// 第1引数には登録属性の属性値、第2引数には全ての属性が入った辞書が渡される
function flipStart(files, elm) {
// コンマで区切って配列に変換する
var files = files.split(",");
// 表示を開始する
start((int)elm.interval, files);
}
// フリップ再生中に毎フレーム呼ばれる
// 引数には現在のSystem.getTickCount()の返り値が渡される
function flipUpdate(currentTick) {
// 現在の時間から表示するファイル番号を計算する
var elapsedTick = currentTick - startTick;
var fileIndex = (elapsedTick \ interval) % files.count;
// 現在表示している画像と同じなら何もしない
if (currentFileIndex === fileIndex) { return; }
currentFileIndex = fileIndex;
// targetLayerに現在の画像を読み込み
targetLayer.loadImages(files[fileIndex]);
targetLayer.setSizeToImageSize();
// flipAssignでtargetLayerを対象のレイヤにコピー
flipAssign(targetLayer);
}
// フリップ停止時に呼ばれる
function flipStop() {
this.interval = 0;
this.files = void;
super.flipStop(); // 必ずsuper.flipStopを呼び出す
}
// セーブする際に呼ばれる
// 引数には保存用の辞書が渡される
function flipStore(dic) {
dic.interval = interval;
dic.files = files;
}
// ロードする際に呼ばれる
// 引数にはflipStoreで保存した辞書が渡される
function flipRestore(dic) {
if (dic.files === void) { return; }
// 画像の表示を再開
start(dic.interval, dic.files);
}
// 画像の表示を開始する関数
// 第1引数に画像を切り替える間隔、第2引数にファイル名が入った配列を渡す
function start(interval, files) {
this.interval = interval > 0 ? interval : 1000;
this.files = files;
this.startTick = System.getTickCount();
this.currentFileIndex = void;
}
}
// 定義したクラスをGenericFlipとして登録
GenericFlip.Entry(%[
"class" => ImageSwitcherGenericFlip, // GenericFlipクラス
"type" => "switch", // 登録属性
"options" => [ "interval" ], // 使用する属性名
]);
@linemode mode=vn
; 環境レイヤにimage01, image02, image03を1秒ごとに繰り返し表示する例
@layer name=レイヤ switch="image01,image02,image03" interval=1000
画像を表示しています。
; レイヤを消したりfile属性などで他のファイルを読み込んだりするとGenericFlipは停止します
@layer name=レイヤ hide
画像を消去しました。
実装の詳細はコメントを参照してください。GenericFlipを作る際の一般的な注意点のみ解説します。
GenericFlipとして使うクラスは必ずGenericFlipクラスを継承してください。ここではImageSwitcherGenericFlipクラスをGenericFlipとして使います(10行目)。
クラスを定義したら、GenericFlip.Entryを使って登録する必要があります(88行目)。登録内容は辞書で渡します。classには先ほど定義したクラス、typeにはこのクラスを呼び出すのに使う属性、optionsにはそれ以外に使う属性を配列で渡します。ここでは[layer]タグでswitch属性が使われたときに呼び出されるように登録しています。switch以外にinterval属性を使うのでそれも登録します。
GenericFlipクラスとして機能させるにはいくつかの関数を実装します。ここではflipStart, flipUpdate, flipStop, flipStore, flipStore, flipRestoreを実装しています。それぞれフリップ開始時、フリップ実行中、フリップ停止時、セーブ時、ロード時に呼ばれます。
switch属性が使われるとまずImageSwitcherGenericFlipクラスのオブジェクトが作成され、その後すぐにflipStartが呼び出されます。第1引数には登録属性(ここではswitch属性)の属性値、第2引数にその他の属性が入った辞書が渡されます。
その後は停止されるまでずっとflipUpdateが呼び出され続けます。現在の時間が第1引数に渡されるのでそれに合わせてレイヤに描画すればいいです。ここで重要になるのがflipAssign()です。これはGenericFlipクラスにあらかじめ用意されている関数で、引数に渡したレイヤの内容を環境レイヤにコピーしてくれます。まずは自前のレイヤに描画してからflipAssignを使ってコピーするのが定石です。ここでもtargetLayerに画像を読み込み、それをflipAssignでコピーしています。
環境レイヤが非表示になったりするとGenericFlipは自動的に停止されます。このときに呼ばれるのがflipStopです。ここでは必ずsuper.flipStop()を呼ばなければなりません。忘れないように注意してください。
flipStore, flipRestoreはセーブ・ロードに対応させるために必要です。flipStoreで現在の状態を保存してflipRestoreで実行を再開できるようにしてください。
まとめ
GenericFlipの実装手順は以下のようになります。
・GenericFlipを継承したクラスを定義する
・定義したクラスにflipStart, flipUpdate, flipStop, flipStore, flipRestoreを実装する
・定義したクラスをGenericFlip.Entryで登録する
GenericFlipはtjsを使ってレイヤに描画できます。環境レイヤに機能を追加する形なので、rotateなどの変形やcontrastなどの色調補正、その他のコマンドと組み合わせて使えます。独自のLayerを用意するよりも、可能であればGenericFlipとして描画機能を実装する方が応用がきいて便利だと思います。