32blogby StudioMitsu
renpy11 min read

Ren'Pyの選択肢と分岐:menuからマルチエンディングまで

Ren'Py 8.5のmenu文、jump/callの使い分け、フラグ管理、条件付き選択肢、マルチエンディング実装まで解説。

renpyvisual-novelgame-devbeginner
目次

ビジュアルノベルの面白さは「選択」にある。プレイヤーの選んだ道でストーリーが変わるからこそ、繰り返し遊びたくなる。

この記事では、Ren'Py 8.5.2 で選択肢と分岐を実装する方法を、基本の menu 文からマルチエンディングまで解説する。

menu 文はプレイヤーに選択肢を提示し、選んだ結果に応じて処理を分岐させる。

renpy
label start:
    "道が二手に分かれている。"

    menu:
        "どちらに進む?"

        "左の道へ":
            "左の道を選んだ。森が広がっている。"

        "右の道へ":
            "右の道を選んだ。川が見えてきた。"

    "旅は続く。"

menu: の直下に書いた文字列("どちらに進む?")はキャプションとして表示される。その下の各文字列が選択肢になる。選択肢のブロック内に、選ばれたときの処理を書く。

選択肢のブロックが終わると、menu の後の行("旅は続く。")に合流する。どの選択肢を選んでも、ここに戻ってくる。

キャラクターに質問させる

キャプションの代わりに、キャラクターのセリフとして質問を出すこともできる。

renpy
define e = Character("エイリーン")

label start:
    menu:
        e "どっちがいい?"

        "お茶":
            e "お茶だね。"

        "コーヒー":
            e "コーヒーだね。"

e "どっちがいい?" と書くと、エイリーンのセリフとして表示された後に選択肢が出る。

jumpとcallの使い分け

選択肢の中身が長くなってきたら、jumpcall で別の label に処理を移す。この2つは似ているが、戻ってくるかどうか が決定的に違う。

jump — 一方通行

renpy
label start:
    menu:
        "どちらに進む?"

        "森へ":
            jump forest_route

        "街へ":
            jump town_route

label forest_route:
    "森の奥深くへ進んだ。"
    jump chapter_2

label town_route:
    "賑やかな街に着いた。"
    jump chapter_2

label chapter_2:
    "第2章が始まる。"

jump は指定した label に飛び、元の場所には戻らない。ルート確定後の遷移やエンディングへのジャンプに使う。

call — 行って帰ってくる

renpy
label start:
    "冒険の準備をしよう。"

    call shop

    "買い物を終えて旅に出発した。"

label shop:
    "何を買う?"

    menu:
        "剣を買う":
            $ has_sword = True
        "盾を買う":
            $ has_shield = True

    return

call は指定した label に飛び、return で呼び出し元に戻る。共通シーン(ショップ、ミニゲーム、回想)など、複数の場所から呼び出したい処理に使う。

比較表

jumpcall
戻る戻らないreturn で戻る
用途ルート分岐、エンディング共通シーン、サブルーチン
スタック積まない積む(return で消化)

フラグで分岐を管理する

選択肢の結果を変数(フラグ)に保存しておくと、後のシーンで参照できる。

フラグの宣言

renpy
# default で宣言(セーブファイルに保存される)
default met_fairy = False
default affection = 0

label start:
    menu:
        "妖精に話しかける?"

        "話しかける":
            $ met_fairy = True
            $ affection += 10
            "妖精と友達になった。"

        "無視する":
            "そのまま通り過ぎた。"

フラグは必ず default で宣言する。default で宣言した変数はセーブファイルに保存され、ロード時に正しく復元される。

フラグを使った分岐

renpy
label chapter_2:
    if met_fairy:
        "あの時の妖精が現れた。"
        $ affection += 5
    else:
        "見知らぬ妖精が現れた。"

    if affection >= 10:
        "妖精はあなたに微笑んだ。"
    else:
        "妖精は警戒している。"

if/elif/else で変数の値に応じて表示するテキストやイベントを切り替える。

条件付き選択肢

選択肢自体に if 条件を付けると、条件を満たしたときだけその選択肢が表示される。

renpy
default has_key = False

