常駐ボタンの作り方

■ INDEX

常駐ボタンの作り方
実際のスクリプト(textbtnwait版)  サンプルのダウンロード(textbtnwait版)
新ボタンで作る常駐ボタン
実際のスクリプト(bexec版)  サンプルのダウンロード(bexec版) 

■ textbtnwait版 (基本)

常駐ボタンの作り方

リクエストをいただきましたのでざっくりと説明のページを作成してみました。
テキストウィンドウの周りに常駐するセーブやロードなどのボタン類を設置させる方法を解説します。
このページの内容は、  ・タイトル画面の作り方  ・システムカスタマイズについて
これらの発展系ですから先に上記2つのページを読んで解説を理解しておいてください。

画面のイメージ

Sがセーブ Lがロード ∧がログ >がオート ≫がスキップ XがCGのみ表示 という動作割当です。

先に結論を言ってしまうと「CGを用意してクリック待ちでボタン登録するだけ」で可能です。
まずはサンプル(textbtnwait版)をダウンロードして動かしてから、
次の実際のスクリプト(textbtnwait版)でコードを順に追いかけていってください。
これまでの解説が理解できていればすぐにそのシンプルさがわかると思います。

実際のスクリプト

下記コードでは「システムカスタマイズについて」と比べて変化のある部分を赤字にしています。


;mode800,value1000
;===============================================================================
;定義節
;===============================================================================
*define
nsa
globalon
kidokuskip
humanz 900
;windowback;コメントアウト→テキストは画面最上部に出ます。
shadedistance 1,1
effectcut
usewheel
useescspc
maxkaisoupage 50
mode_wave_demo
;-------------------------------------システムカスタマイズ
textgosub *text_lb
;-------------------------------------
caption "常駐ボタンサンプル"
defaultspeed 0,25,10
automode
automode_time 2000
resetmenu
insertmenu "終了(&X)",END
insertmenu "バージョン情報(&V)",VERSION
insertmenu "リセット(&R)",RESET
insertmenu "オート開始(&A)",AUTO
insertmenu "選択肢までスキップ(&S)",SKIP
insertmenu "各種設定(&C)",SUB
insertmenu "ボリューム設定(&V)",DWAVEVOLUME,1
insertmenu "スキップ設定(&S)",SUB,1
insertmenu "全て",KIDOKUOFF,2
insertmenu "既読のみ",KIDOKUON,2
insertmenu "フォント(&F)",FONT,1
insertmenu "テキスト速度(&T)",SUB,1
insertmenu "瞬間表示",TEXTSLOW,2
insertmenu "普通",TEXTMIDDLE,2
insertmenu "早い",TEXTFAST,2
insertmenu "画面(&W)",SUB,1
insertmenu "フルスクリーン",FULL,2
insertmenu "ウィンドウ",WINDOW,2
savenumber 20
menusetwindow 20,20,0,0,1,1,#CCCCCC
rmenu "文字を隠す",windowerase,"回想",lookback,"次の選択肢に進む",skip,"セーブ",save,"ロード",load,"タイトルへ戻る",reset

;-------------------------------------ウィンドウとボタンのCG管理モジュール
defsub init_textwin
defsub view_textwin
defsub hide_textwin
;-------------------------------------
game
;===============================================================================
;実行節
;===============================================================================
*start
        init_textwin;ウィンドウとボタンのCGを作品の冒頭(*start直後)で設定しておきます

        erasetextwindow 0
        setwindow 20,443,29,4,25,25,0,9,5,1,1,#FFFFFF,0,430,799,599;#FFFFFFで透明指定です。
        textspeeddefault

;-----------シナリオダミー
bg "img¥bg.jpg",0
ld r,":a;img¥tati.png",0
print 10,500

view_textwin;テキスト直前のここでウィンドウやボタン類を表示します。

4行表示のADVスタイルでテストします。¥

汎用の変数に%0を利用。
テキストウィンドウのスプライト番号が900番。
すぐ上に常駐しているボタンCGのスプライト番号が
894〜899番です。¥

123456789012345678901234567890123456789012345678901234567890¥

色は匂へど散りぬるを@
我が世誰ぞ常ならん@
有為の奥山今日越えて@
浅き夢見じ酔ひもせず¥

一度場面転換のテストを入れます。¥

hide_textwin;ウィンドウやボタン類を非表示にします。背景転換時にあると違和感がありません。

bg black,0
print 10,1000
bg "img¥bg.jpg",0
print 10,1000

view_textwin;テキスト直前のここでウィンドウやボタン類を表示します。

このようにボタンやテキストウィンドウを消しておくと見た目もスマートです。¥

