2023-10-05に更新

Godot でシナリオの分岐を作ろうぜ(^~^)?

親記事から来た

📖 Godot って何だぜ(^~^)?

はじめに

202310__godot__04-1944--Choices.png

ramen-tabero-futsu2.png
「 👆 選択肢までは 出るのだった」

ohkina-hiyoko-futsu2.png
「 その選択肢を選んだあと 次の会話に つながってほしいのよ」

ramen-tabero-futsu2.png
「 多分、それは メッセージ・ウィンドウの仕事ではなくて、
メッセージ・ウィンドウへ メッセージを手配してくる 交換手か何かの仕事だな」

kifuwarabe-futsu.png
「 ストーリーテラー(storyteller;語り部)のようなクラスでも 作るかだぜ?」

ramen-tabero-futsu2.png
「 シナリオプレイヤー(Scenario Player;シナリオ再生機)ぐらいの造語でいいかな」

シナリオプレイヤーを作ろう

202310__godot__04-2028--ScenarioPlayer.png

ramen-tabero-futsu2.png
「 👆 じゃあ 空っぽの Node をベースに シナリオプレイヤーを作ってしまおう。
細かいことは これから詰めていこう」

kifuwarabe-futsu.png
「 なんでもかんでも オートマトン(Automaton;自動人形)と同じように作ればいいんだろ。
ステートマシーンを持たせろだぜ」

📄 ScenarioPlayerStatemachine.gd:

# シナリオ・プレイヤー・ステートマシーン(Scenario Player Statemachine;台本再生機状態遷移図)
extends Node

class_name ScenarioPlayerStatemachine

#  状態遷移図
#  ーーーーー
#
#          +ーーーーー+
#          | はじめ |
#          +ーー+ーー+
#             |
#             |
# +ーーーーーーーーーー>+
# |           |
# |           V
# |       +ーーーーーーー+
# |       | 0.停止中 |
# |       +ーーー+ーーー+
# |           |
# |           | 再生 #ステートマシーン外部からの開始の合図。段落番号を渡される
# |           |
# |   +ーーーーーー>+
# |   |       |
# |   |       V
# |   |   +ーーーーーーー+
# |   |   | 1.再生中 |
# |   |   +ーーー+ーーー+
# |   |       |
# |   |       |
# |   |       |
# |   +ーーーー<ーー+ 再生 #別の段落番号が書かれていた
# |        はい |
# |           |
# +ーーーーーーーーーーー+ 停止 #段落が終わった
#
enum States {None, Playing}

# 状態
var state = States.None

# 停止中か?
func is_none(): 
    return self.state == States.None

# 再生中か?
func is_playing():
    return self.state == States.Playing

# 再生
func play(paragraph_no):
    print("[ステートマシーン] パラグラフの再生")
    self.state = States.Playing

# 停止
func stop(paragraph_no):
    print("[ステートマシーン] 停止")
    self.state = States.None

ramen-tabero-futsu2.png
「 👆 こんなもんかだぜ?」

シナリオプレイヤーにステートマシーンを実装しろだぜ

kifuwarabe-futsu.png
「 そのステートマシーンを シナリオプレイヤーに実装しろだぜ」

📄 ScenarioPlayer.gd:

# シナリオプレイヤー(Scenario Player;台本再生機)
extends Node

# 状態遷移機械
var statemachine = load("scripts/ScenarioPlayerStatemachine.gd").new()


# Called when the node enters the scene tree for the first time.
func _ready():
    pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
    if self.statemachine.is_none():
        # 停止中
        #   何もしない
        pass

    elif self.statemachine.is_playing():
        # 再生中
        #   何もしない
        pass

ramen-tabero-futsu2.png
「 👆 ひとまず こんなもんかだぜ?」

ohkina-hiyoko-futsu2.png
「 シナリオプレイヤーは 自律的に動くといっても、
起動の合図は 外部から与えるのよね?」

ramen-tabero-futsu2.png
「 そうだぜ。 監督 が指示してなければ まだ動くなだぜ」

ohkina-hiyoko-futsu2.png
「 じゃあ 本当に自律的に動く 監督 が必要なんじゃないの?」

ramen-tabero-futsu2.png
「 監督も作るか~」

202310__godot__04-2232--DirectorNode.png

ramen-tabero-futsu2.png
「 👆 ルート・ノードの名前を Director にしたった」

ohkina-hiyoko-futsu2.png
「 合理的ねえ」

📄 Director.gd:

# ディレクター(Director;監督)
#   とりあえず、ゲーム全体をコントロールする
extends Node2D

# Called when the node enters the scene tree for the first time.
func _ready():
    # シナリオ・ブックから、内容を取出す
    print("[2Dプロジェクト] シナリオ・ブックから、内容を取出す")
    var scenario_array = $"./ScenarioBook".scenario_array

    # シナリオプレイヤーへ、内容を渡す
    print("[2Dプロジェクト] シナリオプレイヤーへ、内容を渡す")
    $"./ScenarioPlayer".set_scenario_array(scenario_array)

ramen-tabero-futsu2.png
「 👆 監督のスクリプトの雰囲気は こんな感じになるはずだぜ」

シナリオに段落番号を振りましょう!

ohkina-hiyoko-futsu2.png
「 シナリオブックの 各部分に パラグラフ(Paragraph;段落)番号を振れない?」

ramen-tabero-futsu2.png
「 リストではなく マップが必要だな。 Godot にマップはあるのかだぜ?」

kifuwarabe-futsu.png
「 👇 Dictionary という名前で有るぜ」

📖 Godot Engine / Dictionary

ramen-tabero-futsu2.png
「 調べてみるか……」

📄 ScenarioBook.gd:

# 段落番号を指定して、段落を取得
func get_paragraph(paragraph_code):
    return self.document[paragraph_code]

ramen-tabero-futsu2.png
「 👆 段落番号を指定して、段落を取得できるメソッドを作っておくぜ。
あとで 1.2.3 みたいな段落番号を使いたいので、番号は文字列にしておくぜ」

202310__godot__04-2304--ScenarioDocument.png

ramen-tabero-futsu2.png
「 👆 インデント2つが もったいない気がするが、
普通の書き方を優先し、上図のように セリフを並べることにするぜ」

202310__godot__04-2316--Paragraph_1.png

ramen-tabero-futsu2.png
「 👆 こんな風に パラグラフを追加していくものとしようぜ」

ohkina-hiyoko-futsu2.png
「 選択肢の1番目が 段落の 1.1 に飛ぶのを どうコントロールすんの?」

ramen-tabero-futsu2.png
「 そのコントロールをするのが ScenarioPlayer だぜ」

202310__godot__05-0011--Mappings.png

ramen-tabero-futsu2.png
「 👆 こんな感じでマッピングするんだが、なんかよく分からないな」

ohkina-hiyoko-futsu2.png
「 どうやっても 分かんないんだから 2重の Dictionary にしたらどうなの?」

202310__godot__05-0017--MappingsDocument.png

ramen-tabero-futsu2.png
「 👆 これで分岐の最低要件は満たせるが、確かに 見ても よく分からんよな」

kifuwarabe-futsu.png
「 この設定ファイルを編集する外部エディターぐらい お父ん 作れるだろ」

ramen-tabero-futsu2.png
「 それもそうだぜ」

202310__godot__05-0031--ScenarioBook.png

ramen-tabero-futsu2.png
「 👆 段落番号も止めて、文字列にしたった」

ohkina-hiyoko-futsu2.png
「 台詞だけで できたゲームなら これでいけるけど、
戦闘シーンや、マップや、ムービーに続けたいときは どうすんの?」

ramen-tabero-futsu2.png
「 そのときは インデックスでなんとかしようぜ?」

動画

📺 動画

親記事へ戻る

📖 Godot って何だぜ(^~^)?

.

ツイッターでシェア
みんなに共有、忘れないようにメモ

むずでょ

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント