KAGEX拡張例(GenericFlip)

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として描画機能を実装する方が応用がきいて便利だと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です