消さない場合は次のように、若干残念な見栄えになります。
比較してみましょう。¥

bg black,0
print 10,1000
bg "img¥bg.jpg",0
print 10,1000

このように、ボタンやテキストウィンドウが残ってしまっていると不自然ですね。¥

せっかくの機会なのでNスクの基本動作についても補足しておきましょう。¥

ld c,":a;img¥tati.png",1

立ち絵が出ている状態で……¥

bg black,1

背景を切り替えると立ち絵は消えます。¥

ほとんどの場合、背景の切替は場面転換とイコールであるため、エンジンの側で気を利かせて消してくれているわけです。¥

切り替えた瞬間から立ち絵が出ていて欲しい場合は次のように打ちます。¥

bg "img¥bg.jpg",0
ld l,":a;img¥tati.png",0
print 10,1000

以上です。

クリックで終了します。¥

end
;===============================================================================
;システムカスタマイズ
;-------------------------------------------------------------------------------
;(¥または@到達でこのラベルにgosubされます)
*text_lb
        ;---------------基本設定&画像設定
        saveoff;(autosaveoffしてない場合は書いておこう)
        ;(画像があればここに挟む(クリック待ちアイコンなどもここ))
        ;---------------ボタン設定類
*text_lb_loop
        btndef clear
        ;ボタンの登録
        spbtn 894,894;※スプライト番号をそのままボタン番号にした方が混乱がありません
        spbtn 895,895
        spbtn 896,896
        spbtn 897,897
        spbtn 898,898
        spbtn 899,899
        ;特殊キー入力の設定
        getmclick
        ;---------------キー待ち(通常のbtnwaitではスキップ時に止まってしまうのでtextbtnwaitを使う)
        textbtnwait %0
        ;---------------キー判定
        if %0 == 0   goto *text_lb_end                         ;左クリック or ENTER or SKIP中
        if %0 == -1  hide_textwin:systemcall rmenu:view_textwin:goto *text_lb_loop;右クリック
        if %0 == -2  systemcall lookback:goto *text_lb_loop    ;ホイール上回転
        if %0 == -3  goto *text_lb_end                         ;ホイール下回転
        if %0 == -10 hide_textwin:systemcall rmenu:view_textwin:goto *text_lb_loop;Escキー
        if %0 == -11 goto *text_lb_end                         ;スペースキー
        if %0 == -70 hide_textwin:systemcall windowerase:view_textwin:goto *text_lb_loop ;中クリック
        
        if %0 == 894 systemcall save:goto *text_lb_loop;save
        if %0 == 895 systemcall load:goto *text_lb_loop;load
        if %0 == 896 systemcall lookback:goto *text_lb_loop;backlog
        if %0 == 897 systemcall automode:goto *text_lb_loop;auto
        if %0 == 898 systemcall skip:goto *text_lb_loop;skip
        if %0 == 899 hide_textwin:systemcall windowerase:view_textwin:goto *text_lb_loop;hide
goto *text_lb_loop
;ここに辿り着くということはキーが合わなかったということなのでループに戻します

*text_lb_end
        texec;(※ ¥の場合にtextclearを内部で呼んでくれる)
        saveon;(autosaveoffしてない場合はtexec直後に必須)
return

;-------------------------------------------------------------------------------
;ウィンドウとボタンのCG管理モジュール
;-------------------------------------------------------------------------------
;894〜900番を使用。これらのスプライト番号は絶対に重複利用させないこと。

*init_textwin
        ;画像類の登録
        lsph 894,":a/2,0,3;img¥save.png",600-5,400;save
        lsph 895,":a/2,0,3;img¥load.png",630-4,400;load
        lsph 896,":a/2,0,3;img¥backlog.png",660-3,400;backlog
        lsph 897,":a/2,0,3;img¥auto.png",690-2,400;auto
        lsph 898,":a/2,0,3;img¥skip.png",720-1,400;skip
        lsph 899,":a/2,0,3;img¥hide.png",750,400;hide
        lsph 900,":c;img¥window.jpg",20,430,128;textwindow(※透明度50%で登録しています)
        ;(解説)
        ;humanz 900状態なので、立ち絵は900番よりも下で、901番よりも上のレイヤーに表示されます。
        ;もしwindowbackも設定していた場合テキスト位置は「900→テキスト→立ち絵→901」となります。
        ;そのため、今回はwindowbackを削ってテキストを最上部に表示させるようにしています。
        ;立ち絵をスプライトで運用していく段階になると再びwindowbackを活かせるようになります。
return

*view_textwin
        ;画像類を表示状態にする
        for %0=894 to 900:vsp %0,1:next
        print 1
return

*hide_textwin
        ;画像類を非表示状態にする
        for %0=894 to 900:vsp %0,0:next
        print 1
return

サンプルのダウンロード

実際に動かしてみた方がわかりやすいのでサンプルを用意しておきました。

winbtn_sample.zip ←右クリックして保存を選んでください

見ていただければ分かるように、単にボタンになる画像を用意しておいて、
システムカスタマイズのところでボタン登録→if分岐の設定をするだけ
です。
とてもシンプルですから前回からの発展としても理解しやすいと思います。

また、この段階からテキスト枠のCGをsetwindowから分離してスプライトにしています。
setwindow側はサンプルの通り#FFFFFFで透明指定となります。
何故こうするかというとテキストウィンドウは常駐ボタンと一緒に扱った方が見栄えがするためです。
表示非表示の切替頻度が多いので、こうしないとプレー中にチラつきが気になってしまいます。
スプライトにしておくと扱いやすく、濃度指定も自由に出来るので明らかに便利になりますね。
こうしておけば将来作るかもしれないコンフィグ画面でテキストウィンドウ濃度調整の項目も作れます。
カットインに行うようにテキストウィンドウを揺らしたりするような演出が出来たりもしますね。

今回のサンプルではsystemcallでNScripterからデフォルトの機能呼び出しをしていますが、
セーブやロードやコンフィグなどを自作している場合はそちらを呼び出すことができます。
その場合は、 systemcall save を gosub *save_mode などと変えるだけです。
ここまで打てるようになっている方はこなせることと思います。ぜひ挑戦してみてください。

次はpretextgosubやgettag命令を使って名前ウィンドウを作成することも出来ると思います。
textgosubと基本動作は変わりません。リファレンスを読みながら試してみましょう。

また、defsubも見ての通り簡単かつ便利ですからこの機会に覚えておきましょう。
今回のサンプルのように単なるサブルーチンの代わりに使うことも出来ますし、
引数や返値を設定できるような命令を作ることも可能なので、とても強力な武器になります。
(このdefsubという機能は吉里吉里でいうマクロのようなものですね。

もうひとつ、textbtnwaitは基本的にキーアップ時の取得ですが、ESCキーはキーダウン取得になります。
上のコードではあえて放置していますが、ESCキーを押して離すと右クリックメニューが出てすぐ消えます。
(ESCキーダウンで入り判定→デフォの右クリックメニュー→キーアップで抜け判定を瞬時にやっているため)
いくつかある特殊キー動作はcheckkey命令などで対策できますので、是非挑戦してみてください。

※ 次の新ボタンで実装する手法はシスカマに慣れた中級者向けとなります。まずはこの基本のやり方を覚えてください。

■ bexec版 (中級者向け)

新ボタンで作る常駐ボタン

「spbtnですか」というコメントをいただいてしまいましたので、新ボタン版も記載。
実はこちらでやるとちょっと面倒ごとが多いのですが、上のスクリプトと続けて比較してみてください。

画面のイメージ

Sがセーブ Lがロード ∧がログ >がオート ≫がスキップ XがCGのみ表示 という動作割当です。

実際のスクリプト(bexec版)

下記コードでは上の「実際のスクリプト(textbtnwait版)」と比べて変化のある部分を赤字にしています。


;mode800,value1000
;===============================================================================
;定義節
;===============================================================================
*define
nsa
globalon
kidokuskip
humanz 900
;windowback;コメントアウト→テキストは画面最上部に出ます。
shadedistance 1,1
effectcut
usewheel
useescspc
maxkaisoupage 50
mode_wave_demo
;-------------------------------------システムカスタマイズ
textgosub *text_lb
;-------------------------------------
caption "常駐ボタンサンプル"
defaultspeed 0,25,10
automode
automode_time 2000
resetmenu
insertmenu "終了(&X)",END
insertmenu "バージョン情報(&V)",VERSION
insertmenu "リセット(&R)",RESET
insertmenu "オート開始(&A)",AUTO
insertmenu "選択肢までスキップ(&S)",SKIP
insertmenu "各種設定(&C)",SUB
insertmenu "ボリューム設定(&V)",DWAVEVOLUME,1
insertmenu "スキップ設定(&S)",SUB,1
insertmenu "全て",KIDOKUOFF,2
insertmenu "既読のみ",KIDOKUON,2
insertmenu "フォント(&F)",FONT,1
insertmenu "テキスト速度(&T)",SUB,1
insertmenu "瞬間表示",TEXTSLOW,2
insertmenu "普通",TEXTMIDDLE,2
insertmenu "早い",TEXTFAST,2
insertmenu "画面(&W)",SUB,1
insertmenu "フルスクリーン",FULL,2
insertmenu "ウィンドウ",WINDOW,2
savenumber 20
menusetwindow 20,20,0,0,1,1,#CCCCCC
rmenu "文字を隠す",windowerase,"回想",lookback,"次の選択肢に進む",skip,"セーブ",save,"ロード",load,"タイトルへ戻る",reset

;-------------------------------------ウィンドウとボタンのCG管理モジュール
defsub init_textwin
defsub view_textwin
defsub hide_textwin
;-------------------------------------
game
;===============================================================================
;実行節
;===============================================================================
*start
        init_textwin;ウィンドウとボタンのCGを作品の冒頭(*start直後)で設定しておきます

        erasetextwindow 0
        setwindow 20,443,29,4,25,25,0,9,5,1,1,#FFFFFF,0,430,799,599;#FFFFFFで透明指定です。
        textspeeddefault

;-----------シナリオダミー
bg "img¥bg.jpg",0
ld r,":a;img¥tati.png",0
print 10,500

view_textwin;テキスト直前のここでウィンドウやボタン類を表示します。

4行表示のADVスタイルでテストします。¥

汎用の変数に%0と$0を利用。
テキストウィンドウのスプライト番号が900番。
すぐ上に常駐しているボタンCGのスプライト番号が
894〜899番です。¥

123456789012345678901234567890123456789012345678901234567890¥

色は匂へど散りぬるを@
我が世誰ぞ常ならん@
有為の奥山今日越えて@
浅き夢見じ酔ひもせず¥

一度場面転換のテストを入れます。¥

hide_textwin;ウィンドウやボタン類を非表示にします。背景転換時にあると違和感がありません。

bg black,0
print 10,1000
bg "img¥bg.jpg",0
print 10,1000

view_textwin;テキスト直前のここでウィンドウやボタン類を表示します。

このようにボタンやテキストウィンドウを消しておくと見た目もスマートです。¥

消さない場合は次のように、若干残念な見栄えになります。
比較してみましょう。¥

bg black,0
print 10,1000
bg "img¥bg.jpg",0
print 10,1000

このように、ボタンやテキストウィンドウが残ってしまっていると不自然ですね。¥

せっかくの機会なのでNスクの基本動作についても補足しておきましょう。¥

ld c,":a;img¥tati.png",1

立ち絵が出ている状態で……¥

bg black,1

背景を切り替えると立ち絵は消えます。¥

ほとんどの場合、背景の切替は場面転換とイコールであるため、エンジンの側で気を利かせて消してくれているわけです。¥

切り替えた瞬間から立ち絵が出ていて欲しい場合は次のように打ちます。¥

bg "img¥bg.jpg",0
ld l,":a;img¥tati.png",0
print 10,1000

以上です。

クリックで終了します。¥

end
;===============================================================================
;システムカスタマイズ
;-------------------------------------------------------------------------------
;(¥または@到達でこのラベルにgosubされます)
*text_lb
        ;---------------skip処理(skipはbexecで強制的に止まるのでここで判定します)
        isskip %0;(スキップ状態のチェック)
        if %0 == 1 _wait 1:goto *text_lb_end;(フリーズ対策に必ずwait 1を入れておくこと)
        ;---------------基本設定&画像設定
        saveoff
*text_lb_loop
        ;必ず定義クリア
        bclear
        ;ボタンの登録
        bsp 894
        bsp 895
        bsp 896
        bsp 897
        bsp 898
        bsp 899
        ;---------------auto処理(textbtnwaitと違って自動でオート時間を汲んでくれないので手動設定)
        isskip %0;(オート状態のチェック)
        if %0 == 2 btime 2000:skipoff;(ここで一旦デフォルトオートを止めてbtimeで待たせます)
        ;---------------キー待ち(通常のbtnwait同様にスキップ時に止まってしまう)
        bexec $0
        ;caption $0;(このコメントアウトを外すとデバッグ時に便利です)
        ;---------------キー判定
        if $0 == "LCLICK"  | $0 == "CTRL" | $0 == "ENTER" | $0 == "SPACE" | $0 == "WHEELDOWN"  goto *text_lb_end;ページ送り
        if $0 == "TIMEOUT" systemcall automode:goto *text_lb_end;オートのタイムアウト(オート再開+ページ送り)
        if $0 == "RCLICK"  | $0 == "ESC"  hide_textwin:systemcall rmenu:view_textwin:goto *text_lb_loop;右クリックメニュー
        if $0 == "WHEELUP" systemcall lookback:goto *text_lb_loop;ホイール上回転
        if $0 == "MCLICK" hide_textwin:systemcall windowerase:view_textwin:goto *text_lb_loop ;中クリック
        if $0 == "SKIP" systemcall skip:goto *text_lb_end;スキップ開始
        if $0 == "AUTO" systemcall automode:goto *text_lb_loop;オート開始(待ち動作を入れるために一度ループに戻します)
        
        if $0 == "S894" systemcall save:goto *text_lb_loop ;save
        if $0 == "S895" systemcall load:goto *text_lb_loop ;load
        if $0 == "S896" systemcall lookback:goto *text_lb_loop ;backlog
        if $0 == "S897" systemcall automode:goto *text_lb_loop ;auto
        if $0 == "S898" systemcall skip:goto *text_lb_end ;skip
        if $0 == "S899" hide_textwin:systemcall windowerase:view_textwin:goto *text_lb_loop;hide
        ;(%0でなく$0と、数値変数から文字列変数になることに注意してください)
goto *text_lb_loop
;ここに辿り着くということはキーが合わなかったということなのでループに戻します

*text_lb_end
        texec;(※ ¥の場合にtextclearを内部で呼んでくれる)
        saveon
return

;-------------------------------------------------------------------------------
;ウィンドウとボタンのCG管理モジュール
;-------------------------------------------------------------------------------
;894〜900番を使用。これらのスプライト番号は絶対に重複利用させないこと。

*init_textwin
        ;画像類の登録
        lsph 894,":a/2,0,3;img¥save.png",600-5,400;save
        lsph 895,":a/2,0,3;img¥load.png",630-4,400;load
        lsph 896,":a/2,0,3;img¥backlog.png",660-3,400;backlog
        lsph 897,":a/2,0,3;img¥auto.png",690-2,400;auto
        lsph 898,":a/2,0,3;img¥skip.png",720-1,400;skip
        lsph 899,":a/2,0,3;img¥hide.png",750,400;hide
        lsph 900,":c;img¥window.jpg",20,430,128;textwindow(※透明度50%で登録しています)
return

*view_textwin
        ;画像類を表示状態にする
        for %0=894 to 900:vsp %0,1:next
        print 1
return

*hide_textwin
        ;画像類を非表示状態にする
        for %0=894 to 900:vsp %0,0:next
        print 1
return

サンプルのダウンロード(bexec版)

実際に動かしてみた方がわかりやすいので今回もサンプルを用意しておきました。

winbtn_sample2.zip ←右クリックして保存を選んでください

新ボタン(bexec)を使う最大のメリットはキー感度の良さです。
ループを回しながら入力を待つ動作では、右クリックの感度が悪いbtnwait系と大きな違いが得られます。
また、各キーボードの入力を拾えるため、拡張の自由度がさらに広がる良いことずくめです。
しかしながら、スキップ周りとオート周りで少々工夫しなくてはなりません
オート周りはデフォルトのオートをすぐ使わなくなるでしょうから自作オートでどうとでもなるのですが、
スキップ周りで必ず上のコードのような工夫が必要になります。
bexecで必ずスキップが止まってしまうので、状態をチェックして、bexecを回避してテキスト送りをします。
このとき、マシンによってフリーズがおきますので必ずwait 1を入れておいてください。

上のコードのオートも半分自作のようなものですが、skipoffを入れる理由を解説しておきます。
デフォルトオート状態ですと、btime設定があっても無視して0msでbexecを"AUTO"値を持って経過します。
上のコードでは"TIMEOUT"で判定したかったので一度skipoffでデフォルトのオートを止めているのです。

bexec命令は一般ユーザがテキストのクリック待ちに利用することを想定していないと考えられますが、
(テキスト待ちに使うには、いつものNScripterらしい親切さがうかがえないため)
慣れた方なら上記のようにちょっとした工夫で利用できる柔軟性もまたNスクらしいところですね。

上のコードでは一度目スキップだと既読スキップで止まってしまって二回目ではじめて……という、
よくある動作になっていますが、対応は可能です。その原因は中級TIPSで書いたとおりですから、
強制的にifを先読みしておくか、既読に関係のないluaコードで判定するかといった手法になります。
このあたりは上達していけばやり方が浮かぶと思いますので詳しい解説は行いません。

また、bexec命令は全てキーダウン時に判定がありますので、
上のコードではあえて放置していますが、ESCキーを押して離すと右クリックメニューが出てすぐ消えます。
(ESCキーダウンで入り判定→デフォの右クリックメニュー→キーアップで抜け判定を瞬時にやっているため)
またスペースキーで延々と文字送りする動作になっています。
こういった動作はcheckkey命令などで対策できますので、是非挑戦してみてください。