In the previous section, we explored analyzing nodes in Godot using get_property_list(). This gave us the ability to inspect a node’s properties and their respective types. However, in Godot, not all objects are nodes. Many essential data types—such as Vector2, Color, Dictionary, and Array—do not have get_property_list(), which means treating them the same way as nodes would lead to errors.

This section builds upon our previous approach by expanding compatibility to all Godot objects. We aim to ensure that both node-based and non-node objects can be inspected, categorized, and returned in a structured format for further use.


Understanding Object Type Identification in Godot

Before we can dynamically inspect objects, we first need a way to identify their types . Godot provides two key tools for this:

  1. The is keyword – Determines if an object is an instance of a specific class.
  2. The typeof() function – Returns an integer identifier representing the object’s type.

Each method has its place. The is keyword is excellent for checking class-based objects, while typeof() is more suited for primitive types like int, float, String, and bool.


Method 1: Using is to Identify Object Class

The is keyword is a straightforward way to check if an object belongs to a particular class.

Example: Checking Object Class with is

var my_vector = Vector2(10, 20)
var my_color = Color(1, 0, 0, 1)

print(my_vector is Vector2)  # Output: true
print(my_color is Color)  # Output: true
print(my_vector is Color)  # Output: false

This approach is useful when we need to differentiate between objects that belong to different Godot classes .


Method 2: Using typeof() to Get an Object Type ID

The typeof() function provides an integer identifier for a given object’s type. This is useful for primitive types that don’t belong to a specific class.

Example: Checking Type ID with typeof()

print(typeof(42))  # Output: 2 (int)
print(typeof(3.14))  # Output: 3 (float)
print(typeof("Hello"))  # Output: 4 (String)
print(typeof(Vector2(10, 20)))  # Output: 5 (Vector2)
print(typeof(Color(1, 0, 0, 1)))  # Output: 20 (Color)

This is useful when handling multiple data types where is wouldn’t work , such as differentiating between int and float.


Analyzing and Categorizing Objects in Godot

Now that we know how to identify object types, we can build a system that:

  1. Handles node-based objects differently using get_property_list().
  2. Processes primitive and data-type objects dynamically using a lookup dictionary.
  3. Returns structured data for further use.

Implementing an Object Analysis System

The following system inspects an object, determines its type, and either:

  • Extracts and organizes its properties (if it’s a Node).
  • Uses a predefined handler to process primitive or non-node objects.

Code Implementation

extends Node2D

var handlers: Dictionary = {
	TYPE_NIL: func(): print("Nil"),							# 0
	TYPE_BOOL: func(o): print("Boolean: " , o),				# 1
	TYPE_INT: func(o): print("Integer: " , o),				# 2
	TYPE_FLOAT: func(o): print("Float: " , o),				# 3
	TYPE_STRING: func(o): print("String: " , o),			# 4
	TYPE_VECTOR2: func(o): print("Vector2: " , o),			# 5
	TYPE_VECTOR2I: func(o): print("Vector2i: " , o),		# 6
	TYPE_RECT2: func(o): print("2D Rect" , o),				# 7
	TYPE_RECT2I: func(o): print("2D Recti" , o),			# 8
	TYPE_VECTOR3: func(o): print("Vector3: " , o),			# 9
	TYPE_VECTOR3I: func(o): print("Vector3i: " , o),		# 10
	TYPE_TRANSFORM2D: func(o): print("Transform2D: " , o),	# 11
	TYPE_VECTOR4: func(o): print("Vector4: " , o),			# 12
	TYPE_VECTOR4I: func(o): print("Vector4I" , o),			# 13
	TYPE_PLANE: func(o): print("Plane: " , o),				# 14
	TYPE_QUATERNION: func(o): print("Quaternion: " , o),	# 15
	TYPE_AABB: func(o): print("AABB: " , o),				# 16
	TYPE_BASIS: func(o): print("Basis: " , o),				# 17
	TYPE_TRANSFORM3D: func(o): print("Transform3D" , o),	# 18
	TYPE_PROJECTION: func(o): print("Projection" , o), 		# 19
	TYPE_COLOR: func(o): print("Color: " , o),				# 20
	TYPE_STRING_NAME: func(o): print("String name: " , o),	# 21
	TYPE_NODE_PATH: func(o): print("Node path: " , o),		# 22
	TYPE_RID: func(o): print("RID: " , o),					# 23
	TYPE_OBJECT: func(o): print("Object: " , o),			# 24
	TYPE_CALLABLE: func(o): print("Callable: " , o),			# 25
	TYPE_SIGNAL: func(o): print("Signal: " , o),					# 26
	TYPE_DICTIONARY: func(o): print("Dictionary: " , o),				# 27
	TYPE_ARRAY: func(o): print("Array: " , o),								# 28
	TYPE_PACKED_BYTE_ARRAY: func(o): print("Packed Byte Array: " , o),			# 29
	TYPE_PACKED_INT32_ARRAY: func(o): print("Packed Int32 Array: " , o),		# 30
	TYPE_PACKED_INT64_ARRAY: func(o): print("Pakced Int64 Array: " , o),		# 31
	TYPE_PACKED_FLOAT32_ARRAY: func(o): print("Pakced Float32 Array: " , o),	# 32
	TYPE_PACKED_FLOAT64_ARRAY: func(o): print("Packed Float64 Array: " , o),	# 33
	TYPE_PACKED_STRING_ARRAY: func(o): print("Packed String Array: " , o),		# 34
	TYPE_PACKED_VECTOR2_ARRAY: func(o): print("Packed: " , o),					# 35
	TYPE_PACKED_VECTOR3_ARRAY: func(o): print("Packed Vector3 Array: " , o),	# 36
	TYPE_PACKED_COLOR_ARRAY: func(o): print("Packed Color Array: " , o),		# 37
	TYPE_PACKED_VECTOR4_ARRAY: func(o): print("Packed Vector4 Array: " , o),	# 38
	TYPE_MAX: func(o): print("Max: " , o),										# 39
}

