KAGEX拡張例(kag.addTagの仕組み)

前回紹介したkag.addTagの動作をもう少し詳しく説明します。

function playBgm() {
    // @bgm play=bgm01 というタグを登録
    kag.addTag("bgm", %[ play:"bgm01" ]);

    System.inform("System.informが実行されました");
}
@linemode mode=vn

@eval exp="playBgm()"
bgmを再生開始しました。

kag.addTagは「コンダクタに次のタグを登録する」ための関数です。この例では、”System.informが実行されました”と表示された後にbgmが再生されます。addTagで登録されたタグが実行されるのは、playBgm()の実行が終わって[eval]タグの次のタグを実行するタイミングです。

コンダクタの動作については簡単なコンダクタの話を参照してください。この記事で言われている「; 次のタグを探す」の部分では、まずkag.addTagなどで登録されたタグがないか探します。登録されたタグが無ければksスクリプト上で次のタグに進みます。このような仕組みのため、上の例では[eval]タグの実行が終わって次のタグを探し実行されるタイミングにbgmが再生されます。

コンダクタの動作ついてもっと詳しい説明は次回の記事に続きます。

KAGEX拡張例(kag.addTag)

前回はdoCommand()を使ってワールド拡張のタグを呼び出す方法を紹介しましたが、もっといい方法を教えてもらったので紹介します。

kag.addTag()という関数を使うとコンダクタに次のタグを直接登録できます。まずは実際の使用例です。

function showStage() {
    // @stage stage=道路 stime=昼 fade=1500 sync というタグを次のタグとして登録
    kag.addTag("stage", %[ stage:"道路", stime:"昼", fade:"1500", sync:"true" ]);
}

function showStage2() {
    // @道路 夜 fade=1500 nosync というタグを次のタグとして登録
    kag.addTag("道路", %[ 夜:"true", fade:"1500", nosync:"true" ]);
}

function flashStage() {
    // @stage hide fade=1000 sync というタグを次のタグとして登録
    kag.addTag("stage", %[ hide:"true", fade:"1000", sync:"true"]);

    // @stage show fade=1000 sync というタグを次のタグとして登録
    kag.addTag("stage", %[ show:"true", fade:"1000", sync:"true"]);
}
@linemode mode=vn

@eval exp="showStage()"
道路(昼)の背景を表示しました。

@eval exp="showStage2()"
道路(夜)の背景を表示しました。

@eval exp="flashStage()"
背景を点滅しました。

Override.tjsで定義した関数(showStage, showStage2)を[eval]タグで呼び出しています。関数の定義は[iscript][endscript]を使っても問題ありません。

kag.addTagには第1引数としてタグ名、第2引数として属性が入った辞書配列を渡します。

辞書配列の値はすべて文字列になるので注意してください。つまり、 show:true ではなく show:”true” です。大抵の場合問題になりませんが、稀に文字列でないと駄目な事もあるので必ず文字列にしておくといいです。

showStage2()のように省略記法も使えます。ksスクリプトで属性値を省略したときはtrueになるので、タグで省略されている部分は辞書配列上で”true”を渡しています。

flashStage()のように2つ以上続けて登録もできます。先に登録されたものから順に実行されます。

解説が長くなってしまうので、kag.addTagのもう少し詳しい解説は次回の記事に続きます。

KAGEX拡張例(自動検索パスの追加)

KAGではカスタマイズ用にOverride.tjsとAfterinit.tjsが用意されています。

KAGEXではこれに加えてStorages.tjsがあります。これは独自の検索パスを追加するためのスクリプトです。初期状態では存在しないので作成してください。

以下の例ではseフォルダとscenario/openingフォルダを検索パスに追加しています。

// Storages.tjs
Storages.addAutoPath("se/"); // seフォルダを追加
Storages.addAutoPath("scenario/opening/"); // scenario/openingフォルダを追加

KAGEXの初期状態で使えるフォルダ名はbgimage, bgm, evimage, face, fgimage, image, init, main, others, rule, scenario, sound, sysscn, system, thum, uipsd, video, voiceになります。それ以外のフォルダを使ったり、フォルダの中にフォルダを作りたいときはStorages.tjsで追加します。

KAGEX拡張例(onSoundPropertyChanged)

・前回まで
KAGEX拡張例(音量設定)
KAGEX拡張例(ミュート設定)
KAGEX拡張例(システム効果音)

BGMの音量、またはミュートの状態が変更された際は、onSoundPropertyChangedというフックが呼ばれます。kag.addHookで呼び出す関数を追加できます。大体の動作は以下を見てください。

// 音量などが変更された際に呼ばれる関数を登録
kag.addHook("onSoundPropertyChanged", function(tag, prop, value) {
    switch (tag) {
    case "bgm":
        if (prop === "enable") {
            // BGMのミュートが変更された(value => true or false)
        } else if (prop === "globalVolume") {
            // BGMの音量が変更された(value => 0~100000)
        }
        break;
    case "se":
        if (prop === "enable") {
            // 効果音のミュートが変更された(value => true or false)
        } else if (prop === "globalVolume") {
            // 効果音の音量が変更された(value => 0~100000)
        }
        break;
    case "sysse":
        if (prop === "enable") {
            // システム効果音のミュートが変更された(value => true or false)
        } else if (prop === "globalVolume") {
            // システム効果音の音量が変更された(value => 0~100000)
        }
        break;
    case "movie":
        if (prop === "enable") {
            // 動画のミュートが変更された(value => true or false)
        } else if (prop === "globalVolume") {
            // 動画の音量が変更された(value => 0~100000)
        }
        break;
    case "voice":
        if (prop === "enable") {
            // キャラ共通のミュートが変更された(value => true or false)
        } else if (prop === "globalVolume") {
            // キャラ共通の音量が変更された(value => 0~100000)
        } else if (prop === "しおり") {
            // キャラごとの音量(しおり)が変更された(value => 0~100000)
        }
        break;
    case "bgv":
        if (prop === "enable") {
            // BGV(bvoice)のミュートが変更された(value => true or false)
        } else if (prop === "globalVolume") {
            // BGV(bvoice)の音量が変更された(value => 0~100000)
        }
        break;
    case "bgv2":
        if (prop === "enable") {
            // BGV(hvoice)のミュートが変更された(value => true or false)
        } else if (prop === "globalVolume") {
            // BGV(hvoice)の音量が変更された(value => 0~100000)
        }
        break;
    case "voiceon":
        if (prop === "しおり") {
            // キャラごとのミュート(しおり)が変更された(value => true or false)
        }
        break;
    }
});

tagには”bgm”, “se”など何の値が変更されたかが渡されます。

propが”enable”ならミュートの状態、”globalVolume”なら音量が変更されたと言うことです。prop==”enable”ならvalueは通常の状態ならtrue, ミュートされた状態ならfalseになります。prop==”globalVolume”ならvalueは変更後の音量ですが、0~100000の数値になるので注意してください。value/1000のように1000で割れば0~100に変換できます。

tag==”voice”の時は少し特殊です。propが”enable”,”globalVolume”の他にキャラ名になることがあります。このときはそのキャラの音量が変更されたということです。

キャラごとのミュートはtag==”voiceon”で渡されます。propがキャラ名になります。

全体の音量(wavevolume)やミュート(waveenable)が変更されたときはonSoundPropertyChangedが呼ばれないようになっています。それも必要なときは少し改造する必要があります。
MainWindow.tjsでwavevolumeとwaveenableが定義されている部分を書き換えます。setterの最後にcallHook(~)の行を追加しただけです。これでtag==”wave”でprop==”enable”またはprop==”globalVolume”として変更が通知されるようになります。

/**
 * グローバル WaveSound 音量の設定
 * 100 段階設定
 */
property wavevolume {
    getter()  {
        return scflags.waveVolume !== void ? +scflags.waveVolume : global.WaveSoundBuffer.globalVolume / 1000;
    }
    setter(v) {
        v = +v;
        if      (v < 0)   v = 0;
        else if (v > 100) v = 100;
        scflags.waveVolume = v;
        global.WaveSoundBuffer.globalVolume = scflags.waveEnable ? v * 1000 : 0;
        callHook("onSoundPropertyChanged", "wave", "globalVolume", v * 1000);
    }
}

/**
 * グローバル WaveSound の有効値の設定
 * true / false
 */
property waveenable {
    getter() {
        return scflags.waveEnable !== void ? +scflags.waveEnable : true;
    }
    setter(v) {
        scflags.waveEnable = +v;
        wavevolume = scflags.waveVolume;
        callHook("onSoundPropertyChanged", "wave", "enable", !!v);
    }
}

