它们不是无用的。它们很有用……如果节点在场景树中。
您可以使用add_child 或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)
因此,如您所见,它将具有与设置不同的全局位置。并且差异取决于父母的位置。设置position 将具有相同的效果。 因此设置global_position 在这里没有用。
如果您想更深入地了解 global_position 的作用,我们可以查看 getter 和 setter 的源代码(Node2D 的链接源代码的一部分):
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。如果在源码上搜索,会发现在节点退出场景树或者transform被修改时设置为true(即在_notify_transform,这里我不包括,但是你可以看到在场景树中时由_update_transform调用)。
我们能从这一切中得到什么?
- 属性
global_position 只是方法get_global_position 和set_global_position 的语法糖。
-
get_global_position 和 set_global_position 方法用于全局变换,它继承自 CanvasItem。
- 要确定全局位置,我们需要计算父节点上的变换。 也就是说,我们也可以通过相同的过程来解决这个问题,因此这些方法在技术上是不必要的。
- 这是懒惰的。全局位置失效,并按需重新计算。
- 如果节点不在场景树中……什么父节点?在这种情况下,如果我们使用
position,使用global_position 会做同样的事情。 因此,当节点不在场景树中时,我们可以说global_position 没有用处。
- 有一个断言会告诉您何时使用它并且它不在场景树中。该断言为您提供了您发布的信息。