Python ステートメント link

Ren'Py は、Python プログラミング言語で書かれており、Ren'Py スクリプトの中に Python のコードを埋め込められます。Python への対応は、フラグの設定から displayable の新規作成まで、様々な場面で利用できます。この章では、Ren'Py のスクリプトから Python コードのステートメントを直接呼び出す方法を説明します。

Ren'Py 7 は Python 2.7 を、 Ren'Py 8 は Python 3.9 をサポートします。

注釈

Python を知っているなら、それを活用できるでしょう。しかし Python について知っていることがそのまま適用出来るわけではありません。たとえば Ren'Py には含まれていない Python パッケージは Ren'Py 内で動作しません。

また、いくつかのPythonのコンストラクトは動作しますが、セーブ時に問題が発生する可能性があります。詳しくは セーブ、ロード、ロールバック のページ、特に 何がセーブされないか にある保存できないものについてのセクションを読んでください (ファイル、ソケット、イテレータ、タスク、フューチャー、ジェネレータには注意が必要です)。

最後に、多くのステートメントには Python で相当するものがありますが、それらは劣っている可能性があります。例えば、Ren'Pyは show ステートメントを予測し、画像を早期にロードできますが、 renpy.show() 関数は予測できません。

Python link

python ステートメントは python コードのブロックを受け取り、制御がそのステートメントまで到達するとそのコードを実行します。基本的な python ステートメントはとても単純です。

python:
    flag = True

python ステートメントは必要ならさらに複雑になります。

python:
    player_health = max(player_health - damage, 0)
    if enemy_vampire:
        enemy_health = min(enemy_health + damage, enemy_max_health)

python ステートメントにはその動作を変更するものが二つあります。 :

hide

hide が与えられると python ステートメントは無名のスコープで python のブロックを実行します。そのスコープは python ブロックが終了すると消失します。

これで python コードに保存されない一時的な変数を使用可能になります。しかしそれはつまり store オブジェクトに直接ではなくフィールドとしてアクセスする必要があるということでもあります。

in

in は名前を受け取ります。デフォルトの store で実行する代わりに python コードはその名前の store で実行されます。

一行 python link

デフォルトの store で実行される一行だけの python が欲しいというのはよくあることです。例えばフラグの初期化や更新には一行だけの python が使用されます。 一行だけの python をより便利に記述するために、一行 python のステートメントがあります。

一行 python ステートメントはドル記号 $ で始まり、その行にコードのすべてを含みます。ここでは 一行 python の例をいくつか示します。

# Set a flag.
$ flag = True

# Initialize a variable.
$ romance_points = 0

# Increment a variable.
$ romance_points += 1

# Call a function that exposes Ren'Py functionality.
$ renpy.movie_cutscene("opening.ogv")

一行 python は常にデフォルトの store で実行されます。

init python ステートメント link

init python ステートメントはゲームロード前の初期化時に python コードを実行します。特にこのコードはクラス、関数の定義やスタイル、設定変数、永続データの初期化に使用されます。

init python:

    def auto_voice_function(ident):
        return "voice/" + ident + ".ogg"

    config.auto_voice = auto_voice_function

    if persistent.endings is None:
        persistent.endings = set()

init 1 python:

    # The bad ending is always unlocked.
    persistent.endings.add("bad_ending")

優先度の値は initpython の間に配置出来ます。優先度が指定されないと、 0 が使用されます。 init ステートメントは優先度の小さいものから大きいものの順に実行されます。 優先度の同じ init ステートメントはファイルパスのユニコード順に、各ファイルの開始から終端まで実行されます。

Ren'Py 本体との衝突を防ぐため、開発者は -999 から 999 の範囲の優先度を使用するべきです。 0 以下の優先度は通常ライブラリーやテーマの設定に使用されます。通常の init コードには優先度 0 かそれ以上を使用するべきです。

init python ステートメントは hidein 節も受け取ります。

init python ブロックで値が設定された変数はその変数が参照するオブジェクトが変更されない限りセーブ、ロードされず、ロールバックにも参加しません。それゆえこれらの変数は初期化後は変更されるべきではありません。

警告

Ren'Py 内で作成され、何も継承しないか明示的に object を継承するクラス、およびこれらのクラスのサブクラスは、 __slots__ をサポートしません。これを実行しようとすると、古いバージョンのrenpyではロールバックの動作がおかしくなり、新しいバージョンではエラーが発生します。

スロットを持つクラスを作成するには、ロールバックをサポートしない python_object を明示的にサブクラスとして作成する必要があります。

define ステートメント link

define ステートメントは初期化時、変数に値を設定します。例えば

define e = Character("Eileen")

これは (後述のいくつかの利点を除いて) 次と等しいです。

init python:
    e = Character("Eileen")

define ステートメントはドットと変数名を続けて任意で名前付き store (以下参照) も受け取られます。その store がなければ作成されます。例

define character.e = Character("Eileen")

define ステートメントは任意にインデックスも受け取れ、辞書に要素を追加させられます。例

define config.tag_layer["eileen"] = "master"

= に加えて、define はあと2つのオペレーターを受け取れます。 += オペラーターは追加で、一般的にリストの連結に使用されます。 |= オペレーターは一般的にセットの連結に使用されます。例

define config.keymap["dismiss"] += [ "K_KP_PLUS" ]
define endings |= { "best_ending }

define ステートメントを使用する利点の 1 つは代入が行なわれたファイル名と行番号を記録し、ランチャーのナビゲーション機能が利用可能になることです。もう一つの利点は Lint で例えば、同じ変数が2重定義されているかを検出して、異なる値を持つ定義された変数を確認できることです。

define ステートメントを使用して定義された変数は定数として扱われ、セーブロードされないため、変更しないべきです。この定数の性質はフィールドアクセスや添え字によってそれらの変数からアクセス出来るオブジェクトまで拡張されます(Ren'Py はこれを強制しませんが、守らない場合、未定義の動作をします)。

default ステートメント link

default ステートメントは、ゲーム開始時かロード後に変数が定義されていなければその変数の値を設定します。例えば

default points = 0

変数 points がゲーム開始時に定義されていなければ、このステートメントは次と等しいです。

label start:
    $ points = 0

変数 points がゲームロード時に定義されていなければ、次と等しいです。

label after_load:
    $ points = 0

default ステートメントはドットと変数名を続けて任意で名前付き store (以下参照) も受け取れます。その store がなければ作成されます。例

default schedule.day = 0

define ステートメントと同じで Lintdefault ステートメントに対するチェックと最適化を提供します。

init offset ステートメント link

init offset ステートメントは初期化時に実行するすべてのステートメント ( init, init python, define, default, screen, transform, style, など ) に対して優先度のオフセットを設定します。オフセットは現在のブロックとコードブロック内のすべての後続のステートメントに次の優先度ステートメントが来るまで適応されます。例

init offset = 42

このコードでは優先度のオフセットを 42 に設定しています。

init offset = 2
define foo = 2

init offset = 1
define foo = 1

init offset = 0

最初の deffine ステートメントは優先度 2 で実行されるので 二つ目の define ステートメントの後に実行されます。 foo は 2 の値になります。

Store の名前 link

Ren'Py が Python 変数を格納するデフォルトの場所は store と呼ばれます。 store で使用する名前が衝突しないかの確認は重要です。

define ステートメントは値を、それがキャラクターの定義に使用されていても変数に代入します。つまりキャラクターとフラグに同じ名前は使用出来ません

以下のコードには欠陥があります。

define e = Character("Eileen")

label start:

    $ e = 0

    e "Hello, world."

    $ e += 1
    e "You scored a point!"

これは変数 e がキャラクターとフラグの両方に使用されているため動作しません。通常 store に格納されるその他の物にはトランジションと transform があります。。

アンダースコア "_" で初まる名前は Ren'Py 内部で使用するものとして扱われます。詳しくは以下を参照してください。 Index of Reserved Names

その他の名前付き store link

名前付きの store はpython コードをモジュールに分ける方法を提供します。モジュールにコードを置くと名前が衝突する機会を減らせます。

名前付きの store は in 節を pythoninit python に与えるとアクセス可能で、コードは名前付き store で実行されます。各 store は python モジュールに対応します。デフォルトのstore は store で、名前付きの store は store.name でアクセスされます。モジュール内の名前は python の from ステートメントを使用してインポート出来ます。名前付き store は init python in ブロックや default, define ステートメントを使用して作成できます。

init python in mystore:

    serial_number = 0

    def serial():

        global serial_number
        serial_number += 1
        return serial_number

default character_stats.chloe_substore.friends = {"Eileen",}

label start:
    $ serial = mystore.serial()

    if "Lucy" in character_stats.chloe_substore.friends:
        chloe "Lucy is my friend !"
    elif character_stats.chloe_substore.friends:
        chloe "I have friends, but Lucy is not one of them."

名前付きの store はデフォルトの store 同様にセーブロード、ロールバックに参加します。 persistent, config, renpy などのような特別な名前空間はそうではなく、その中への substore 作成もサポートしません。

本体、サードパーティーの Python モジュールとパッケージ link

Ren'Py は純粋な python モジュールとパッケージをインポートできます。ゲームのために書かれた本体のモジュールとパッケージは game ディレクトリーに直接配置されます。サードパーティーのパッケージは game/python-packages ディレクトリーに配置できます。

例えば必要なパッケージをインストールするにはゲームのベースディレクトリーを自環境に合わせて次のコマンドを実行します。

pip install --target game/python-packages requests

モジュールとパッケージどちらでも init python ブロックからインポート出来ます。

init python:
    import requests

警告

.rpy ファイルで定義された Python コードは、ロールバックで動作するために変換されます。 .py ファイルからインポートされた Python コードは変換されません。そのため、 python コードで作成されたオブジェクトはロールバックで動作しないので、作成後は変更するべきではありません。