KAGEX拡張例(コンダクタの停止)

前回の続きです。

kag.addTagを使うとコンダクタに次のタグを登録できます。登録するだけなので[s]タグなどでコンダクタが止まっている間はタグは実行されません。

タグが実行されない例

以下の例では[msgoff][msgon]タグを登録していますが、コンダクタが停止しているため実行されることはありません。

function flashMessage() {
    /* 以下のタグを登録
     *   @msgoff time=500
     *   @msgon time=500
     */
    kag.addTag("msgoff", %[ time:500 ]);
    kag.addTag("msgon", %[ time:500 ]);
}
@linemode mode=vn

コンダクタを停止します。

@click exp="flashMessage()"
@s

[click]タグを使って左クリックされた時にflashMessage()が呼ばれるように設定しています。flashMessage()は[msgoff][msgon]タグを登録する関数です。[msgoff][msgon]を連続的に実行してメッセージレイヤを点滅させようとしていますが、これでは動作しません。

[s]タグでコンダクタの動作が停止されており、登録されたタグが実行されないためです。動作させるにはflashMessage()でタグを登録するだけでなくコンダクタの動作を開始しなければなりません。

実行されるように修正した例

以下が実際に動作するように修正したスクリプトです。クリックするたびにメッセージレイヤが点滅します。

function flashMessage() {
    /* 以下のタグを登録
     *   @msgoff time=500
     *   @msgon time=500
     *   @waittrig name=flash_message
     */
    kag.addTag("msgoff", %[ time:500 ]);
    kag.addTag("msgon", %[ time:500 ]);
    kag.addTag("waittrig", %[ name:"flash_message" ]);
    
    // triggerでコンダクタの実行を再開
    kag.trigger("flash_message");
}
@linemode mode=vn

コンダクタを停止します。

@click exp="flashMessage()"
@waittrig name=flash_message

[s]タグの代わりに[waittrig]タグを使っています。このタグもコンダクタの動作を停止しますが、name属性に指定したトリガが発動されるとコンダクタの動作を再開します。この場合は”flash_message”が発動すれば動作を再開します。

flashMessage()ではタグを登録してからkag.trigger(“flash_message”);としてトリガを発動します。これによってコンダクタの動作が再開され、登録したタグを順番に実行できます。

最初の例と異なり、[msgoff][msgon]タグだけでなく[waittrig]タグも登録していることに注意してください。[s]や[waittrig]などのタグでコンダクタを停止しない場合は当然そのまま実行し続けます。この例では登録したタグを実行し終わった後、first.ks最後の @waittrig name=flash_message の次の行から実行されます。続きを実行したくない場合はしっかり止めるようにしてください。

まとめ

kag.addTagを使うときはコンダクタの動作を意識するようにしてください。注意して使わないと思わぬバグの元になりかねません。

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

吉里吉里2から吉里吉里Zへの移行

吉里吉里Zに移行しようとしてみた
吉里吉里Zに移行しようとして挫折した話を読んだ。吉里吉里2と吉里吉里Zではかなり違うので意外と大変そう。

(勝手に)吉里吉里Z移行ガイドはまず読んだ方がいいです。以下、ここに書いていない部分など。

・コンソールがない
githubにあるKrkr2Compatにtjsで書かれたコンソールがあります。
右にあるDownload ZIPボタンから吉里吉里Zのソースコードをダウンロードできます。その中のscript/Krkr2Compat/フォルダがKrkr2Compatです。使い方などの詳しい説明はreadme.txtを読んでください。

・Layerのメソッドが減ってる
Layer.affineBlendなど古いメソッドが無くなっています。以下のスクリプトをstartup.tjsの最初などに書いておけばいいです。厳密にはLayer.faceとLayer.typeを使っていると描画結果が変わることがあるかもしれません。

