Godot/Gdscript:为什么str2var不工作与_init方法的类?



我们定义两个类

A.gd

class_name A
var v = null
func _init(v_):
v = v_

B.gd

class_name B
var v = null

现在,当我尝试使用str2var/var2str时,这是我得到的

var a = A.new("aaa")
var b = B.new()
b.v = "bbb"
printt("var2str(a):", var2str(a))
printt("var2str(b):", var2str(b))
printt ("var2str(str2var(var2str(a))):", var2str(str2var(var2str(a))))
printt ("var2str(str2var(var2str(b))):", var2str(str2var(var2str(b))))

:

var2str(a): Object(Reference,"script":Resource( "res://Scripts/AI/A.gd"),"v":"aaa")
var2str(b): Object(Reference,"script":Resource( "res://Scripts/AI/B.gd"),"v":"bbb")
var2str(str2var(var2str(a))):   Object(Reference,"script":null)
var2str(str2var(var2str(b))):   Object(Reference,"script":Resource( "res://Scripts/AI/B.gd"),"v":"bbb")

为什么str2var(a)不工作?

我该如何修复它?

解决方案

通过使参数可选来修复它,例如:

class_name A
var v = null
func _init(v_ = null):
v = v_

这样就没有错误了。我得到这样的输出:

var2str(a): Object(Reference,"script":Resource( "res://A.gd"),"v":"aaa")
var2str(b): Object(Reference,"script":Resource( "res://B.gd"),"v":"bbb")
var2str(str2var(var2str(a))):   Object(Reference,"script":Resource( "res://A.gd"),"v":"aaa")
var2str(str2var(var2str(b))):   Object(Reference,"script":Resource( "res://B.gd"),"v":"bbb")

问题对于抽象,str2var不会传递任何参数给_init它不知道传递什么。

答案的其余部分是确认str2var将导致调用_init而没有参数的过程。


当我尝试你的代码时,我得到这个错误:

E 0:00:00.630   _create_instance: Condition "r_error.error != Variant::CallError::CALL_OK" is true. Returned: __null
<C++ Source>  modules/gdscript/gdscript.cpp:121 @ _create_instance()
<Stack Trace> main.gd:12 @ _ready()

我们可以通过查看源代码找到在_create_instance中抛出错误的行。

遗憾的是,这并没有给我太多信息。所以,我决定搜索str2var是如何实现的。

我们在GDScriptFunctions::call中找到它,这里。它调用VariantParser::parse,它调用VariantParser::parse_value。我们对"Object"的情况感兴趣(在这里)。这导致呼叫ClassDB::instance(type)。这里的类型是"Reference",然后它开始设置所有属性。作为第一个"script":Resource("res://A.gd").

当我们设置脚本时(这里),它将导致对GDScript::instance_create的调用。调用GDScript::_create_instance(这里):

return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error)

对于_init没有参数(NULL是参数数组,0是参数的个数)。这是GDScript::_create_instance的签名:

GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error)

当然,initializer->call(instance, p_args, p_argcount, r_error);失败了,因为_init需要参数。我们找到了把错误扔到更下面的那行。注意:initializer是在解析脚本时创建的。

最新更新