I'm trying to create a Unit class that will hold unit information, such a strength, movement points, as well as a TextureRect containing the unit's position and texture. But I'm having trouble displaying the unit on the map. Here's my class initializaiton function. Maybe I'm not creating the TextureRect correctly? Or, more likely, I've messed up the syntax of load()? I confess I don't understand load() very well. Here's the code:

extends Object

class_name Unit

var unit_rect : TextureRect
... (other variable declarations omitted)

func _init(_str: int = 0, _move : int = 0, _size : int = FORMATION.ARMY, _col : int = 0,
		_row : int = 0, _on_map : bool = true, _name : String = designation.G1,
		_texture : String = "res://units/6th Armee.jpg", _unit_rect = TextureRect.new() ):
	strength = _str
	movement = _move
	size = _size
	col = _col
	row = _row
	on_map = _on_map
	name = _name	
	texture = _texture
	unit_rect = _unit_rect
	unit_rect.texture = load(_texture)

Then, in a setup_units function elsewhere, I create new units:

func setup_units():
	G6 = Unit.new(6, 5, Unit.FORMATION.ARMY, 1, 3, true,
			$Unit.designation.G6, "res://units/6th Armee.jpg" )
	G6.unit_rect.texture = load(G6.texture)
	G6.unit_rect.rect_size.x = 64
	G6.unit_rect.rect_size.y = 64
	G6.unit_rect.rect_position.x = 300	
	G6.unit_rect.rect_position.y = 400

The code compiles and runs, but I never see a unit, regardless of where I put the load(texture) call. I got the texture string by right clicking on the image in the resources pane and clicking "copy path", then pasting it into the code. I'm pretty new to Godot, so I'd appreciate any help. Thanks.

TextureRect is a node. It needs to be added to the scene tree in order to be displayed. So you'll need to add it as a child of any existing node, either in the Unit constructor or in the setup_units() function. For example if you want to add it as a child of the root node you'd do something like:

func setup_units():
	G6 = Unit.new(...)
	var root = get_tree().get_root()
	root.add_child(G6)

Thanks for that helpful reply. So I guess I'll need a separate TextureRect node for every unit object I create, then. For prototyping, I need only a couple dozen unique units, with unique names, attributes, textures, etc. But if I carry the project forward, that might become a couple hundred unique units, each with its own node. I hope that doesn't create performance issues.

Do I have to physically add these child nodes to the tree, or is it enough to create them in code, as you did in your example?

Couple of dozen to a couple of hundred, on modern desktop systems at least, should probably be fine. Its when you need thousands that you might want to start scripting the servers directly.

When you call add_child() it is adding it to the tree (just as if you did it with the editor). I think up to probably like a few hundred should be no problem. However, if not all the enemies are on screen at once, you can use tricks to dynamically remove and add enemies that are off-screen (like by using object pools).

It may be more convenient to use sprites for this.

Thanks for your replies. OK, I'll call add_child() and see how things go.

@xyz , I see from the docs that TextureRects are designed for UI, whereas sprites more for in-game objects. Maybe sprites are more lightweight? I'll experiment with a sprite node and see how it goes.

Thanks again for all the help.

@Selek Yeah, sprites could be more appropriate choice.

Also, if your unit uses only a single node for its visual representation (be it TextureRect or Sprite) it may be simpler to just inherit your Unit class from that node type (e.g. extends Sprite). That way you only have one object to manage.

If you still want to do it via generic class that refers to visual representation node, as you're currently doing, note that inheriting from Object does not grant you automatic memory management. You need to manually delete the object when it's no longer needed, otherwise you risk a memory leak in your application.

That's why in most cases it's better to inherit from Reference instead of Object. Reference will automatically delete itself when its no longer used.

Thanks for your advice. I like the idea of inheriting from Sprite. If I do that, does that solve the memory management issue?

@Selek said: Thanks for your advice. I like the idea of inheriting from Sprite. If I do that, does that solve the memory management issue?

No, because all node types inherit from Object. You'll need to remove them from scene and call free() on them when you no longer need them. You have to do that anyway if your Unit object creates a node, but if you inherit from Sprite you'll need to do it only once. And all your unit data is in one place. I'd try something like this. Unit class:

class_name Unit
extends Sprite

# constructor
func _init(...):
	# init 

Creation:

unit = Unit.new(...)
some_parent_node.add_child(unit)

Deletion:

some_parent_node.remove_child(unit)
unit.free() # or unit.queue_free() for safer deletion

I think if you use queue_free() you don't even need to call remove_child() as it will automatically remove the node from the scene tree.

Calling free usually is a bad idea. Better to always use queue_free.

@cybereality said: Calling free usually is a bad idea. Better to always use queue_free.

Right, better to stick to queue_free() when deleting nodes.

I think it's safe to call free() if node hasn't got any children and you properly remove it from scene beforehand. But since free() is Object's method it doesn't know/care what happens with node in the scene tree context, which may cause problems.

Yes, there are cases where free is safe, but most likely in a game you have done something with the object (not just created and destroyed it on the next line) so common examples would be bullets hitting a target, going off screen, etc, and you'd want to use queue_free.

Thanks for your replies. That creation/deletion code seems straightforward enough. Sprites are working nicely so far, thanks to your help. The code is more consolidated now, easier to follow.

I suppose I should familiarize myself with Godot's performance tools to make sure I'm not leaking memory. I haven't even looked at that section of the IDE yet, or at the relevant docs.

Lots of fun ahead of me: a UI to give orders; pathfinding and A stuff; and, even more challenging, an AI for the computer opponent. I've done pathfinding and A in Gamemaker Studio (with help from Amit's page on pathfiding etc), and it will be interesting to see whether it's any easier in Godot. AI will never be easy, regardless of the engine! But it's the most fun part of this sort of project, at least for me.

Thanks again.

a year later