'Is there way to create TRUE custom type in Godot?

I'm trying to create a custom type for my Player Controller.

First I went with "script classes":

extends Node

class_name PlayerController

export var max_speed = 32
export var id = 1
export(NodePath) var node_path
onready var node = get_node(node_path)

...

But then I realized, and was not quite satisfied with the way that properties are displayed: script class properties

I'd expected it to be in the "PlayerController" dedicated section as it with node, so it will be possible to inherit and see the nice stack of properties there.

I thought that it is due to the "script classes" being a simplified comparing to regular extensions. So I created one.

tool
extends EditorPlugin

func _enter_tree():
    add_custom_type("PlayerController", "Node", preload("PlayerController.gd"),preload("PlayerController.svg"))

func _exit_tree():
    pass

The result was literally the same.

What I figured out is that "custom type" created in this way is not a "custom type" but just a Parent type with script attached to it. It can be confirmed in the docs:

void add_custom_type(type: String, base: String, script: Script, icon: Texture)

Adds a custom type, which will appear in the list of nodes or resources. An icon can be optionally passed.

When given node or resource is selected, the base type will be instanced (ie, "Spatial", "Control", "Resource"), then the script will be loaded and set to this object.

You can use the virtual method handles() to check if your custom object is being edited by checking the script or using the is keyword.

During run-time, this will be a simple object with a script so this function does not need to be called then.

My question is: It is possible to create a true custom type?



Solution 1:[1]

Adding a category in the inspector panel

First of all, if what you want is a dedicated section in the inspector panel, you can do that with a tool (see Running code in the editor) script and _get_property_list.

This is an example based on another answer:

tool
extends Node

export var something_else:String

var custom_position:Vector2
var custom_rotation_degrees:float
var custom_scale:Vector2

func _get_property_list():
    return [
        {
            name = "Custom",
            type = TYPE_NIL,
            hint_string = "custom_",
            usage = PROPERTY_USAGE_CATEGORY
        },
        {
            name = "custom_position",
            type = TYPE_VECTOR2
        },
        {
            name = "custom_rotation_degrees",
            type = TYPE_REAL
        },
        {
            name = "custom_scale",
            type = TYPE_VECTOR2
        }
    ]

There I'm creating a category called "Custom". Notice that type is TYPE_NIL and usage is PROPERTY_USAGE_CATEGORY. Which is how the documentation does it. See Adding script categories.

Using PROPERTY_USAGE_CATEGORY will produce a named header, similar to the one that says "Node" on the picture on the question. Use PROPERTY_USAGE_GROUP to make a collapsible group.

The value of hint_string will be used as a prefix. Any property with that prefix will be in that category. Such as the ones you see in the code, each with their respective types. These are all declared with var in my code. However, not with export because then they would appear twice.


And it looks as follows:

"Custom" category visible in the inspector panel


Adding a custom type

When we create a a class in a script, it is a type. A GDScript type. For evidence that they are GDScript types. Notice that when using class_name you can declare variables of that type, check if a value is of the type with the is operator. And that you can use extends with them.

There are also core types. Which are also GDScript types. So you can also use declare variable of the type, use extend with them and check for them with is.

However, the classes we create in a script are not core types. We cannot really create a core type from GDScript or any other script language. All we can do is add a script to an existing core type.

If you want to create actual core types, you need to use C++ and create a Godot Module.

You may also be interested in GDExtension in the upcoming Godot 4.0.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1