查看: 83|回复: 7

[讨论] 【随缘更新】Godot 小知识

[复制链接]

38

主题

731

回帖

13

精华

版主

经验
7466
硬币
1182 枚

赞助用户永吧十五周年建吧日纪念勋章永吧十五周年倒计时海报勋章第五届MW杯亚军对不起,小姐盲猜大王数字君X68数字君X68数字君X78

发表于 5 天前 来自手机 | 显示全部楼层 |阅读模式
不如说是踩坑记录。
Moonstruck Blossom
个人网站:dasasdhba.github.io

38

主题

731

回帖

13

精华

版主

经验
7466
硬币
1182 枚

赞助用户永吧十五周年建吧日纪念勋章永吧十五周年倒计时海报勋章第五届MW杯亚军对不起,小姐盲猜大王数字君X68数字君X68数字君X78

 楼主| 发表于 5 天前 | 显示全部楼层
1. export NodePath 和 export Node 的区别

乍一看从编辑器体验上两者没有区别,而且后者写代码更方便,似乎是前者的上位替代,但其实这俩有点区别。
NodePath 变量存的是相对路径,而 Node 变量存的则是绝对的 Node
当你想要 duplicate 一整个 Node 的时候,区别就体现出来了:NodePath 变量在 duplicate 之后存的仍然是相对路径,而 Node 变量在 duplicate 之后,指向的仍然是 duplicate 之前指向的那个老 Node

总之,在使用相关功能的时候,请衡量自己想要的到底是相对路径关系,还是绝对的引用。

点评

本质上export Node应该是特殊的export NodePath,只不过内部应该是自行封装了一个安全的get_node()  发表于 4 天前
duplicate以后还指向老node的那个应该是bug,前段时间在pr上看到过,在4.3被修了  发表于 4 天前
Moonstruck Blossom
个人网站:dasasdhba.github.io

38

主题

731

回帖

13

精华

版主

经验
7466
硬币
1182 枚

赞助用户永吧十五周年建吧日纪念勋章永吧十五周年倒计时海报勋章第五届MW杯亚军对不起,小姐盲猜大王数字君X68数字君X68数字君X78

 楼主| 发表于 5 天前 | 显示全部楼层
2. 碰撞检测时,想好是 A 检测 B 还是 B 检测 A

让大量的砖块每个单独去检测有没有受到攻击,和让攻击判定去检测有没有碰到砖块,这两种方式的性能差异是巨大的
通常来说,一定要想好哪些对象更加适合作为发起碰撞检测的一方,不要怕麻烦,尤其是砖块特别多的时候

这一条不仅限于 Godot,任何游戏引擎都需要注意此问题。

点评

mitf坦克.jpg  发表于 5 天前
Moonstruck Blossom
个人网站:dasasdhba.github.io

38

主题

731

回帖

13

精华

版主

经验
7466
硬币
1182 枚

赞助用户永吧十五周年建吧日纪念勋章永吧十五周年倒计时海报勋章第五届MW杯亚军对不起,小姐盲猜大王数字君X68数字君X68数字君X78

 楼主| 发表于 5 天前 | 显示全部楼层
3. 通过 metadata 进行通信

试想下列情形:你为了不把逻辑和物理耦合在一块,选择通过子节点 C 来操控物理根节点 A
现在,你希望另一个物理节点 B 与节点 A 发生碰撞时,调用其子节点 C 的相关函数
但是,物理节点 B 只能得到节点 A 的引用,并不能直接得到子节点 C 的引用
你可能首先想到了 get_node(path_to_c),但这样一来,你又把节点树的结构耦合到了一起

metadata 可以解决这个难题,其实这就是 godot node 都有的一个 Dictionary<string, Variant>
只需要在子节点 C 初始化时,将其自身的引用存储到 A 的 metadata 中
B 就可以在拿到节点 A 之后,通过 metadata 作进一步判断,以及拿到节点 C 的引用
Moonstruck Blossom
个人网站:dasasdhba.github.io

56

主题

415

回帖

8

精华

版主

☯ 博 丽 不 是 灵 梦 ☯

经验
6186
硬币
1047 枚

赞助用户永吧十五周年建吧日纪念勋章永吧十五周年倒计时海报勋章

发表于 4 天前 | 显示全部楼层
dasasdhba 发表于 2024-5-14 23:40
3. 通过 metadata 进行通信

试想下列情形:你为了不把逻辑和物理耦合在一块,选择通过子节点 C 来操控物理 ...

其实根据官方对SceneTree优化的表述,结合metadata存引用这个特性,可以在初始化组件节点C的时候顺带把组件节点C移出场景树(其实就是主循环要遍历的节点变少了,自然便流畅了)
需要注意的是:上述操作只有在组件节点C里没有_process()或_physics_process()时才能保证安全,不然后两者在节点树外是没法运作的。
另外,如果只是将其移出节点树外,那么在中心节点A调用queue_free()的时候,组件节点C并不会被删除,这个时候可以下代码:

  1. func _ready() -> void:
  2.     var par := get_parent()
  3.     assert(par != null, "The component %s does not have a operatee!" % name)
  4.     par.tree_exited.connect(func() -> void:
  5.         if par.is_queue_deletion():
  6.             queue_free()
  7. )
复制代码

不过上述代码也有个缺陷,就是如果用户是通过free()来删除节点的话那么is_queue_deletion()就会不起作用,从而导致组件无法删除,残留在内存当中,造成内存泄漏。这个时候最好的方法就是自己写一个delete()静态方法,在删除对象的同时也删除掉与其相关联的组件
>❀ To the Best You ❀<
您需要登录后才可以回帖 登录 | 创建账户

本版积分规则