Ren’Pyで画面全体にテキストウィンドウを表示する方法とスタイルを使用した外観カスタマイズ例

NVLモードで動作させる

 Ren’Pyで画面全体にテキストを表示するにはNVLモードを使用します。公式ドキュメントに従えば特に難しいことはなく下記のようにnvlモードで表示するキャラクターを定義し、地の文もnvlで表示したければnarratorも置き換えればよいだけです。

https://ja.renpy.org/doc/html/nvl_mode.html

define n = Character('NVL', color="#c8ffc8", kind=nvl) #nvlにしたければkindをnvlにそうでなければadvにする
define a = Character('ADV', color="#c8ffc8", kind=adv)
define narrator = nvl_narrator #地の文も置き換えるならばnarratorをnvl_narratorに

 narratorはゲーム中でも他の変数と同じように変更できるので用途に合わせて切り替えられます。戻すときは_narratorを代入するか、適当な変数に保存しておけばよいです。

$adv_narrator=narrator #narratorをバックアップ(この方法をとるならdefineでnvl_narratorをnarratorに代入しないこと)
$narrator=nvl_narrator
"この地の文はnvlモードで表示されます。"
$narrator=nvl_narrator
"この地の文はadvモードで表示されます。"

 選択肢を表示するときは引数にnvl=Trueを指定すればnvlウィンドウのなかに選択肢が組み込まれます。指定しない場合nvlウィンドウの上に通常の方法で選択肢が表示されます。

menu(nvl=True)
    n "nvlウィンドウに選択肢を表示"
    "選択肢A":
        jump A
    "選択肢B":
        jump A

 その他動作について注意しておく点としては空windowの表示非表示です。Ren’Pyではウィンドウの表示、非表示時にトランジション効果をつけられますが、これはconfig.empty_windowを実行して空のウィンドウをトランジション付きで表示、非表示して実施しています。現行のバージョンでは_default_empty_window関数が設定されており、これは直前のキャラクターのkindに従って空のウィンドウを表示しているのですが、直前のキャラクターなのでウィンドウ非表示時には問題ないのですが、次に話すキャラクターが違うkindですとadvモードなのにウィンドウ表示時にnvlウィンドウが一瞬表示されたりその逆が起こります。これを防ぐのはなかなか難しく直前のキャラクターを参照する_default_empty_windowと常にnvlウィンドウを表示するnvl_show_core, 常にadvウィンドウを表示する_narrator.empty_windowを適宜切り替えて使用する必要があります。例えば以下のように記述します。

scene
with dissolve
$config.empty_window = nvl_show_core
n "nvlウィンドウが表示されます。"
scene
with dissolve
$config.empty_window = _narrator.empty_window
a "advウィンドウが表示されます。"

 最初のnvlキャラクターの台詞はnvl_show_coreで表示されるのでnvlウィンドウで表示、非表示されます。次のadvキャラクターの台詞は_default_empty_windowでは直前のnvlキャラクターを参照してしまうので_narrator.empty_windowを使用します。

 このように適宜切り替える必要がでてきます。いっそモード切替時にはウィンドウのトランジションを実施しないというのも手です。これを自動でやるには以下のリンクのコードをRen’Py本体に追加してください。_default_empty_windowで次のステートメントがsayか、キャプション付きのmenuステートメントだった場合は直前ではなく直後のキャラクターを参照するようになり、自動的にウィンドウを管理してくれます。一応本家にもパッチを送っているので採用されれば次期バージョンからはウィンドウについては何もしなくてよくなるかもしれません。

https://github.com/kyouryuukunn/renpy/commit/2e31cd29b66af8b464df149e9782a9043d765c02

外観のカスタマイズ

 これでnvlモードの動作については問題ないと思いますが、恐らくnvlウィンドウの外観が気になってくるでしょう。標準では以下のような表示になります。地の文とキャラクターの台詞で揃っていません。行の間隔も広すぎるし、そもそもadvモードではないテキスト全体表示ですとキャラクター名自体が不要に思えます。

 なので以下を外観を設定してみます。guiのカスタマイズに関しては取りあえず以下のページを読んでみましょう

https://ja.renpy.org/doc/html/gui.html#nvl

外観を設定します。いかのコードを記述してみてください。

define e = Character(None, kind=nvl, what_prefix="「", what_suffix="」", ctc=Text("{size=-5}→{/size}"), ctc_pause=Text("{size=-5}pause{/size}"))
define narrator = Character(None, kind=nvl, ctc=Text("{size=-5}→{/size}"), ctc_pause=Text("{size=-5}pause{/size}"))
init python:
    config.nvl_page_ctc = Text("{size=-5}↓{/size}")

label start:

    scene bg room
    with dissolve
    e "Ren'Py の新しいゲームを作成しました。nvlモードのテストです。nvlモードのテストです。nvlモードのテストです。nvlモードのテストです。"
    "Ren'Py の新しいゲームを作成しました。nvlモードのテストです。nvlモードのテストです。nvlモードのテストです。nvlモードのテストです。"
    e "Ren'Py の新しいゲームを作成しました。nvlモードのテストです。nvlモードのテストです。nvlモードのテストです。nvlモードのテストです。"
    "Ren'Py の新しいゲームを作成しました。nvlモードのテストです。nvlモードのテストです。nvlモードのテストです。nvlモードのテストです。"
    nvl clear

 まずキャラクター名は不要なのでNoneにします。ちなみにキャラクター定義時にprefix, suffixを設定すると「」を自動で入れられたりまします。キャラクター名を表示しないなら全部narratorで「」は自分で入れた方がシンプルでよさそうですが。また、定義時にctc_pauseやctcを指定するとそれがクリック待ち時に表示できます。今回は文字を使用しましたが、画像を指定した方が見栄えするでしょう。改ページの記号はconfig.nvl_page_ctcで指定します。ここまでで画面が次のようになります。

 では行間が開いているのを近づけます。ドキュメントに従い以下のコードを追加しますと行が近づきます。

