class 属性的访问器有用吗?
Are accessors of class properties useful?
考虑 class Node2D
的 属性 global_position
的以下访问器方法:
矢量2global_position
Setter set_global_position(value)
Getter get_global_position()
但是 属性 没有被封装,如本例所示:
tool
extends EditorScript
func _run() -> void:
var n = Node2D.new()
n.global_position = Vector2(100, 100)
print(n.global_position)
产生:
* scene/2d/canvas_item.cpp:467 - Condition "!is_inside_tree()" is true. Returned: get_transform()
(100, 100)
那些访问器没用吗?
它们并非毫无用处。它们很有用……如果节点在场景树中。
您可以使用add_child
or add_child_below_node
将节点添加到场景树中。
我不确定你所说的“未封装”是什么意思。为了以防万一,我会指出你没有绕过它们。
当您使用 属性 时,您正在使用 getter 和 setter 方法。 属性 是一种语言绑定的便利。因此,我们也可以说您不需要 属性,只需要 getter 和 setter.
你可以在source for Node2D
中看到,有一个_bind_methods
函数设置了所有公开使用的属性和方法。这是 global_position
的样子:
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
您收到的消息是因为您在不在场景树上的节点上使用 global_position
。而且,是的,在那种情况下,它没有用。我们可以用一个简单的脚本来解决这个问题:
extends Node2D
func _ready() -> void:
global_position = Vector2(200, 300)
var n = Node2D.new()
n.global_position = Vector2(100, 100)
print(n.global_position)
add_child(n)
print(n.global_position)
这输出:
(100, 100)
(300, 400)
因此,如您所见,它将具有与设置的不同的全局位置。而差异取决于 parent 的位置。设置 position
会产生同样的效果。 因此设置 global_position
在这里没有用。
如果您想更深入地了解 global_position
的作用,我们可以查看 getter 和 setter 的来源([= 的链接来源的一部分) 19=]):
Point2 Node2D::get_global_position() const {
return get_global_transform().get_origin();
}
void Node2D::set_global_position(const Point2 &p_pos) {
Transform2D inv;
CanvasItem *pi = get_parent_item();
if (pi) {
inv = pi->get_global_transform().affine_inverse();
set_position(inv.xform(p_pos));
} else {
set_position(p_pos);
}
}
顺便说一下,这是 set_position
(注意它写着 pos
):
void Node2D::set_position(const Point2 &p_pos) {
if (_xform_dirty)
((Node2D *)this)->_update_xform_values();
pos = p_pos;
_update_transform();
_change_notify("position");
}
和_update_transform
(有明显的!is_inside_tree()
检查):
void Node2D::_update_transform() {
_mat.set_rotation_and_scale(angle, _scale);
_mat.elements[2] = pos;
VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), _mat);
if (!is_inside_tree())
return;
_notify_transform();
}
请注意 _update_transform
基于 pos
.
更新 _mat
get_global_transform
呢?不在那个文件里。我们在 source for CanvasItem
:
中找到它
Transform2D CanvasItem::get_global_transform() const {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
#endif
if (global_invalid) {
const CanvasItem *pi = get_parent_item();
if (pi) {
global_transform = pi->get_global_transform() * get_transform();
} else {
global_transform = get_transform();
}
global_invalid = false;
}
return global_transform;
}
还有您看到的失败断言:!is_inside_tree()
。
哦,关于那个 global_invalid
。如果你在源上搜索它,你会发现当节点退出场景树或修改变换时它被设置为真(即在 _notify_transform
中,我不包括在这里,但你可以看到它在场景树中时被 _update_transform
调用。
我们能从这一切中得到什么?
- 属性
global_position
只是方法 get_global_position
和 set_global_position
. 的语法糖
- 方法
get_global_position
和set_global_position
作用于全局变换,它继承自CanvasItem。
- 为了计算出全局位置,我们需要计算 parent 节点上的变换。 这意味着,我们也可以通过相同的过程来弄清楚,因此这些方法在技术上是不必要的。
- 这是懒惰完成的。全局位置失效,并根据需要重新计算。
- 如果节点不在场景树中……什么parent节点?在这种情况下,使用
global_position
与我们使用 position
的效果相同。 因此,当节点不在场景树中时,我们可以说 global_position
没有用。
- 有一个断言告诉你什么时候使用它,它不在场景树中。该断言为您提供了您发布的消息。
考虑 class Node2D
的 属性 global_position
的以下访问器方法:
矢量2global_position
Setter
set_global_position(value)
Getter
get_global_position()
但是 属性 没有被封装,如本例所示:
tool
extends EditorScript
func _run() -> void:
var n = Node2D.new()
n.global_position = Vector2(100, 100)
print(n.global_position)
产生:
* scene/2d/canvas_item.cpp:467 - Condition "!is_inside_tree()" is true. Returned: get_transform()
(100, 100)
那些访问器没用吗?
它们并非毫无用处。它们很有用……如果节点在场景树中。
您可以使用add_child
or add_child_below_node
将节点添加到场景树中。
我不确定你所说的“未封装”是什么意思。为了以防万一,我会指出你没有绕过它们。
当您使用 属性 时,您正在使用 getter 和 setter 方法。 属性 是一种语言绑定的便利。因此,我们也可以说您不需要 属性,只需要 getter 和 setter.
你可以在source for Node2D
中看到,有一个_bind_methods
函数设置了所有公开使用的属性和方法。这是 global_position
的样子:
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
您收到的消息是因为您在不在场景树上的节点上使用 global_position
。而且,是的,在那种情况下,它没有用。我们可以用一个简单的脚本来解决这个问题:
extends Node2D
func _ready() -> void:
global_position = Vector2(200, 300)
var n = Node2D.new()
n.global_position = Vector2(100, 100)
print(n.global_position)
add_child(n)
print(n.global_position)
这输出:
(100, 100)
(300, 400)
因此,如您所见,它将具有与设置的不同的全局位置。而差异取决于 parent 的位置。设置 position
会产生同样的效果。 因此设置 global_position
在这里没有用。
如果您想更深入地了解 global_position
的作用,我们可以查看 getter 和 setter 的来源([= 的链接来源的一部分) 19=]):
Point2 Node2D::get_global_position() const {
return get_global_transform().get_origin();
}
void Node2D::set_global_position(const Point2 &p_pos) {
Transform2D inv;
CanvasItem *pi = get_parent_item();
if (pi) {
inv = pi->get_global_transform().affine_inverse();
set_position(inv.xform(p_pos));
} else {
set_position(p_pos);
}
}
顺便说一下,这是 set_position
(注意它写着 pos
):
void Node2D::set_position(const Point2 &p_pos) {
if (_xform_dirty)
((Node2D *)this)->_update_xform_values();
pos = p_pos;
_update_transform();
_change_notify("position");
}
和_update_transform
(有明显的!is_inside_tree()
检查):
void Node2D::_update_transform() {
_mat.set_rotation_and_scale(angle, _scale);
_mat.elements[2] = pos;
VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), _mat);
if (!is_inside_tree())
return;
_notify_transform();
}
请注意 _update_transform
基于 pos
.
_mat
get_global_transform
呢?不在那个文件里。我们在 source for CanvasItem
:
Transform2D CanvasItem::get_global_transform() const {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
#endif
if (global_invalid) {
const CanvasItem *pi = get_parent_item();
if (pi) {
global_transform = pi->get_global_transform() * get_transform();
} else {
global_transform = get_transform();
}
global_invalid = false;
}
return global_transform;
}
还有您看到的失败断言:!is_inside_tree()
。
哦,关于那个 global_invalid
。如果你在源上搜索它,你会发现当节点退出场景树或修改变换时它被设置为真(即在 _notify_transform
中,我不包括在这里,但你可以看到它在场景树中时被 _update_transform
调用。
我们能从这一切中得到什么?
- 属性
global_position
只是方法get_global_position
和set_global_position
. 的语法糖
- 方法
get_global_position
和set_global_position
作用于全局变换,它继承自CanvasItem。 - 为了计算出全局位置,我们需要计算 parent 节点上的变换。 这意味着,我们也可以通过相同的过程来弄清楚,因此这些方法在技术上是不必要的。
- 这是懒惰完成的。全局位置失效,并根据需要重新计算。
- 如果节点不在场景树中……什么parent节点?在这种情况下,使用
global_position
与我们使用position
的效果相同。 因此,当节点不在场景树中时,我们可以说global_position
没有用。 - 有一个断言告诉你什么时候使用它,它不在场景树中。该断言为您提供了您发布的消息。