KAGEX拡張例(システム効果音)

・前回まで
KAGEX拡張例(音量設定)
KAGEX拡張例(ミュート設定)

kag.sameSysSEVolume=falseの状態ではゲーム中の効果音とシステム効果音の音量を別々に設定できます。Config.tjsの効果音バッファの数を設定している部分で設定するのが良いと思います。

// ◆ 利用可能な効果音バッファの数
// 利用可能な効果音バッファの最大値を指定します。つまり、ここで指定した数の
// 分だけ効果音を同時に再生できます。効果音を使用しない場合は 0 を指定して
// かまいません。
;numSEBuffers = 3;
;numSysSEBuffers = 2;
;sameSysSEVolume = false;

numSysSEBuffersとsameSysSEVolumeの設定を追加しました。numSysSEBuffersはシステム効果音のバッファの数です。sameSysSEVolume = falseで音量を別にしています。

デフォルトのsameSysSEVolume = trueの状態でも、音量が共通になるだけでシステム効果音が使えないわけではありません。

システム効果音のバッファは通常の効果音の後ろに追加される形になります。今回の例だとバッファ番号0~2が通常の効果音バッファ、バッファ番号3~4がシステム効果音のバッファとなります。

バッファ番号を指定する際にシステム効果音の番号を指定すればシステム効果音として再生されます。

@linemode mode=none
@nowait
@link clickse=seテスト clicksebuf=4
テスト
@endlink
@endnowait
@s

4番のバッファなのでクリックするたびにシステム効果音として再生されます。

また、システム効果音はワールド拡張では効果音として使用されません。例えば[seテスト]とするとseテスト.oggが適当な空いているバッファで再生されますが、システム効果音のバッファが使われることはありません。[seテスト buf=4]のように直接指定しても使えません。システム効果音を再生したいときはtjsを使ってください。

; 4番のバッファでseテスト.oggを再生
@eval exp="kag.se[4].play(%[ storage:'seテスト' ])"

KAGEX拡張例(ミュート設定)

・前回まで
KAGEX拡張例(音量設定)

KAGEXでは0~100の音量に加えて、オン/オフの設定もあります。

kag.waveenable ゲーム全体のミュート
kag.bgmenable BGMミュート
kag.seenable 効果音ミュート
kag.sysseenable システム効果音ミュート
kag.sameSysSEVolume=falseの時のみ
kag.movieAudioEnable ムービーミュート
kag.independentMovieAudioProperty=trueの時のみ
kag.voiceenable キャラ共通のボイスミュート
kag.bgvenable キャラ共通のBGV(bvoice)ミュート
kag.bgv2enable キャラ共通のBGV(hvoice)ミュート
kag.setVoiceOn(名前, 設定) キャラごとのミュートを設定する関数
kag.getVoiceOn(名前) キャラごとのミュートを得る関数

・全てtrueまたはfalseを設定します。デフォルトではtrueです。falseにすると対象の音がミュートされます。

以下は前回のスライダの例にミュート用のチェックボックスを追加した例です。

; スライダとチェックボックスで音量を設定する使用例
@iscript
// しおりのキャラ音量のプロパティ
property voiceVolumeShiori {
  setter(value) { kag.setVoiceVolume("しおり", value); }
  getter() { return kag.getVoiceVolume("しおり", true); }
}
// しおりのキャラミュートのプロパティ
property voiceEnableShiori {
	setter(value) { kag.setVoiceOn("しおり", value); }
	getter() { return kag.getVoiceOn("しおり"); }
}
@endscript

@linemode mode=none
@backlay
@nowait

; 操作対象を message1/back に設定
@current layer=message1 page=back

; メッセージレイヤの大きさを調整
@position left=0 top=0 width=800 height=600 visible


; BGM音量スライダを追加
@locate x=0 y=0
BGM
@locate x=120 y=0
@slider width=200 height=30 min=0 max=100 value=kag.bgmvolume jumpmode
@locate x=330 y=0
@checkbox onchange=kag.bgmenable name=kag.bgmenable

; 効果音音量スライダを追加
@locate x=0 y=80
効果音
@locate x=120 y=80
@slider width=200 height=30 min=0 max=100 value=kag.sevolume jumpmode
@locate x=330 y=80
@checkbox onchange=kag.seenable name=kag.seenable