define gui.nvl_height = None
define gui.nvl_spacing = 0

 ここでテキストの上でShift+iを押してみてください。Displayableインスペクターが表示されます。その中のvboxをクリックしてみると以前はなかったSpacing 0の設定が追加されています。ちなみにこれは下が親で上に行くほど設定の優先度が高くなります。VBOXの場合default->vbox->displayableの順に優先度が上がります。

 実はRen’Pyのgui.hogehogeという変数はスタイルとかを直接弄らなくてもユーザーが外観を変更しやすいようにする薄いラッパーだったりします(なので標準のscreens.rpyがないとほぼ動作しません)。数値を設定するだけでよいのでスタイルを弄れないユーザーにはよいのでしょうが、今後のために実際にはどう設定しているのかを見てみます。gui周りの変数は変数名でscreens.rpyを検索するとどういう風にスタイルを設定すればよいかの参考になってよいと思います。Displayableインスペクターによるとvboxはscreens.rpyの1314で定義していますので開いてみます。

screen nvl(dialogue, items=None):

    window:
        style "nvl_window"

        has vbox:
            spacing gui.nvl_spacing

        ## gui.nvl_height が設定されていれば vpgrid で等間隔に表示、そうでなけれ
        ## ば vbox で可変的に表示します。
        if gui.nvl_height:

            vpgrid:
                cols 1
                yinitial 1.0

                use nvl_dialogue(dialogue)

        else:

            use nvl_dialogue(dialogue)

        ## 選択肢があれば表示。config.narrator_menu が初期設定である True のまま
        ## の場合、正しく表示されないことがあります。
        for i in items:

            textbutton i.caption:
                action i.action
                style "nvl_button"

    add SideImage() xalign 0.0 yalign 1.0


screen nvl_dialogue(dialogue):

    for d in dialogue:

        window:
            id d.window_id

            fixed:
                yfit gui.nvl_height is None

                if d.who is not None:

                    text d.who:
                        id d.who_id

                text d.what:
                    id d.what_id

  赤文字の部分に注目すると単純にvboxのプロパティーにgui.nvl_spacingを指定しているだけですね。これをみるとgui.nvl_heightが有効のときはすべてのテキストが1つのvpgrid内に並べられるのでgui.nvl_spacingでは思うような動作はしません。

 さて、行間隔は大分縮まりましたが、まだ少し同じステートメントのテキスト間と比べると少し広いです。これは青文字の部分で1行1行のテキストをwindowに包んでいるのでwindowのプロパティーが効いている気がします。ドキュメントのwindowのスタイルプロパティーを参照して以下のようにypaddingを0にしてみました。

https://ja.renpy.org/doc/html/style_properties.html#window-style-properties

        window:
            id d.window_id
            ypadding 0

            fixed:
                yfit gui.nvl_height is None

 変化なしです。ymarginも設定した見ましたがこちらも変化なしで違ったようです。となるとテキスト自体のスタイルでしょう。テキストに同様にしてスタイルを指定してもよいですが、色々な方法を試すため、ここはstyleステートメントを使用します。先ほどのインスペクターの表示だとNVLモードのテキストはnvl_dialogueスタイルで定義されています。丁度みているscreens.rpyの少し下で定義しているのでこれを変更しましょう。

https://ja.renpy.org/doc/html/style_properties.html#text-style-properties

style nvl_dialogue is say_dialogue:
    line_leading 0

 上記のコードではsay_dialogueを親としてそのプロパティーを引き継ぎ、line_leadingプロパティのみ変更しています。…効果ないですね。line_spacingも0にしましたが効果なかったです。この間隔どこ由来なのでしょ?分からないのでgui.nvl_spacingを-5ぐらいにします。対症療法ですが、こだわっているときりがないので動けばいいのさの精神が重要です。次に全体が右上に寄りすぎなので同様にしてどのスタイルが効いているかをインスペクターで探し、設定します。vboxごと動かすのが力業ですが楽そうです。vboxにはスタイル名が設定されていないですね。以下のようにしましょう。

screen nvl(dialogue, items=None):

    window:
        style "nvl_window"

        has vbox:
            style "nvl_vbox" #style追加
            spacing gui.nvl_spacing
style nvl_vbox:
    xoffset -150
    yoffset 50

 こうすると今度は一行が短く感じたのでさらに一行の長さを設定します。gui.nvl_text_widthを700にしました。最終的に画面はこうなります。

 これで見た目はまあまあよくなりました。しかしADVモードならまだ見られるのですが、NVLモードだと横長の画面と合いませんね。横一杯までテキストを表示すると視線の移動量が増えるので仕方ないですが。

 ちなみにデザインの違う複数ウィンドウを使用したい場合ですが、一応キャラクター定義で使用するスクリーンを指定出来ますが、say, nvlスクリーン以外の使用を想定していない部分が見られるため、スクリーンはすべてsay, nvlスクリーンを使用し、デザインはフラグを立てて変更するようにした方がよいです。

Pocket