检查一个对象是否属于给定字符串中的类名的类?

cak*_*ver 3 gdscript godot

假设我有一个对象,并且在字符串中给定了一个类名,
如何检查该对象是否属于该类?

extends Node2D

func _ready():
    var given_class_name="KinematicBody2D"
    if($Obj is given_class_name):
       ...
Run Code Online (Sandbox Code Playgroud)

The*_*aot 7

您可以使用get_class()来查找 an 的类Object,忽略Scripts。在这种情况下应该足够了:

var given_class_name="KinematicBody2D"
prints($Obj.get_class() == given_class_name)
Run Code Online (Sandbox Code Playgroud)

但并非所有情况都是如此,不是吗?也许您想检查基类,那么这不起作用:

var given_class_name="PhysicsBody2D"
prints($Obj.get_class() == given_class_name)
Run Code Online (Sandbox Code Playgroud)

相反,我们可以使用is_class

var given_class_name="PhysicsBody2D"
prints($Obj.is_class(given_class_name))
Run Code Online (Sandbox Code Playgroud)

或者我们可以问ClassDB

var given_class_name="PhysicsBody2D"
var obj_class := $Obj.get_class()
prints(
    obj_class == given_class_name
    or ClassDB.is_parent_class(given_class_name, obj_class)
)
Run Code Online (Sandbox Code Playgroud)

但是课程呢Script

也许您还记得我们可以通过查看来找到脚本的类名_global_script_classes,如下所示:

var obj_class_name := $Obj.get_class()
var script:Script = $Obj.get_script()
if script != null:
    obj_class_name = script.resource_path
    for x in ProjectSettings.get_setting("_global_script_classes"):
        if str(x["path"]) == script.resource_path:
            script_class_name = str(x["class"])
Run Code Online (Sandbox Code Playgroud)

上面的代码将设置obj_class_name为:

  • 的脚本的类名$Obj(如果有)。
  • 脚本的路径$Obj(如果有)。
  • 的内置类$Obj

然而,由于我们想要检查它是否属于给定类型,所以这是不够的。因为我们还需要检查Script继承。事实证明,弄清楚我们给出的名称是什么类型的类并从那里开始工作会更方便:

func is_instance_of(obj:Object, given_class_name:String) -> bool:
    if ClassDB.class_exists(given_class_name):
        # We have a build in class
        return obj.is_class(given_class_name)
    else:
        # We don't have a build in class
        # It must be a Script class
        # Try to find the Script
        var class_script:Script
        for x in ProjectSettings.get_setting("_global_script_classes"):
            if str(x["class"]) == obj_class_name:
                class_script = load(str(x["path"]))
                break

        if class_script == null:
            # Unknown class
            return false

        # Get the script of the object and try to match it
        var check_script := obj.get_script()
        while check_script != null:
            if check_script == class_script:
                return true

            check_script = check_script.get_base_script()

        # Match not found
        return false
Run Code Online (Sandbox Code Playgroud)

我们就快到了。如您所知,在 GDScript 中,您可以使用脚本路径进行扩展(请参阅)。因此,我们可能会考虑脚本有效类名的资源路径...我们也可以支持:

func is_instance_of(obj:Object, given_class_name:String) -> bool:
    if ClassDB.class_exists(given_class_name):
        # We have a build in class
        return obj.is_class(given_class_name)
    else:
        # We don't have a build in class
        # It must be a script class
        var class_script:Script
        # Assume it is a script path and try to load it
        if ResourceLoader.exists(given_class_name):
            class_script = load(given_class_name) as Script

        if class_script == null:
            # Assume it is a class name and try to find it
            for x in ProjectSettings.get_setting("_global_script_classes"):
                if str(x["class"]) == obj_class_name:
                    class_script = load(str(x["path"]))
                    break

        if class_script == null:
            # Unknown class
            return false

        # Get the script of the object and try to match it
        var check_script := obj.get_script()
        while check_script != null:
            if check_script == class_script:
                return true

            check_script = check_script.get_base_script()

        # Match not found
        return false
Run Code Online (Sandbox Code Playgroud)

您可以加倍努力并支持 Variant 而不是Object. 然后你可以用typeof...检查它的类型。如果是,TYPE_OBJECT那么你继续检查一个类。如果不是,您将需要一个巨大的开关来检查构建类型的名称(与此处的类似,但带有类型名称)。


对于任何试图在《GODOT 4》中这样做的人:ProjectSettings.get_setting("_global_script_classes")不再有效。而是使用ProjectSettings.get_global_class_list().