; ボイス音量スライダを追加
@locate x=0 y=160
ボイス
@locate x=120 y=160
@slider width=200 height=30 min=0 max=100 value=kag.voicevolume jumpmode
@locate x=330 y=160
@checkbox onchange=kag.voiceenable name=kag.voiceenable

; キャラ音量(しおり)スライダを追加
@locate x=0 y=240
しおり
@locate x=120 y=240
@slider width=200 height=30 min=0 max=100 value=voiceVolumeShiori jumpmode
@locate x=330 y=240
@checkbox onchange=voiceEnableShiori name=voiceEnableShiori

; 操作対象を戻す
@current layer=message0 page=fore

@endnowait

; トランジションで表示
@trans method=crossfade time=1000
@wt
@s

KAGEX拡張例(音量設定)

KAGEXのサウンドはBGM、ゲーム効果音、システム効果音、ボイス、BGVの5種類に大別できます。
その音量はプロパティまたは関数で設定できます。

kag.wavevolume ゲーム全体のマスター音量
kag.bgmvolume BGM音量
kag.sevolume 効果音音量
kag.syssevolume システム効果音音量
kag.sameSysSEVolume=falseの時のみ
kag.movieAudioVolume ムービー音量
kag.independentMovieAudioProperty=trueの時のみ
kag.voicevolume キャラ共通のボイス音量
kag.bgvvolume キャラ共通のBGV(bvoice)音量
kag.bgv2volume キャラ共通のBGV(hvoice)音量
kag.setVoiceVolume(名前, 音量) キャラごとの音量を設定する関数
kag.getVoiceVolume(名前, true) キャラごとの音量を得る関数

・音量はすべて0~100の数値になります。デフォルトでは100です。

・システム効果音はkag.sameSysSEVolumeがtrueの時のみ使えます。デフォルトではfalseです。今回は解説しません。

・動画の音量はデフォルトではBGMの音量と同じになります。kag.independentMovieAudioPropertyをtrueにすると動画の音量を別に設定できるようになります。

BGVには実はbvoiceとhvoiceの2種類があります。hvoiceの使い方はbvoiceと全く同じで、属性名がbvoiceからhvoiceになるだけです。音量調整がbgvvolumeとbgv2volumeで別々にできます。実際に使うことは滅多にありません。

・キャラごとの音量はボイス、BGVの両方に影響します。kag.voicevolumeは全キャラのボイスのみ、kag.bgvvolumeは全キャラのbvoiceのみに影響します。

以下は実際に使ってみた例です。使った見た以上の意味はありません。

; 音量設定の簡単な使用例
@linemode mode=vn

; 現在のマスター音量を表示
現在の音量は[emb exp="kag.wavevolume"]%です。

; ゲーム全体の音量を100に設定
@eval exp="kag.wavevolume = 100"

; BGMの音量を80に設定
@eval exp="kag.bgmvolume = 80"

; ボイス全体音量を20に設定
@eval exp="kag.voicevolume = 20"

; キャラ音量を50に設定
@eval exp="kag.setVoiceVolume('しおり', 50)"

; キャラ音量を表示
現在のしおりの音量は[emb exp="kag.getVoiceVolume('しおり', true)"]%です

以下は音量を調整するスライダを配置する例です。こちらはよく使うかもしれません。

; スライダで音量を設定する使用例
@iscript
// しおりのキャラ音量のプロパティ
property voiceVolumeShiori {
	setter(value) { kag.setVoiceVolume("しおり", value); }
	getter() { return kag.getVoiceVolume("しおり", true); }
}
@endscript

@linemode mode=none
@backlay
@nowait

; 操作対象を message1/back に設定
@current layer=message1 page=back

; メッセージレイヤの大きさを調整
@position left=0 top=0 width=800 height=600 visible


; BGM音量スライダを追加
@locate x=0 y=0
BGM
@locate x=120 y=0
@slider width=200 height=30 min=0 max=100 value=kag.bgmvolume jumpmode

; 効果音音量スライダを追加
@locate x=0 y=80
効果音
@locate x=120 y=80
@slider width=200 height=30 min=0 max=100 value=kag.sevolume jumpmode

; ボイス音量スライダを追加
@locate x=0 y=160
ボイス
@locate x=120 y=160
@slider width=200 height=30 min=0 max=100 value=kag.voicevolume jumpmode

; キャラ音量(しおり)スライダを追加
@locate x=0 y=240
しおり
@locate x=120 y=240
@slider width=200 height=30 min=0 max=100 value=voiceVolumeShiori jumpmode

; 操作対象を戻す
@current layer=message0 page=fore

@endnowait

; トランジションで表示
@trans method=crossfade time=1000
@wt
@s

KAGEX講座(35) – 動画再生(movie)

環境レイヤのmovieコマンドに動画ファイルを指定すると動画再生できます。fileで画像を読み込んだり、deleteでレイヤを削除したりすれば止まります。

@linemode mode=vn

@layer name=動画 movie=テスト.wmv
動画を再生しています。

@動画 delete
停止しました。

再生中の動画はwvタグで待てます。ただしlayer=allにしてください。

@linemode mode=vn

クリックすると動画を再生します。 クリックで再生を飛ばせます。

@layer name=動画 movie=テスト.wmv
@wv layer=all canskip=true

@動画 delete
動画を再生しました。

オープニング動画を再生するスクリプトは例えば次のようになります。

@linemode mode=vn

オープニング動画を再生します。

; スキップとオートモードを停止
@cancelskip
@cancelautomode

; BGM、効果音、ボイスを停止
@bgm stop=3000
@allse stop=3000
@allchar vcond=all stopvoice

; すべての画像を消去して暗転
@begintrans
@allimage hide
@msgoff
@endtrans fade=3000

; トランジションが飛ばされた時のために強制的に停止
@bgm stop
@stopse buf=all

; 再生前にもう一度スキップとオートモードを停止
@cancelskip
@cancelautomode

; 動画を再生
@layer name=動画 movie=オープニング.wmv

; 再生が終わるまで待つ
@wv layer=all canskip=true

; 再生が飛ばされた時のためにレイヤを動画終了時の色に塗る
;   最後が真っ白ならcolor=0xFFFFFFFF 真っ暗なら color=0xFF000000
;   widthとheightは動画のサイズに合わせます
@動画 color=0xFFFFFFFF width=1280 height=720

; 動画レイヤを隠す
@begintrans
@動画 delete
@endtrans fade=3000

; 少し待つ
@wait time=1000

オープニング動画を再生しました。

KAGEX講座(34) – 遅延実行4(ラベル指定)

delayrunコマンドでは数値の代わりにラベル名を指定できます。その場合はBGM、効果音、ボイスを再生中にその名前のラベルを通過すると実行されます。ラベルはループチューナであらかじめ入れておきます。

@linemode mode=vn

@layer name=カード file=card show
レイヤを表示

@se雨
@カード rotate=90 delayrun=ラベル0
効果音を再生し、ラベル0を通過するタイミングで90度回転します。

ボイスやBGMでも同じです。以下はボイスの例です。

@linemode mode=vn

@layer name=カード file=card show
レイヤを表示

@しおり playvoice=ai000001
@カード rotate=30 delayrun=ラベル0
@カード rotate=60 delayrun=ラベル1
@カード rotate=90 delayrun=ラベル2
【しおり】「ボイス再生中です。ラベル通過でレイヤが回転します」

nodelaydoneやdelaydoneも数値の時と同じように使えます。
delayrunコマンド自体はボイス再生中に立ち絵の表情を変えたりするのに使うことが多いです。数値で指定するよりはラベルを入れて調整するほうが楽だと思います。

KAGEX講座(33) – 遅延実行3(delaycancel)

delaycancelタグでは実行待ちの遅延実行を全て消去します。delaydoneタグや改ページでの強制実行ではその時点で全ての遅延実行が実行されますが、delaycancelでは実行されません。よく注意して使わないとバグの元になります。一応紹介しましたがdelaycancelが必要なことはまず無いので使わないのがいいです。

@linemode mode=vn

@layer name=カード file=card show
レイヤを表示

@カード rotate=30
@カード rotate=60 delayrun=2000
@カード rotate=90 delayrun=4000
@カード rotate=120 delayrun=6000
@カード rotate=150 delayrun=8000
2秒ごとに30度ずつ回転[l]
@delaycancel
クリックした時点で残っている遅延実行は消去され、それ以上回転しません。