label locked_door:
    "鍵のかかった扉がある。"

    menu:
        "鍵を使う" if has_key:
            "扉が開いた。"
            jump secret_room

        "引き返す":
            "別の道を探すことにした。"

has_keyFalse のとき、「鍵を使う」は選択肢に表示されない。プレイヤーには「引き返す」しか見えない。

選べない選択肢をグレーアウトで見せる

条件未達成の選択肢を非表示にするのではなく、グレーアウトして「存在するが選べない」と示したい場合がある。

renpy
init python:
    config.menu_include_disabled = True

label locked_door:
    menu:
        "鍵を使う" if has_key:
            "扉が開いた。"

        "引き返す":
            "別の道を探すことにした。"

config.menu_include_disabled = True を設定すると、条件を満たさない選択肢がグレーアウト状態で表示される。プレイヤーに「別の条件を満たせば選べる」というヒントを与えられる。

一度選んだ選択肢を除外する

set を使うと、すでに選んだ選択肢をメニューから自動的に除外できる。

renpy
default explored = set()

label explore:
    "どこを調べる?"

    menu:
        set explored

        "机の上":
            "手紙が見つかった。"

        "本棚":
            "古い日記が見つかった。"

        "窓の外":
            "誰かの影が見えた。"

    if len(explored) < 3:
        jump explore
    else:
        "すべて調べ終えた。"

マルチエンディングを実装する

ここまでの知識を組み合わせて、マルチエンディングを実装してみよう。

ポイント型:好感度で分岐

プレイヤーの選択に応じてポイントを加減し、最終的な値でエンディングを決める。

renpy
default affection = 0

label start:
    "エイリーンと出会った。"

    menu:
        "挨拶する":
            $ affection += 10
            "エイリーンは嬉しそうだ。"

        "素通りする":
            "エイリーンは寂しそうだ。"

    "しばらく旅を続けた。"

    menu:
        "エイリーンを助ける":
            $ affection += 20
            "エイリーンの目が輝いた。"

        "見て見ぬふりをする":
            $ affection -= 10
            "エイリーンは失望した。"

    jump ending

label ending:
    if affection >= 20:
        jump good_ending
    elif affection >= 0:
        jump normal_ending
    else:
        jump bad_ending

label good_ending:
    "エイリーンと固い絆で結ばれた。"
    "GOOD END"
    return

label normal_ending:
    "エイリーンとは友人のままだった。"
    "NORMAL END"
    return

label bad_ending:
    "エイリーンは去っていった。"
    "BAD END"
    return

フラグ型:特定の選択の組み合わせで分岐

ポイントではなく、特定のイベントを経験したかどうかでエンディングを決める。

renpy
default saved_cat = False
default found_letter = False

label start:
    menu:
        "猫を助ける":
            $ saved_cat = True
        "通り過ぎる":
            pass

    menu:
        "手紙を読む":
            $ found_letter = True
        "手紙を無視する":
            pass

    jump ending

label ending:
    if saved_cat and found_letter:
        "すべての真実にたどり着いた。"
        "TRUE END"
    elif saved_cat:
        "猫が恩返しに来た。"
        "CAT END"
    elif found_letter:
        "手紙の謎を解いた。"
        "LETTER END"
    else:
        "何も見つけられなかった。"
        "NORMAL END"
    return

実際のゲームでは、ポイント型とフラグ型を組み合わせて使うことが多い。好感度でメインルートを決め、フラグで細かいバリエーションを出すのが定番のパターンだ。

まとめ

この記事で解説したこと:

  • menu文: 選択肢の基本構文。キャプションやキャラクターのセリフで質問を出せる
  • jump vs call: jump は一方通行、callreturn で戻れる。共通シーンには call を使う
  • フラグ管理: default で変数を宣言し、選択結果を保存する
  • 条件付き選択肢: if 条件で表示/非表示を制御。config.menu_include_disabled でグレーアウト表示
  • マルチエンディング: ポイント型(好感度)とフラグ型(イベント経験)の2パターン

Ren'Pyの基本は 入門ガイド を、変数の管理については 変数管理ガイド を、UIの作り方は screen言語入門 を参照してほしい。

公式リソース: