So far, we’ve implemented a powerful object analysis system that can dynamically inspect and categorize both node-based and non-node objects in Godot. However, keeping all this logic inside main.gd can clutter the script, making it harder to maintain and expand.

To improve code organization, we’ll move the get_properties() function into its own dedicated class. This will:

  • Keep main.gd clean and focused on high-level game logic.
  • Make get_properties() reusable across different parts of the project.
  • Encourage modular programming , making it easier to expand in the future.

Step 1: Creating a New Script for Object Analysis

In Visual Studio Code, we will create a new script to handle object analysis separately.

  1. Navigate to the Scripts folder (or create one if it doesn’t exist).
  2. Create a new script and name it ObjectAnalyzer.gd .
  3. Open ObjectAnalyzer.gd and define a new class.

Step 1.1: Understanding Classes in Godot

What is a Class?

A class in GDScript is a blueprint for creating objects. Classes let us group related functions and variables together, making the code more modular and reusable.

How Do We Define a Class in GDScript?

In Godot, a class is simply a script file that extends a base type (like Node, Node2D, or Object).

For example:

extends Node  # This makes it a Node class

var example_variable = "Hello!"

func example_function():
    print(example_variable)
  • extends Node: This means our script inherits from Node, allowing it to be added to the scene.
  • example_variable: A property that stores a value.
  • example_function(): A method (or function) that performs an action.

When should we use classes?

  • When we reuse code across multiple files.
  • When we need to organize related functions into a single location.
  • When we want to keep main.gd clean.

Step 1.2: Creating Our ObjectAnalyzer Class

Now that we understand classes, let’s define one for object analysis .

  1. Inside ObjectAnalyzer.gd, define the class by extending Node:
  2. What does class_name ObjectAnalyzer do?
    • This registers the class as ObjectAnalyzer, so we can instantiate it in main.gd without needing to use load() or preload().
    • Example usage:
extends Node  # This makes our script a class that can be instantiated

class_name ObjectAnalyzer  # This allows us to reference it by name in other scripts

Now that we’ve defined a class, we can move the get_properties() function inside it.


Step 2: Moving get_properties() into ObjectAnalyzer.gd

We’ll define a new class called ObjectAnalyzer that manages object inspection . Instead of keeping everything in main.gd, we’ll encapsulate the logic inside this separate script.

ObjectAnalyzer.gd

extends Node

class_name ObjectAnalyzer

var handlers: Dictionary = {
	TYPE_NIL: func(): print("Nil"),				
	TYPE_BOOL: func(o): print("Boolean: ", o),	
	TYPE_INT: func(o): print("Integer: ", o),	
	TYPE_FLOAT: func(o): print("Float: ", o),	
	TYPE_STRING: func(o): print("String: ", o),
	TYPE_VECTOR2: func(o): print("Vector2: ", o),
	TYPE_VECTOR3: func(o): print("Vector3: ", o),
	TYPE_COLOR: func(o): print("Color: ", o),	
	TYPE_OBJECT: func(o): print("Object: ", o),
	TYPE_DICTIONARY: func(o): print("Dictionary: ", o),
	TYPE_ARRAY: func(o): print("Array: ", o),	
}

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

	# Handle nodes separately
	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",
			9: "Vector3", 11: "Transform2D", 20: "Color", 22: "NodePath", 23: "RID",
			24: "Object", 27: "Dictionary", 28: "Array"
		}

		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]: numbers.append(prop.name + " - Type: " + type_name)
			elif prop.type in [4]: strings.append(prop.name + " - Type: " + type_name)
			elif prop.type in [5, 9, 11]: vectors.append(prop.name + " - Type: " + type_name)
			elif prop.type in [20]: colors.append(prop.name + " - Type: " + type_name)
			elif prop.type in [22, 23, 24]: objects.append(prop.name + " - Type: " + type_name)
			elif prop.type in [27, 28]: 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()

		return {"numbers": numbers, "strings": strings, "bools": bools, "vectors": vectors, "colors": colors, "objects": objects, "arrays": arrays, "nil": nil}

	else:
		handler.call(obj)

Step 3: Updating main.gd to Use ObjectAnalyzer

Now that get_properties() is moved to a separate script , we need to update main.gd so it uses ObjectAnalyzer.

  1. Open main.gd.
  2. Create an instance of ObjectAnalyzer.
  3. Call get_properties() through this instance.

Updated main.gd

extends Node2D

var object_analyzer: ObjectAnalyzer

func _ready():
	object_analyzer = ObjectAnalyzer.new()  # Create an instance of ObjectAnalyzer

	# Example: Analyzing a Node2D instance
	for x in object_analyzer.get_properties(Node2D.new())["numbers"]:
		print(x)

	# Example: Analyzing a Color object
	object_analyzer.get_properties(Color(0, 0, 0, 0))