Layer.affineBlend = function(src, sleft, stop, swidth, sheight, affine, A, B, C, D, E, F, opa=255, type=stNearest) {
    this.operateAffine(src, sleft, stop, swidth, sheight, affine, A, B, C, D, E, F, omOpaque, opa, type);
};
Layer.affinePile = function(src, sleft, stop, swidth, sheight, affine, A, B, C, D, E, F, opa=255, type=stNearest) {
    this.operateAffine(src, sleft, stop, swidth, sheight, affine, A, B, C, D, E, F, omAuto, opa, type);
};
Layer.blendRect = function(dleft, dtop, src, sleft, stop, swidth, sheight, opa=255) {
    this.operateRect(dleft, dtop, src, sleft, stop, swidth, sheight, omOpaque, opa);
};
Layer.pileRect = function(dleft, dtop, src, sleft, stop, swidth, sheight, opa=255) {
    this.operateRect(dleft, dtop, src, sleft, stop, swidth, sheight, omAuto, opa);
};
Layer.stretchBlend = function(dleft, dtop, dwidth, dheight, src, sleft, stop, swidth, sheight, opa=255, type=stNearest) {
    this.operateStretch(dleft, dtop, dwidth, dheight, src, sleft, stop, swidth, sheight, omOpaque, opa, type);
};
Layer.stretchPile = function(dleft, dtop, dwidth, dheight, src, sleft, stop, swidth, sheight, opa=255, type=stNearest) {
    this.operateStretch(dleft, dtop, dwidth, dheight, src, sleft, stop, swidth, sheight, omAuto, opa, type);
};

・自分でビルドしよう
配布されているバージョンはあまり更新されないようなのでできれば自分で最新版をビルドして使った方が良いです。発見されたバグなどが修正されていません。
やり方はgithubのHowToBulid.txtに書いてあります。簡単に手順を説明すると
1.Visual Studio Express 2012をインストールする
2.nasm-2.10.09-installer.exeをダウンロードしてインストールする
3.githubのDownload ZIPボタンからソースコードをダウンロードする
4.解凍してsrc/core/vc2012/tvpwin32.slnをダブルクリックしてVisual Studio 2012を起動する
5.メニューのビルド>ソリューションのビルドをクリックする
しばらく待つとbin/win32/フォルダにtvpwin32.exeができます

・移行する意味あるの?
新しい機能を使わないなら苦労するだけです。やめておきましょう。

最初に作ったWindowを閉じると終了してしまう

以下のスクリプトを実行すると、ウィンドウが一瞬表示されてもすぐに吉里吉里が終了してしまいます。吉里吉里ではメインウィンドウ(最初に作ったウィンドウ)が無効化されると自動的に終了する仕組みになっているからです。
この場合は先に作成したtemporaryWindowが無効化されているため終了してしまいます。

var temporaryWindow = new Window();
invalidate temporaryWindow;

var mainWindow = new Window();
mainWindow.visible = true;

System.exitOnWindowCloseをfalseにしておけばメインウィンドウが無効化されても終了しなくなります。なので以下のようにすればtemporaryWindowが無効化されても吉里吉里が終了しないようにできます。

// temporaryWindowが無効化されても吉里吉里が終了しないようにする
System.exitOnWindowClose = false;

var temporaryWindow = new Window();
invalidate temporaryWindow;

// mainWindowが無効化されたら吉里吉里が終了するようにtrueに戻しておく
System.exitOnWindowClose = true;

var mainWindow = new Window();
mainWindow.visible = true;

mainWindowが作成される時点で他のウィンドウがないので、mainWindowが新しいメインウィンドウとして機能します。よってSystem.exitOnWindowCloseをtrueに戻しておけば、mainWindowが無効化されたときに吉里吉里も終了するようになります。
falseのままだとウィンドウが全て消えても吉里吉里自体は起動したまま、ということになってしまうので戻しておくのが安全です。

実際に表示して使用するウィンドウを作成する前に、別の用途で一時的にウィンドウを使う場合などに便利だと思います。ちょっとウィンドウ作成したら勝手に終了するようになったので、この辺を覚えていないと微妙に詰まりました。

ちなみにですが、ウィンドウオブジェクトは右上の閉じるボタンやWindow.closeなどで閉じると自動的に無効化されるようです。無効化せず非表示にしたいだけの場合はWindow.visibleの方を使います。