func _ready():
	for x in get_properties(Node2D.new())["numbers"]:
		print(x)

	get_properties(Color(0,0,0,0))

func get_properties(obj):
	var type_id = typeof(obj)
	var handler = handlers.get(type_id, func(): print("handler does not exist"))

	# determine if node (not all TYPE_OBJECTS are nodes but all nodes are TYPE_OBJECTS)
	if obj is Node:

		var numbers = []
		var strings = []
		var bools = []
		var vectors = []
		var colors = []
		var objects = []
		var arrays = []
		var nil = []

		var type_lookup = {
			0: "Nil", 1: "bool", 2: "int", 3: "float", 4: "String", 5: "Vector2", 6: "Vector2i",
			7: "Rect2", 8: "Rect2i", 9: "Vector3", 10: "Vector3i", 11: "Transform2D", 12: "Vector4",
			13: "Vector4i", 14: "Plane", 15: "Quat", 16: "AABB", 17: "Basis", 18: "Transform3D",
			19: "Projection", 20: "Color", 21: "StringName", 22: "NodePath", 23: "RID", 24: "Object",
			25: "Callable", 26: "Signal", 27: "Dictionary", 28: "Array", 29: "PackedByteArray",
			30: "PackedInt32Array", 31: "PackedInt64Array", 32: "PackedFloat32Array", 33: "PackedFloat64Array",
			34: "PackedStringArray", 35: "PackedVector2Array", 36: "PackedVector3Array", 37: "PackedColorArray"
		}

		for prop in obj.get_property_list():
			var type_name = type_lookup.get(prop.type, "Unknown")

			if prop.type in [1]:
				bools.append(prop.name + " - Type: " + type_name)
			elif prop.type in [2, 3]:  # bool, int, float
				numbers.append(prop.name + " - Type: " + type_name)
			elif prop.type in [4, 21]:
				strings.append(prop.name + " - Type: " + type_name)
			elif prop.type in [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]:  # Vector types & transforms
				vectors.append(prop.name + " - Type: " + type_name)
			elif prop.type in [20]:  # Colors
				colors.append(prop.name + " - Type: " + type_name)
			elif prop.type in [22, 23, 24, 25, 26]:  # Node and object references
				objects.append(prop.name + " - Type: " + type_name)
			elif prop.type in [27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37]:  # Arrays and dictionaries
				arrays.append(prop.name + " - Type: " + type_name)
			else:
				nil.append(prop.name + " - Type: " + type_name)

		numbers.sort()
		strings.sort()
		bools.sort()
		vectors.sort()
		colors.sort()
		objects.sort()
		arrays.sort()
		nil.sort()

		var sorted_obj_prop_dict = {"numbers": numbers, "strings": strings, "bools": bools,
		"vectors": vectors, "colors": colors, "objects": objects, "arrays": arrays, "nil": nil }

		return sorted_obj_prop_dict

	# Not a node, check the handler
	else: 
		handler.call(obj)

How This System Works

  1. Node objects are categorized into different property types (numbers, strings, vectors, etc.).
  2. Primitive and non-node objects are processed using handlers stored in the handlers dictionary.
  3. Data is returned in a structured format , allowing it to be reused for debugging, storage, or further processing.
  4. Non-node objects are processed immediately using the associated function in the handlers dictionary.