2023-11-21に更新

Godot でノードパスを気にせずにシーン・ビューでノードを移動したいぜ(^~^)

親記事から来た

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

情報

📖 Git Hub / きふわらべRPG、他
📺 Discord サーバー 招待 / きふわらべRPG

はじめに

202311__shogi__21-1906--folder-o2o0.png

ramen-tabero-futsu2.png
「 👆 フォルダーを自由に作って そこにノードを移動できるようにしたいぜ。
そのとき パスも リンク切れしないようにしたいぜ」

ohkina-hiyoko-futsu2.png
「 Godot エディター上で 移動すれば リンクは切れないんじゃないの?」

ramen-tabero-futsu2.png
「 ノードパスの仕様が難しい。もっと適当に ノードを移動したい」

202311__shogi__21-1919--node-path-o2o0.png

ramen-tabero-futsu2.png
「 👆 このような ハードコーティングしたノードパスを 自動で修正してくれる仕掛けが
Godot には あるらしいぜ」

kifuwarabe-futsu.png
「 やってみろだぜ」

202311__shogi__21-1925--node-moved.png

ramen-tabero-futsu2.png
「 👆 こんな風に ノードを移動しても、さっきのノードパスは 自動で変更されるといったことはないぜ」

変更案

#func hub():
#   return $"../../🛩️ScenarioWritersHub"


# シナリオライターズ・ハブ取得
func hub():
    var cur_node = $".."

    while cur_node != null:
        if cur_node.has_node("🛩️ScenarioWritersHub"):
            return cur_node.get_node("🛩️ScenarioWritersHub")

        cur_node = cur_node.get_parent()

    return null

ramen-tabero-futsu2.png
「 👆 例えば 上記のように書きかえれば 親をさかのぼって探してくれるぜ」

kifuwarabe-futsu.png
「 キャッシュした方が よくないか?」

var cached_hubs = {}

# シナリオライターズ・ハブ取得
func hub():
    var target = "🛩️ScenarioWritersHub"

    if target in self.cached_hubs:
        return self.cached_hubs[target]

    var cur = $".."

    while cur != null:
        if cur.has_node(target):
            var hub = cur.get_node(target)
            self.cached_hubs[target] = hub
            return hub

        cur = cur.get_parent()

    return null

ramen-tabero-futsu2.png
「 👆 じゃあ こうだぜ」

モジュール化

ohkina-hiyoko-futsu2.png
「 そのコードを使い回せるようにしたら いいんじゃない?」

📄 monkey.gd:

extends Object


class_name Monkey


# ーーーーーーーー
# メモリ関連
# ーーーーーーーー


var cached_ancestor_children = {}


# ーーーーーーーー
# 親パス関連
# ーーーーーーーー


# 親の直下の子を調べる。なければ、祖先の直下の子を調べる
func find_ancestor_child(
        current_node,       # Node
        target_node_name):  # StringName

    var cur = current_node
    var target = str(target_node_name)

    if target in self.cached_ancestor_children:
        return self.cached_ancestor_children[target]

    while cur != null:
        if cur.has_node(target):
            var hub = cur.get_node(target)
            self.cached_ancestor_children[target] = hub
            return hub

        cur = cur.get_parent()

    return null

ramen-tabero-futsu2.png
「 👆 じゃあ monkey.gd を作るぜ」

# ーーーーーーーー
# メモリ関連
# ーーーーーーーー


var monkey = Monkey.new()


# ーーーーーーーー
# 親パス関連
# ーーーーーーーー


# シナリオライターズ・ハブ取得
func hub():
    return monkey.find_ancestor_child(
            self,
            "🛩️ScenarioWritersHub")

ramen-tabero-futsu2.png
「 👆 あとは それを使うだけだぜ」

トレードオフ

ohkina-hiyoko-futsu2.png
「 ノードの置き場所が自由になった分、
ノードパスによるノードの識別が できなくなるわね」

ramen-tabero-futsu2.png
「 運用でカバーしろだぜ」

フォルダーの深い所に置いたから、探索しろだぜ

ramen-tabero-futsu2.png
「 しまった!」

📄 scenario_writers_hub.gd :

# 指定の部門下の scenario_document 辞書を全てマージして返します。
# この処理は、最初の1回は動作が遅く、その1回目でメモリを多く使います
func get_merged_scenario_document(department_name):
    if not (department_name in self.cached_scenario_document):
        var book_node = self.get_scenario_writer().get_node(str(department_name))
        self.cached_scenario_document[department_name] = {}

        # 再帰。結果は外部変数に格納
        self.search_merged_scenario_document(department_name, book_node)

    return self.cached_scenario_document[department_name]


func search_merged_scenario_document(department_name, current_node):
    for child_node in current_node.get_children():
        if "scenario_document" in child_node:
            self.cached_scenario_document[department_name].merge(child_node.scenario_document)

        # 再帰。結果は外部変数に格納
        self.search_merged_scenario_document(department_name, child_node)

ramen-tabero-futsu2.png
「 👆 フォルダーの下まで 再帰的に探索するコードを書いてないぜ」

📄 programs_hub.gd :

# 全ての部門名一覧
func get_all_department_names():
    if self.cached_all_department_names == null:
        self.cached_all_department_names = []   # StringName の配列

        # 結果は変数に格納される
        self.search_all_department_names(
                self.get_scenario_writer())

    return self.cached_all_department_names


# 結果は変数に格納される
func search_all_department_names(current_node):
    for child_node in current_node.get_children():
        # 部門のノード名は `📗` で始まるものとする
        if child_node.name.begins_with("📗"):
            self.cached_all_department_names.append(child_node.name)

        # `📂` で始まるノード名は、さらにその中も再帰的に探索されるものとする
        elif child_node.name.begins_with("📂"):
            self.search_all_department_names(child_node)

📄 scenario_writers_hub :

# 指定の部門下の scenario_document 辞書を全てマージして返します。
# この処理は、最初の1回は動作が遅く、その1回目でメモリを多く使います
func get_merged_scenario_document(department_name):
    # キャッシュになければ探索
    if not (department_name in self.cached_scenario_document):

        # [📗~]ノードの位置が変わっていることがあるので探索する
        var book_node = self.search_scenario_book_node(
                self.get_scenario_writer(),
                str(department_name))
        self.cached_scenario_document[department_name] = {}

        # 再帰。結果は外部変数に格納
        self.search_merged_scenario_document(department_name, book_node)

    return self.cached_scenario_document[department_name]


# [📗~]ノードを探索
func search_scenario_book_node(
        current_node,
        department_name_str):
    if current_node.has_node(department_name_str):
        return current_node.get_node(department_name_str)

    for child_node in current_node.get_children():
        var book_node = self.search_scenario_book_node(
                child_node,
                department_name_str)

        if book_node != null:
            return book_node


func search_merged_scenario_document(department_name, current_node):
    for child_node in current_node.get_children():
        if "scenario_document" in child_node:
            self.cached_scenario_document[department_name].merge(child_node.scenario_document)

        # 再帰。結果は外部変数に格納
        self.search_merged_scenario_document(department_name, child_node)

ramen-tabero-futsu2.png
「 👆 まず 部門名を再帰的に探すことにするぜ。
📗 で始まるノード名なら 部門名、
📂 で始まる名前のノードなら、その中を探索されるぜ」

202311__shogi__21-2146--folder-2o0.png

ramen-tabero-futsu2.png
「 👆 これで フォルダーの中に 台本を置いて 任意に整理できるようになったぜ」

ohkina-hiyoko-futsu2.png
「 任意に置くことができるフォルダーと、
置く場所が決まってるフォルダーのアイコンを 変えた方がよくない?」

202311__shogi__21-2226--globe.png

ramen-tabero-futsu2.png
「 👆 固定のディレクトリーのアイコンをグローブ(Globe;地球)に変えたぜ。
ハブ(Hub;中心地)が飛行機なんで、合うぜ」

kifuwarabe-futsu.png
「 ストII のキャラクター選択画面のイメージだろ」

202311__shogi__21-2303--addon.png

ramen-tabero-futsu2.png
「 👆 📂Imported より、 📂Addon の方がイメージをつかめるか。変えたろ」

親記事へ戻る

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

.

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

むずでょ

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

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

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

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

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

コメント