Section 4.13 プラグインの応用

今回は日付表示のプラグインをちょっと応用してみるね。
応用って?
日付表示プラグインのスクリプトをベースにして、所持金を表示するプラグインを作ってみるの。
あ、そう言えば§4.1でそんなこともできるって言ってたよね。
うん。所持金を表示するプラグインは日付を表示するプラグインと共通してる部分が多いから、ちょっと書き換えるだけで作れるんだ。
ふぅん、そうなんだ。
で、今回使う画像はこれ。

<所持金表示に使う画像 "money_char.png">

所持金表示に使う画像

日付表示の時と似てるね。
あ、でも日付表示の時は右端が / だったけど、この画像は \ になってるね。
『¥1000』みたいな感じで所持金を表示するからね。
そっか、だから \ を使うんだね。
じゃあ、DatePlugin クラスをベースにして、 所持金を表示する MoneyPlugin クラスを作っていくね。
は〜い。
まずはメンバ変数からね。
MoneyPlugin クラスのメンバ変数はこんな感じ。

MoneyPlugin クラスのメンバ変数>

var imgLay;  // 所持金表示に使う画像用のレイヤ
var foreLay;  // 表画面用のレイヤ
var backLay;  // 裏画面用のレイヤ
var chWidth;  // 各文字(数字、"\")の幅
var chHeight;  // 各文字の高さ
var foreVisible, backVisible;  // 表/裏画面用のレイヤが表示されているか
var foreMoney, backMoney;  // 表/裏画面用のレイヤに設定されている金額

ちなみに DatePlugin クラスのメンバ変数はこれね。

DatePlugin クラスのメンバ変数>

var imgLay;  // 日付表示に使う画像用のレイヤ
var foreLay;  // 表画面用のレイヤ
var backLay;  // 裏画面用のレイヤ
var chWidth;  // 各文字(数字、"/")の幅
var chHeight;  // 各文字の高さ
var foreVisible, backVisible;  // 表/裏画面用のレイヤが表示されているか
var foreMonth, backMonth;  // 表/裏画面用のレイヤに設定されている月
var foreDay, backDay;  // 表/裏画面用のレイヤに設定されている日

確かに DatePlugin クラスのメンバ変数と共通してるのが結構あるね。
違ってるのは… foreMoneybackMoney っていうメンバ変数だね。
ん。今回表示するのは所持金だから、foreMonthforeDayforeMoney に変わって、 backMonthbackDaybackMoney に変わってるってワケ。
日付の代わりに金額を表示するってことだね。
そうそう。それじゃ、次はコンストラクタね。
MoneyPlugin クラスのコンストラクタはこんな感じ。

MoneyPlugin クラスのコンストラクタ>

function MoneyPlugin()
{
    super.KAGPlugin();  // スーパークラスのコンストラクタを呼び出します

    // 所持金表示に使う画像用のレイヤを作ります
    imgLay = new Layer(kag, kag.fore.base);  // 表画面の背景レイヤを親レイヤにします
    imgLay.loadImages("money_char");  // 所持金表示に使う画像を読み込みます

    chWidth = imgLay.imageWidth \ 11;  // 文字の幅を代入します
    chHeight = imgLay.imageHeight;  // 文字の高さを代入します

    // 表画面用のレイヤを作ります
    foreLay = new Layer(kag, kag.fore.base);  // 表画面の背景レイヤを親レイヤにします
    foreLay.setSize(chWidth * 8, chHeight);  // 最大7桁まで表示できるようにサイズを設定します

    // 裏画面用のレイヤを作ります
    backLay = new Layer(kag, kag.back.base);  // 裏画面の背景レイヤを親レイヤにします
    backLay.setSize(foreLay.width, foreLay.height);  // 表画面のレイヤと同じサイズにします

    // はじめはデフォルトの設定にしておきます
    setOptions(%["page" => "fore""left" => 20, "top" => 20, "money" => 0, "visible" => false]);
    setOptions(%["page" => "back""left" => 20, "top" => 20, "money" => 0, "visible" => false]);
}

ちなみにこれが DatePlugin クラスのコンストラクタ。

DatePlugin クラスのコンストラクタ>

function DatePlugin()
{
    super.KAGPlugin();  // スーパークラスのコンストラクタを呼び出します

    // 日付表示に使う画像用のレイヤを作ります
    imgLay = new Layer(kag, kag.fore.base);  // 表画面の背景レイヤを親レイヤにします
    imgLay.loadImages("date_char");  // 日付表示に使う画像を読み込みます

    chWidth = imgLay.imageWidth \ 11;  // 文字の幅を代入します
    chHeight = imgLay.imageHeight;  // 文字の高さを代入します

    // 表画面用のレイヤを作ります
    foreLay = new Layer(kag, kag.fore.base);  // 表画面の背景レイヤを親レイヤにします
    foreLay.setSize(chWidth * 5, chHeight);  // 日付が表示できるようにサイズを設定します

    // 裏画面用のレイヤを作ります
    backLay = new Layer(kag, kag.back.base);  // 裏画面の背景レイヤを親レイヤにします
    backLay.setSize(foreLay.width, foreLay.height);  // 表画面のレイヤと同じサイズにします

    // はじめはデフォルトの設定にしておきます
    setOptions(%["page" => "fore""left" => 20, "top" => 20, "month" => 1, "day" => 1, "visible" => false]);
    setOptions(%["page" => "back""left" => 20, "top" => 20, "month" => 1, "day" => 1, "visible" => false]);
}

コンストラクタもよく似てるね。
どこが違ってるか解る?
imgLay に読み込む画像が違ってるよね。
うん。まぁこれは当然違ってくるよね。他には?
えっと、所持金表示に使う文字も日付表示に使う文字も11種類だし、画像も同じように作ってるから、 chWidthchHeight は同じになってるね。
ん、そうだね。
所持金を表示するレイヤも日付表示用のレイヤとほとんど同じみたいだけど、 setSize メソッドの第1引数が違ってるよね。
日付表示のときは chWidth * 5 だったけど、 所持金表示だと chWidth * 8 になってるね。
所持金表示の時は別に 8 じゃなくても適当な数でいいんだけどね。
今回は金額を最大7桁まで表示できるようにするために 8 にしてるんだ。
えっ? chWidth * 8 にしてるんだから8桁表示できるんじゃないの?
さっき所持金は『¥1000』っていうふうに表示するって言ったでしょ?
うん。
…あっ、もしかして『¥』の分があるから、表示できる桁数が1小さくなるってこと?
そ。chWidth * 8 だと全部で8文字表示できるわけだけど、 『¥』を表示するのに1文字分必要だから、表示できる金額は最大7桁になるの。
なるほどね。
あとは、setOptions メソッドの引数が違ってるね。
setOptions メソッドは引数だけじゃなくて、 中身も DatePlugin クラスとはちょっと違ってるんだ。
で、これが MoneyPlugin クラスの setOptions メソッド。

setOptions メソッド>

// 表/裏画面のレイヤの表示/非表示・位置・所持金を設定します
function setOptions(elm)
{
    var fore;  // 表画面のレイヤを設定する場合は true、裏画面の場合は false
    if(elm.page === void || elm.page == "fore")
        fore = true;  // page 属性が省略されているか "fore" が指定されていれば表画面の設定を行います
    else if(elm.page == "back")
        fore = false;  // page 属性に "back" が指定されていれば、裏画面の設定を行います
    else
        return;  // page 属性値が不正です

    // visible 属性が指定されていればレイヤの visible を設定します
    if(elm.forevisible !== void)
    {
        if(fore)
            foreVisible = foreLay.visible = +elm.visible;
        else
            backVisible = backLay.visible = +elm.visible;
    }

    // left が設定されていればレイヤの left (左端の位置)を設定します
    if(elm.left !== void)
        (fore ? foreLay.left : backLay.left) = +elm.left;

    // top が設定されていればレイヤの top (上端の位置)を設定します
    if(elm.top !== void)
        (fore ? foreLay.top : backLay.top) = +elm.top;

    // money が設定されていれば所持金を設定します
    if(elm.money !== void)
    {
        (fore ? foreMoney : backMoney) = +elm.money;
        drawMoney(fore);
    }
}

ん〜、最初の方は DatePlugin クラスの setOptions メソッド と同じみたいだけど…
最後の if ブロックだけが違ってるのかな?
そうそう。レイヤの表示状態とか位置の設定は DatePlugin クラスと全く同じ。
違うのは表示内容の設定、つまり所持金の表示を設定してる最後の if ブロックのとこだけ。
だよね。
drawMoney メソッドって DatePlugin クラスにはなかったし。
drawMoney メソッドは所持金を表示するメソッドで、 setOptions メソッドの引数 elmmoney 要素が設定されてる場合に呼び出されるんだ。
えっと、MoneyPlugin クラスには drawMoney メソッドがある代わりに drawDate メソッドは無いんだよね?
うん、MoneyPlugin クラスで日付を表示する必要はないからね。
で、これが drawMoney メソッド。

<レイヤに所持金を書き込む drawMoney メソッド>

// レイヤに所持金を書き込みます
function drawMoney(fore)
{
    var layer, money;
    if(fore)
    {
        // fore が true なら表画面のレイヤに書き込みます
        layer = foreLay;
        money = foreMoney;
    }
    else
    {
        // fore が false なら裏画面のレイヤに書き込みます
        layer = backLay;
        money = backMoney;
    }

    var num = new Array();  // 各桁の数字を格納する配列
    do{
        num.add(money % 10);
        money \= 10;
    }while(money != 0);

    // 最初に "\" を書き込みます
    drawChar(layer, 10, 0);

    // 金額を1桁ずつ書き込んでいきます
    var n = num.count;
    for(var i=1;i<=n;i++)
        drawChar(layer, num[n - i], chWidth * i);  // i 桁目の数字を書き込みます
}

なんか最後の方が drawDate メソッド より複雑そうだね。
金額の場合は日付と違って表示する文字数が一定じゃないからね。 何文字表示するかをカウントしたりしなくちゃいけないから、その分日付表示よりはちょっと複雑になっちゃうね。
まぁ、でもそんなに難しいってこともないから。
そうなの?
うん。
じゃ、まずは引数から説明するね。
はーい。
って言っても、drawMoney メソッド の引数は drawDate メソッド の引数と同じで、 fore だけだよ。
true だったら表画面のレイヤに所持金を表示して、 false だったら裏画面のレイヤに所持金を表示するってことだよね?
そう。だから変数の layerdrawDate メソッド と同じで、 書き込み先のレイヤを指してるわけね。
で、money は表画面に書き込む時は foreMoney で、 裏画面に書き込む時は backMoney になるから、表示する金額を表してるの。
その次の do〜while ブロックって何してるの?
この do〜while ブロックの中で金額の桁数とそれぞれの桁の数字を計算してるんだ。
それってどういうこと?
do〜while ブロックに入る前に num っていう配列を作ってるでしょ。
うん。
この配列の各要素に金額の各桁の数字を代入していくんだ。
例えば、金額が 123 円、つまり money123 だとすると、 money % 10 っていくつになる?
えっ? えっと… 123 % 10 だから…
12310 で割った余りで、3 だよね?
で、それが配列 numadd メソッドの引数になるから…
num[0]3 になるね。
そ。それから money \= 10; を実行すると、money はいくつになる?
money10 で割った商だから… 12 になるよね。
ん。で、この時点ではまだ money0 じゃないから、 do〜while ブロックの先頭に戻るよね。
今度は money % 102 になるから、 add メソッドを呼び出すと num[1]2 が代入されるってことだよね?
そう。それから money \= 10; を実行すると…
money1 になるね。
money はまだ 0 じゃないから、 もう一回 do〜while ブロックの先頭に戻って…
money % 101 だから、 add メソッドが呼び出されると num[2]1 になるね。
で、今度は money \= 10; を実行すると money0 になるから、 do〜while ループから抜けるわけだね。
ループから抜けた後、配列 num の中身はどうなってる?
えっと、num[0]3 で、 num[1]2num[2]1 だよね。
つまり、金額(money)の1の位、10の位、100の位になってるってワケ。
あ、ほんとだ。
この計算を図にするとこんな感じだね。

<各桁の数字の計算過程>

各桁の数字の計算過程

あとは、配列 num の中身を順番に表示していけばOK。
ま、その前にまず『¥』を表示してるんだけどね。
『¥』は所持金表示用画像の一番右にあるから drawChar メソッドの第2引数が 10 になるんだよね?
そ。日付表示の『/』の時と同じだね。
あと、『¥』は一番左側に表示するから、第3引数は 0 になるわけね。
なるほどね。
じゃあ、最後の for のところで金額を表示してるの?
そうだよ。
for のループ条件が『i1 から n (配列 num の要素数(num.count))までの間繰り返す』ってなってることに注意してね。
ってことは、表示する金額が 123 円だったら num の要素数は 3 だから、 i1 から 3 までの間繰り返すってことだよね?
そ。要するに金額の桁数だけ繰り返して、1桁ずつ表示していくってことね。
あ、そういうことなんだ。
じゃあ、表示する金額が 123 円だったら、 i1 の時は drawChar メソッドの引数はどうなる?
え〜っと、n3 だから…

i1 の時>

drawChar(layer, num[2], chWidth * 1);

こうなるよね?
うん。つまり…?
えっと、num[2] は100の位の数字で、 chWidth * 1 は左から2文字目ってことだから…
つまり、『1』を左から2文字目に書き込む…ってこと?
ん、そういうこと。
じゃ、i2 の時と 3 の時はどうなる?
えっとねぇ…

i2, 3 の時>

drawChar(layer, num[1], chWidth * 2);  // i が 2 の時
drawChar(layer, num[0], chWidth * 3);  // i が 3 の時

こうなるから、i2 の時は10の位の『2』を左から3文字目に書き込んで、 i3 の時は1の位の『3』を左から4文字目に書き込むってことだよね?
そう。だから最終的にレイヤには『¥123』って表示されるわけだね。
ほんとだ。ちゃんと所持金が表示できてるね。
これで drawMoney メソッド は解った?
うん、おっけーだよ。
んじゃ、次は onStore メソッドね。
MoneyPlugin クラスの onStore メソッドはこんな感じ。

onStore メソッド>

// セーブ可能なラベルを通過した時に呼び出されます
function onStore(f, elm)
{
    // セーブデータの中に moneyOptions という辞書配列を作ってプラグインの設定を書き込みます
    f.moneyOptions = new Dictionary();
    with(f.moneyOptions)
    {
        // 設定内容をセーブデータに書き込みます
        .foreVisible = foreVisible;  // 表画面のレイヤが表示されているか
        .backVisible = backVisible;  // 裏画面のレイヤが表示されているか
        .foreLeft = foreLay.left;  // 表画面のレイヤの左端位置
        .backLeft = backLay.left;  // 裏画面のレイヤの左端位置
        .foreTop = foreLay.top;  // 表画面のレイヤの上端位置
        .backTop = backLay.top;  // 裏画面のレイヤの上端位置
        .foreMoney = foreMoney;  // 表画面のレイヤの金額
        .backMoney = backMoney;  // 裏画面のレイヤの金額
    }
}

DatePlugin クラスの onStore メソッド と似てるね。
うん。MoneyPlugin クラスの場合も保存する内容はレイヤの状態とメンバ変数だけだからね。
DatePlugin クラスと違ってるのは、設定を保存する辞書配列の要素の名前が moneyOptions になってるってことと…
foreMoneybackMoney メンバ変数の値を保存するってこと?
そ。じゃ次は onRestore メソッドね。

onRestore メソッド>

// セーブデータを読み込む時に呼び出されます
function onRestore(f, clear, elm)
{
    if(f.moneyOptions !== void)
    {
        // セーブデータに設定が保存されている場合は読み込みます
        if(elm !== void && elm.backlay !== void && +elm.backlay)
        {
            // backlay が true の tempload の場合は裏画面のレイヤに表画面のレイヤの状態を設定します
            with(f.moneyOptions)
            {
                setOptions(%["page" => "back""left" => .foreLeft, "top" => .foreTop, "money" => .foreMoney, "visible" => .foreVisible]);
            }
        }
        else
        {
            // それ以外の場合は普通に表画面と裏画面のレイヤの状態を設定します
            with(f.moneyOptions)
            {
                setOptions(%["page" => "fore""left" => .foreLeft, "top" => .foreTop, "money" => .foreMoney, "visible" => .foreVisible]);
                setOptions(%["page" => "back""left" => .backLeft, "top" => .backTop, "money" => .backMoney, "visible" => .backVisible]);
            }
        }
    }
    else
    {
        // セーブデータに設定が保存されていない場合はデフォルトの設定にします
        if(elm === void || elm.backlay === void || !+elm.backlay)
        {
            // backlay が true の tempload 以外の場合は表画面のレイヤをデフォルトの設定にします
            setOptions(%["page" => "fore""left" => 20, "top" => 20, "money" => 0, "visible" => false]);
        }
        setOptions(%["page" => "back""left" => 20, "top"=> 20, "money" => 0, "visible" => false]);
    }
}

これも DatePlugin クラスの onRestore メソッド と似てるね〜。
まぁ、やってることは DatePlugin クラスの onRestore メソッドと同じだからね。
違ってるのは設定を保存してる辞書配列の要素名と setOptions メソッドの引数だけだよ。
所持金を表示するから setOptions メソッドの引数の辞書配列には "money" っていう要素を指定してるんだよね。
ん、そう。
じゃ次は onCopyLayer メソッドね。

onCopyLayer メソッド>

function onCopyLayer(toback)
{
    if(toback)
    {
        // 表画面の内容が裏画面にコピーされます
        backLay.assignImages(foreLay);  // backLay に foreLay の内容をコピーします(画像を共有します)
        backLay.setPos(foreLay.left, foreLay.top);  // backLay の位置を foreLay の位置に合わせます
        backLay.visible = foreLay.visible;  // backLay の表示状態を foreLay の表示状態に合わせます
        // 表画面のレイヤの設定をコピーします
        backVisible = foreVisible;
        backMoney = foreMoney;
    }
    else
    {
        // 裏画面の内容が表画面にコピーされます
        foreLay.assignImages(backLay);  // foreLay に backLay の内容をコピーします(画像を共有します)
        foreLay.setPos(backLay.left, backLay.top);  // foreLay の位置を backLay の位置に合わせます
        foreLay.visible = backLay.visible;  // foreLay の表示状態を backLay の表示状態に合わせます
        // 裏画面のレイヤの設定をコピーします
        foreVisible = backVisible;
        foreMoney = backMoney;
    }
}

これって DatePlugin クラスの onCopyLayer メソッドforeMonthforeDayforeMoney に変わってて、 backMonthbackDaybackMoney に変わってるだけ、だよね?
うん。レイヤの表示状態をコピーする部分は DatePlugin クラスの onCopyLayer メソッドと同じでいいから、メンバ変数をコピーする部分がこう変わるわけ。
そっか。
んじゃ次は onExchangeForeBack メソッド。

onExchangeForeBack メソッド>

function onExchangeForeBack()
{
    foreLay <-> backLay;  // 表画面用レイヤと裏画面用レイヤの参照を入れ替えます
    // 表画面のレイヤの設定と裏画面のレイヤの設定を入れ替えます
    foreVisible <-> backVisible;
    foreMoney <-> backMoney;
}

これも DatePlugin クラスの onExchangeForeBack メソッド のメンバ変数の部分が変わってるだけだね。
レイヤの参照とかを入れ替える部分は同じだからね。
で、後は onMessageHiddenStateChanged メソッドなんだけど、 これは DatePlugin クラスの onMessageHiddenStateChanged メソッド をそのまま使って OK。
え、そうなの?
onMessageHiddenStateChanged メソッドはレイヤの表示状態を変えてるだけで、 メンバ変数は出てこないからね。
あ、そっか。だからそのまま使えるんだ。
これで MoneyPlugin クラスは完成。
DatePlugin クラスと共通してるとこが多いから簡単に作れたでしょ。
そうだね。
共通してる所が少ないのって drawMoney メソッド くらいだもんね。
それじゃ、MoneyPlugin クラスを使って実際に所持金を表示してみよっか。
は〜い!
まずは MoneyPlugin クラスのオブジェクトを作って、 kag オブジェクトに登録してみて。
オブジェクトの名前は global.money にしてね。
addPlugin メソッドを使って登録すればいいんだよね?
ん、そう。
じゃあ…

// プラグインオブジェクトを作って kag オブジェクトに登録します
kag.addPlugin(global.money = new MoneyPlugin());

これでいいかな?
ん、これでOK。
それじゃ、次は dateopt マクロ と同じようにして moneyopt マクロを作ってみて。
setOptions メソッド を呼び出せばいいんだよね?
うん。
ってことは…

moneyopt マクロの定義>

; moneyopt マクロを定義します
[macro name=moneyopt]
[eval exp="money.setOptions(mp)"]
[endmacro]

こんな感じだよね?
ん、OK。
それじゃ、実行してみよ。
うん!
今回はとりあえず所持金が表示できるかどうかだけチェックするね。
りょーかい。
このスクリプトを first.ks に書き込んで実行してみて。
必要なファイルはここに置いとくね。

<所持金を表示する kag スクリプト(first.ks)>

; プラグインを読み込みます
[call storage="MoneyPlugin.ks"]

; 表画面に所持金を表示します
[moneyopt page=fore money=123 visible=true]

じゃあ、実行してみるね。

<実行結果>

表示されたウィンドウ

お〜、ちゃんと『¥123』って表示されてるね〜。
ん、OKだね。
あとトランジションとかセーブ・ロードも試してみてね。
うん、わかった。
これでプラグインもできたし、第4章はこんなところかな。
あ、第4章って今回で終わりなんだ?
んー、ホントは DatePlugin クラスと MoneyPlugin クラスには共通点が多いから、 スーパークラスを1つ作って、そこから継承して DatePlugin クラスと MoneyPlugin クラスを作るようにすればもっと効率的なんだけど…
だけど…?
まぁ今回は KAG プラグインの作り方を見ていくのが目的だから、 その辺はパスしてこの章はこれで終わりにしようかなと思って。
ふーん、そうなんだ。
ってワケで、第4章はこれで終わり。
次は何をするの?
第5章はメッセージウィンドウにシステムボタンをつけてみようと思うんだ。
それってセーブやロードができたり、メッセージをスキップしたりできるボタンのこと?
そうそう、それ。
KAG にはメッセージウィンドウのシステムボタン用に SystemButtonPlugin クラスっていう KAG プラグインが同梱されてるから、それをベースにしてメッセージウィンドウに色んなボタンをつけてみるの。
へ〜、今度はなんか実用的な感じだね。
まぁ、ボタンって結構色んな所で使うからね。
どうやって作るのか知ってて損はないと思うよ。
だね。
それじゃ、次の章もがんばってついてきてね!
うんっ!


前へ | TOP | 次へ