如何在没有 setter 函数的情况下创建 getter 函数?
How to create a getter function without a setter function?
我的脚本中有多个导出变量,每当更改一个变量时,我想调用一个公共 getter 并自动设置值
tool
export(float) var sample1 setget ,smthn_changed;
export(float) var sample2 setget ,smthn_changed;
export(float) var sample3 setget ,smthn_changed;
func smthn_changed():
print("something changed!")
但这不起作用,我必须为每个变量创建一个 setter
有解决办法吗?
请注意,您将这些属性的 smthn_changed
定义为 getter。 getter 是在您尝试读取它们时调用的,而不是在您尝试分配它们时调用的。
好的,假设您确实想知道何时分配变量。为此,您通常会使用 setters,如下所示:
export var property:bool setget set_property
func set_property(new_value:bool) -> void:
if property == new_value:
return
property = new_value
print("value changed") # or emit a signal or whatever
setter 会在变量被外部赋值的任何时候被调用(或者内部使用 self.property = value
,如果你不使用 self
你可以直接赋值变量而不用触发 setter).
但是,由于您需要从 setter 写入实际变量,这意味着为每个变量创建一个 setter(如果您对多个变量使用相同的 setter,你不知道要设置哪个)。
您还可以尝试其他方法:_set
。 _set
的问题是只会为未在脚本中声明的变量调用。
所以,这是计划:
- 我们将使用不同的名称声明支持变量,而不是导出它们。
- 我们将使用
_set
和 _set
来处理它们。
- 我们将使用
_get_property_list
导出它们。
让我们看看只有一个变量的情况:
tool
extends Spatial
var _x:String setget _no_set
func _set(property: String, value) -> bool:
if property == "x":
_x = value
smth_changed()
return true
return false
func _get(property: String):
if property == "x":
return _x
return null
func _get_property_list() -> Array:
if not Engine.editor_hint or not is_inside_tree():
return []
return [
{
name = "x",
type = TYPE_STRING,
usage = PROPERTY_USAGE_DEFAULT
}
]
func _no_set(_new_value) -> void:
pass
func smth_changed() -> void:
print("something changed!")
与简单的 setter 相比,这不值得付出努力。
setter _no_set
是一个什么都不做(甚至不设置变量)的 setter。我已经添加它以防止通过直接设置支持变量来从外部绕过该机制。 您可以在此处添加警告,因为这不是您的代码应该做的事情。另一方面,您的代码不应该这样做的事实也可以被视为反对 _no_set
.
的论据
但让我们看看它如何扩展到多个变量:
tool
extends Spatial
var _x:String setget _no_set
var _y:String setget _no_set
func _set(property: String, value) -> bool:
match property:
"x":
_x = value
"y":
_y = value
_:
return false
smth_changed()
return true
func _get(property: String):
match property:
"x":
return _x
"y":
return _y
return null
func _get_property_list() -> Array:
if not Engine.editor_hint or not is_inside_tree():
return []
return [
{
name = "x",
type = TYPE_STRING,
usage = PROPERTY_USAGE_DEFAULT
},
{
name = "y",
type = TYPE_STRING,
usage = PROPERTY_USAGE_DEFAULT
}
]
func _no_set(_new_value) -> void:
pass
func smth_changed() -> void:
print("something changed!")
仍然不太好,因为我们不得不多次重复变量。我仍然希望有多个 setter,即使它们都有相同的代码。
任意一组属性的通用情况很棘手,因为从 _get
调用 get
,或从 _set
调用 set
,或 get_property_list
以导致堆栈溢出的方式形成 _get_property_list
将使 Godot 崩溃(并在打开项目时继续崩溃)。 所以写这段代码的时候要小心。
为了避免从 _get_property_list
调用 get_property_list
,我要做的是将我们想要的属性放入字典中:
tool
extends Spatial
var _properties := {
"x": "",
"y": ""
} setget _no_set, _no_get
func _set(property: String, value) -> bool:
if _properties.has(property):
_properties[property] = value
smth_changed()
return true
return false
func _get(property: String):
if _properties.has(property):
return _properties[property]
return null
func _get_property_list() -> Array:
if not Engine.editor_hint or not is_inside_tree():
return []
var result := []
for property_name in _properties.keys():
result.append(
{
name = property_name,
type = typeof(_properties[property_name]),
usage = PROPERTY_USAGE_DEFAULT
}
)
return result
func _no_set(_new_value) -> void:
pass
func _no_get():
return null
func smth_changed() -> void:
print("something changed!")
另请注意,我正在根据 typeof
的值报告类型。
我会留给您来决定这种方法是否值得付出努力。例如,如果变量集可以更改,则可能是这样。 我提醒你,你可以调用 property_list_changed_notify
以便 Godot 调用 _get_property_list
并使用新的属性集更新检查面板。
尽管 _no_set
,仍然可以从外部读取和操作字典。所以我添加了一个 getter _no_get
returns null 来防止这种情况发生。 如果您喜欢 _no_set
中的警告,您可能也想要 _no_get
中的警告。
附录:这是一个变体,它使用数组来存储要导出的属性的名称。这样你仍然可以有常规变量而不是处理字典。保持阵列最新由您决定。
tool
extends Spatial
var _property_names := ["x", "y"] setget _no_set, _no_get
var _x:String
var _y:String
func _set(property: String, value) -> bool:
if _property_names.has(property):
set("_" + property, value)
smth_changed()
return true
return false
func _get(property: String):
if _property_names.has(property):
return get("_" + property)
return null
func _get_property_list() -> Array:
if not Engine.editor_hint or not is_inside_tree():
return []
var result := []
for property_name in _property_names:
if not "_" + property_name in self:
push_warning("Not existing variable: " + property_name)
continue
result.append(
{
name = property_name,
type = typeof(get("_" + property_name)),
usage = PROPERTY_USAGE_DEFAULT
}
)
return result
func _no_set(_new_value) -> void:
pass
func _no_get():
return null
func smth_changed() -> void:
print("something changed!")
请注意,我添加了一个检查以防止在没有支持变量的情况下导出,这也会发出警告。公开它们并不是灾难性的,因为它们只会被视为 null。
另请注意,我必须从该版本的变量中删除 _no_set
。原因是我用 set
设置它们,这导致调用 setter,并且由于 _no_set
没有设置变量,结果是它没有保存值。
关于重置值的附录
如果你想添加那个箭头来重置你需要实现几个 (yikes) 未记录的方法的值:
func property_can_revert(property:String) -> bool:
if property in self:
return true
return false
func property_get_revert(property:String):
match typeof(get(property)):
TYPE_NIL:
return null
TYPE_BOOL:
return false
TYPE_INT:
return 0
TYPE_REAL:
return 0.0
TYPE_STRING:
return ""
TYPE_VECTOR2:
return Vector2()
TYPE_RECT2:
return Rect2()
TYPE_VECTOR2:
return Vector3()
TYPE_TRANSFORM2D:
return Transform2D()
TYPE_PLANE:
return Plane()
TYPE_QUAT:
return Quat()
TYPE_AABB:
return AABB()
TYPE_BASIS:
return Basis()
TYPE_TRANSFORM:
return Transform()
TYPE_COLOR:
return Color()
TYPE_NODE_PATH:
return NodePath()
TYPE_RID:
return RID(Object())
TYPE_OBJECT:
return Object()
TYPE_DICTIONARY:
return {}
TYPE_ARRAY:
return []
TYPE_RAW_ARRAY:
return PoolByteArray()
TYPE_INT_ARRAY:
return PoolIntArray()
TYPE_REAL_ARRAY:
return PoolRealArray()
TYPE_STRING_ARRAY:
return PoolStringArray()
TYPE_VECTOR2_ARRAY:
return PoolVector2Array()
TYPE_VECTOR3_ARRAY:
return PoolVector3Array()
TYPE_COLOR_ARRAY:
return PoolColorArray()
return null
想法是 property_can_revert
将 return true
用于任何 属性 将具有重置箭头。并且 property_get_revert
将给出单击所述箭头时将设置的值。 这必须在 source code 中找到,因为它没有记录。
我的脚本中有多个导出变量,每当更改一个变量时,我想调用一个公共 getter 并自动设置值
tool
export(float) var sample1 setget ,smthn_changed;
export(float) var sample2 setget ,smthn_changed;
export(float) var sample3 setget ,smthn_changed;
func smthn_changed():
print("something changed!")
但这不起作用,我必须为每个变量创建一个 setter
有解决办法吗?
请注意,您将这些属性的 smthn_changed
定义为 getter。 getter 是在您尝试读取它们时调用的,而不是在您尝试分配它们时调用的。
好的,假设您确实想知道何时分配变量。为此,您通常会使用 setters,如下所示:
export var property:bool setget set_property
func set_property(new_value:bool) -> void:
if property == new_value:
return
property = new_value
print("value changed") # or emit a signal or whatever
setter 会在变量被外部赋值的任何时候被调用(或者内部使用 self.property = value
,如果你不使用 self
你可以直接赋值变量而不用触发 setter).
但是,由于您需要从 setter 写入实际变量,这意味着为每个变量创建一个 setter(如果您对多个变量使用相同的 setter,你不知道要设置哪个)。
您还可以尝试其他方法:_set
。 _set
的问题是只会为未在脚本中声明的变量调用。
所以,这是计划:
- 我们将使用不同的名称声明支持变量,而不是导出它们。
- 我们将使用
_set
和_set
来处理它们。 - 我们将使用
_get_property_list
导出它们。
让我们看看只有一个变量的情况:
tool
extends Spatial
var _x:String setget _no_set
func _set(property: String, value) -> bool:
if property == "x":
_x = value
smth_changed()
return true
return false
func _get(property: String):
if property == "x":
return _x
return null
func _get_property_list() -> Array:
if not Engine.editor_hint or not is_inside_tree():
return []
return [
{
name = "x",
type = TYPE_STRING,
usage = PROPERTY_USAGE_DEFAULT
}
]
func _no_set(_new_value) -> void:
pass
func smth_changed() -> void:
print("something changed!")
与简单的 setter 相比,这不值得付出努力。
setter _no_set
是一个什么都不做(甚至不设置变量)的 setter。我已经添加它以防止通过直接设置支持变量来从外部绕过该机制。 您可以在此处添加警告,因为这不是您的代码应该做的事情。另一方面,您的代码不应该这样做的事实也可以被视为反对 _no_set
.
但让我们看看它如何扩展到多个变量:
tool
extends Spatial
var _x:String setget _no_set
var _y:String setget _no_set
func _set(property: String, value) -> bool:
match property:
"x":
_x = value
"y":
_y = value
_:
return false
smth_changed()
return true
func _get(property: String):
match property:
"x":
return _x
"y":
return _y
return null
func _get_property_list() -> Array:
if not Engine.editor_hint or not is_inside_tree():
return []
return [
{
name = "x",
type = TYPE_STRING,
usage = PROPERTY_USAGE_DEFAULT
},
{
name = "y",
type = TYPE_STRING,
usage = PROPERTY_USAGE_DEFAULT
}
]
func _no_set(_new_value) -> void:
pass
func smth_changed() -> void:
print("something changed!")
仍然不太好,因为我们不得不多次重复变量。我仍然希望有多个 setter,即使它们都有相同的代码。
任意一组属性的通用情况很棘手,因为从 _get
调用 get
,或从 _set
调用 set
,或 get_property_list
以导致堆栈溢出的方式形成 _get_property_list
将使 Godot 崩溃(并在打开项目时继续崩溃)。 所以写这段代码的时候要小心。
为了避免从 _get_property_list
调用 get_property_list
,我要做的是将我们想要的属性放入字典中:
tool
extends Spatial
var _properties := {
"x": "",
"y": ""
} setget _no_set, _no_get
func _set(property: String, value) -> bool:
if _properties.has(property):
_properties[property] = value
smth_changed()
return true
return false
func _get(property: String):
if _properties.has(property):
return _properties[property]
return null
func _get_property_list() -> Array:
if not Engine.editor_hint or not is_inside_tree():
return []
var result := []
for property_name in _properties.keys():
result.append(
{
name = property_name,
type = typeof(_properties[property_name]),
usage = PROPERTY_USAGE_DEFAULT
}
)
return result
func _no_set(_new_value) -> void:
pass
func _no_get():
return null
func smth_changed() -> void:
print("something changed!")
另请注意,我正在根据 typeof
的值报告类型。
我会留给您来决定这种方法是否值得付出努力。例如,如果变量集可以更改,则可能是这样。 我提醒你,你可以调用 property_list_changed_notify
以便 Godot 调用 _get_property_list
并使用新的属性集更新检查面板。
尽管 _no_set
,仍然可以从外部读取和操作字典。所以我添加了一个 getter _no_get
returns null 来防止这种情况发生。 如果您喜欢 _no_set
中的警告,您可能也想要 _no_get
中的警告。
附录:这是一个变体,它使用数组来存储要导出的属性的名称。这样你仍然可以有常规变量而不是处理字典。保持阵列最新由您决定。
tool
extends Spatial
var _property_names := ["x", "y"] setget _no_set, _no_get
var _x:String
var _y:String
func _set(property: String, value) -> bool:
if _property_names.has(property):
set("_" + property, value)
smth_changed()
return true
return false
func _get(property: String):
if _property_names.has(property):
return get("_" + property)
return null
func _get_property_list() -> Array:
if not Engine.editor_hint or not is_inside_tree():
return []
var result := []
for property_name in _property_names:
if not "_" + property_name in self:
push_warning("Not existing variable: " + property_name)
continue
result.append(
{
name = property_name,
type = typeof(get("_" + property_name)),
usage = PROPERTY_USAGE_DEFAULT
}
)
return result
func _no_set(_new_value) -> void:
pass
func _no_get():
return null
func smth_changed() -> void:
print("something changed!")
请注意,我添加了一个检查以防止在没有支持变量的情况下导出,这也会发出警告。公开它们并不是灾难性的,因为它们只会被视为 null。
另请注意,我必须从该版本的变量中删除 _no_set
。原因是我用 set
设置它们,这导致调用 setter,并且由于 _no_set
没有设置变量,结果是它没有保存值。
关于重置值的附录
如果你想添加那个箭头来重置你需要实现几个 (yikes) 未记录的方法的值:
func property_can_revert(property:String) -> bool:
if property in self:
return true
return false
func property_get_revert(property:String):
match typeof(get(property)):
TYPE_NIL:
return null
TYPE_BOOL:
return false
TYPE_INT:
return 0
TYPE_REAL:
return 0.0
TYPE_STRING:
return ""
TYPE_VECTOR2:
return Vector2()
TYPE_RECT2:
return Rect2()
TYPE_VECTOR2:
return Vector3()
TYPE_TRANSFORM2D:
return Transform2D()
TYPE_PLANE:
return Plane()
TYPE_QUAT:
return Quat()
TYPE_AABB:
return AABB()
TYPE_BASIS:
return Basis()
TYPE_TRANSFORM:
return Transform()
TYPE_COLOR:
return Color()
TYPE_NODE_PATH:
return NodePath()
TYPE_RID:
return RID(Object())
TYPE_OBJECT:
return Object()
TYPE_DICTIONARY:
return {}
TYPE_ARRAY:
return []
TYPE_RAW_ARRAY:
return PoolByteArray()
TYPE_INT_ARRAY:
return PoolIntArray()
TYPE_REAL_ARRAY:
return PoolRealArray()
TYPE_STRING_ARRAY:
return PoolStringArray()
TYPE_VECTOR2_ARRAY:
return PoolVector2Array()
TYPE_VECTOR3_ARRAY:
return PoolVector3Array()
TYPE_COLOR_ARRAY:
return PoolColorArray()
return null
想法是 property_can_revert
将 return true
用于任何 属性 将具有重置箭头。并且 property_get_revert
将给出单击所述箭头时将设置的值。 这必须在 source code 中找到,因为它没有记录。