Godot中基于子节点动态创建属性列表的实现困惑
解决Godot动态生成属性列表的问题
一、先修复_get/_set的无限循环问题
你之前的实现没有处理非动态属性的情况,导致Godot访问节点内置属性(比如name、position)时也会进入你的_get/_set,进而引发报错或无限递归。修改成下面这样:
var propertyHolder = {} func _get(key): if propertyHolder.has(key): return propertyHolder[key] # 交给父类处理其他属性 return super._get(key) func _set(key, value): if propertyHolder.has(key): propertyHolder[key] = value return true # 交给父类处理其他属性 return super._set(key, value)
二、动态收集子节点的属性定义
让每个子节点暴露自己需要的属性信息,父节点遍历收集后返回给编辑器:
- 子节点侧:定义返回属性列表的方法
# 子节点脚本 func get_dynamic_properties(): # 返回该子节点需要的属性信息,比如枚举类型 return [ PropertyInfo(Variant.INT, "weapon_type", PROPERTY_HINT_ENUM, "Sword,Bow,Staff"), PropertyInfo(Variant.BOOL, "is_blessed") ] # 子节点本地存储属性值 var _local_props = { "weapon_type": 0, "is_blessed": false }
- 父节点侧:重写
_get_property_list收集所有子节点的属性
# 父节点脚本 func _get_property_list(): var props = [] # 先继承父类的属性列表 props.append_array(super._get_property_list()) # 遍历所有子节点,收集动态属性 for child in get_children(): if child.has_method("get_dynamic_properties"): props.append_array(child.get_dynamic_properties()) return props
三、优化属性存储与访问(可选,更符合组合性)
如果不想父节点统一管理所有属性,可以把属性存储放到子节点本地,父节点仅做转发:
# 父节点的_get/_set修改为转发给子节点 func _get(key): for child in get_children(): if child.has_method("get_dynamic_property"): var val = child.get_dynamic_property(key) if val != null: return val return super._get(key) func _set(key, value): for child in get_children(): if child.has_method("set_dynamic_property"): if child.set_dynamic_property(key, value): return true return super._set(key, value)
# 子节点实现对应的方法 func get_dynamic_property(key): return _local_props.get(key, null) func set_dynamic_property(key, value): if _local_props.has(key): _local_props[key] = value # 可选:属性变化时触发子节点逻辑 _on_property_changed(key, value) return true return false func _on_property_changed(key, value): # 子节点自己处理属性变化后的逻辑 match key: "weapon_type": print("武器类型切换为: ", value)
四、编辑器属性列表刷新
当子节点添加/移除时,需要通知编辑器更新属性面板:
# 父节点脚本 func _ready(): notify_property_list_changed() # 监听子节点变化事件 connect("child_entered_tree", self, "_on_child_tree_changed") connect("child_exiting_tree", self, "_on_child_tree_changed") func _on_child_tree_changed(child): notify_property_list_changed()
内容的提问来源于stack exchange,提问作者epic man
相关产品推荐
相关产品推荐

