How to iteratively spawn objects with different properties?

Godot Version

4.2.1

Question

I’ve been working on a Chess game and got pretty far into it when I realized how long my main script is and decided it’s time to learn how to properly do OOP. I only have basic knowledge of how this works and am struggling with what I think is a pretty basic concept.

When the game starts, I am iterating through a FEN string (a string representing the piece layout on the board) and spawning instantiating Piece.tscn and storing the FEN character and colour etc. Piece.tscn consists of the Piece node with Piece.gd attached to it, and the Icon node (textureRect) which loads the piece’s corresponding icon.

I think what I want to do now is keep Piece.gd as the parent class for all pieces, and then have different scripts such as Pawn.gd which will calculate valid moves (currently all valid moves are calculated in one long spaghetti code script). I’m having trouble summarizing the question because I feel like I have a fundamental misunderstanding on what this setup should look like…

So here’s what I got so far, which does not work. Further down I’ll add the working spaghetti code.

Broken code

Main.gd

func add_piece(fen_char, location) -> void:
	#var new_piece = piece_scene.instantiate() #Piece.tscn
	var piece_script_path = DataHandler.piece_objects[DataHandler.fen_dict[fen_char]]
	var piece_script = load(piece_script_path).new()
	var piece_scene_instance = piece_scene.instantiate()

# Here piece_script somehow ends up being Piece.gd even though piece_script_path is pointing to Pawn.gd ??
	
	chess_board_grid.add_child(piece_scene_instance)
	piece_scene_instance.set_script(piece_script)
	piece_scene_instance.add_child(piece_script)
	
	#piece_scene_instance.icon_path = get_node(piece_scene_instance/Icon)
	
	piece_script.fen_char = fen_char
	piece_script.type = DataHandler.fen_dict[fen_char]
	piece_script.team = "w" if fen_char == fen_char.capitalize() else "b"
	piece_script.load_icon()

Then theres a bit more about location etc, but I don’t get past loading the icon because the reference to the TextureRect doesnt work (returns Nil)

Piece.gd

extends Node2D

class_name Piece

@onready var icon = $Icon
var square_ID : int = -1
var type : int 
var team : String
var fen_char : String
var is_revealed : bool = true
var is_pawn : bool = false
var square_ID_history = {}

...
func load_icon() -> void:
	icon.texture = load(DataHandler.assets[type])

Pawn.gd

extends Piece


# Called when the node enters the scene tree for the first time.
func _ready():
	is_pawn = true
	pass # Replace with function body.

Spaghetti code (working)

Main.gd

func add_piece(fen_char, location) -> void:
	var new_piece = piece_scene.instantiate()
	
	chess_board_grid.add_child(new_piece)
	new_piece.fen_char = fen_char
	new_piece.type = DataHandler.fen_dict[fen_char]
	new_piece.team = "w" if new_piece.type < 6 else "b"
	new_piece.load_icon(new_piece.type)

	new_piece.global_position = bg_grid_array[location].global_position + piece_offset
	piece_array[location] = new_piece
	new_piece.square_ID = location
	new_piece.square_ID_history[current_halfmove] = location

Piece.gd

# and here's the beginning of Piece.gd
extends Node2D

@onready var icon_path = $Icon
var square_ID : int = -1
var type : int
var team : String
var fen_char : String
var is_revealed : bool = true
var square_ID_history = {}

...
func load_icon(piece_ID) -> void:
	icon_path.texture = load(DataHandler.assets[piece_ID])


When you extend a class, you always extend a script, not a scene! That is, you cannot assume the existence of any child nodes – unless you create and add them in the script itself.


Since the number of different chess pieces is rather small, I’d probably create one base scene establishing the common fundamentals and then create an inherited scene for each different piece. So instead of re-using the same Piecescene with a different script, I’d look at the FEN string and then spawn the appropriate piece right away.

Ah that makes sense. I got so caught up in my script that I missed out on learning how and when to use inherited scenes.
Thank you!