How to 'spawn' mutiple of the same node and controls each individually?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By inTech
:warning: Old Version Published before Godot 3 was released.

Hello

I am new to Godot Engine and GDScript. I have read through all the 2D based tutorial at http://www.gamefromscratch.com/ and I am now trying to develop a simple game.

My game is a simple RTS game. And I would like to spawn multiple of the same node (armies) from time to time. I do not want to create a lot of nodes and spawn them via code one by one because all of them will eventually be the same and I do not know how many my ‘player’ will need to spawn.

I read about instancing and so I create two scene. One as the main game scene and another one to spawns the armies. Below is a snippet of my code from the main scene.

extends Node

var continueAdd = false;

func _ready():
	set_process_input(true)
	
func _input(event):
	# if user left clicks
	if(event.type == InputEvent.MOUSE_BUTTON):
		if(event.button_index == 1):
			if (continueAdd == true):
				var player = preload( "res://scenes/spawns.tscn" ).instance()
				get_node(".").add_child(player)
				print("Getting player!");
				continueAdd = false;

func _on_ContinueAdd_Timer_timeout():
    # I have a timer that set at one seconds interval
	continueAdd = true;

My code worked as intended but I am just wondering if I am going at the correct path or not - maybe there is another better way to approach this(?). And how do I go about controlling each individual instance of that node that locate inside res://scenes/spawns.tscn? (I am not referring to control the main node inside spawns.tscn but the instance that I spawned using “get_node(“.”).add_child(player)”).

I know it is a bit confusing. If you have any other questions, feel free to us and I will try my best to answer.

Thank you.

what do you mean “control”, controlling what?

volzhs | 2016-10-24 15:31

you can save the preloaded scene on a variable and instance it as many times you want but as volzhs says, explain a bit more the “control”.

eons | 2016-10-24 16:55

@volzhs and @eons, by controlling I mean to control each instance of that node I loaded into the main scene individually. For example, my player may have spawned ten ‘armies’. However they only want one out of the ten armies to ‘go out and fight’. How do I control the one army using code? Or how do I get a reference of that instance using code?

(I am not asking on how to move the instance or what. I am asking on how do I get reference to that individual instance using code like get_parent() or get_root(), is there?)

@eons, that is a neat idea. I will be correcting my node.

inTech | 2016-10-25 11:23

:bust_in_silhouette: Reply From: avencherus

One method would be to add each new instance as reference into an array.

Inside the scene that you’re instancing, you would write some functions that manipulate their data, like their position, stats, whatever.

Then from the point you wish to send a command to all of them you would loop through the array and call that function.

for unit in units:
  unit.retreat()

If you want specific commands to specific things, you’ll have to create the logic you desire for making selections and such. But algorithms like that are not specific to Godot.

Another option you could employ is grouping: http://docs.godotengine.org/en/stable/tutorials/step_by_step/scripting_continued.html#groups

Selecting units, grouping and giving orders to the groups in godot could be just add_to_group (selected units) and get_tree.call_group to give orders as avencherus said.
Using groups means you will have to be careful and organized with adding, removing and naming groups.

But that depends on the design, you can have something more complex.


Apart ffrom grouping, to control armies for a RTS I can recommend you to design states and behaviors, units may need to avoid themselves, get better paths, avoid obstacles and react (alone or in group) without direct intervention from the player (a simple AI).

eons | 2016-10-25 14:14

This worked great (array method) and everything seem to work as what I wanted. I just prototype your idea out and that now I can control each individually object via hard coded - just to check if it will work or not. Soon I will turn this prototype into a more dynamic program. Below is the snippet that is working.

Autoload global.gd

extends Node

var arrayBlue = Array();

func _ready():
	print("Global ready!");
	
func arrayBlue_add(addName):
	arrayBlue.push_back(addName);

func arrayBlue_size():
	return arrayBlue.size();

Main scene

extends Node

var continueAdd = false;

func _ready():
	set_process_input(true)
	
func _input(event):
	# if user left clicks
	if(event.type == InputEvent.MOUSE_BUTTON):
		if(event.button_index == 1):
			if (continueAdd == true):
				global.arrayBlue_add(global.arrayBlue_size() + 1);
				var player = preload( "res://scenes/spawns.tscn" ).instance()
				get_node(".").add_child(player)
				print(str("Getting player #", global.arrayBlue_size(), "!"));
				print(global.arrayBlue);
				continueAdd = false;

func _on_ContinueAdd_Timer_timeout():
	continueAdd = true;

Spawns

extends KinematicBody2D

var blueInstanceId = global.arrayBlue_size();
var x_pos = 200;
var y_pos = 200;

func _ready():
	set_pos(Vector2(x_pos, y_pos));
	print("#", blueInstanceId, " - ", "X: ", x_pos, " | Y: ", y_pos);
	set_process(true);
	
func _process(delta):
	if(Input.is_action_pressed("ui_left")):
		if (blueInstanceId == 3):
			set_pos(Vector2(get_pos().x - 100 * delta, get_pos().y));

Now whenever I press ‘left’ button, only the third instance will be moved away. I will be checking out the grouping method and see if it will be a better alternative for my simple test game.

By the way, is there any disadvantages of using one over another or is it just a matter of preference - array and grouping.

inTech | 2016-10-25 15:44

More preference/design, also groups are like arrays managed by the tree.

You can design groups to have many functions (a single node in groups “player”,“infantry”,“current selection”,“stand ground”).

Direct references to an array may feel more “normal” than using groups, for programmers in particular.
What I don’t know is if adding&removing from an array is optimized like the built in group system.
Like individual unit add and remove from selection.

ps: Other methods that can be used are node reparenting to a “selection” node but not sure if is clean for a RTS because you can select&deselect all the time.

eons | 2016-10-25 16:39

Seems like a fine start to me.

I’m not sure about what groups do on the back end, and I haven’t had any need yet to use them for my projects. So I can’t comment on it.

When it comes to performance, you’ll have to measure that case by case. A lot of it is going to be mainly reliant on Godot’s implementations. You’re not going to be doing your own memory management and such from GDScript.

So what I can say about arrays, is that when they’re used in certain ways where the memory is aligned, they can out perform many types of traditional algorithms, even though it is brute force. It’s because of things like a cache prefetchers in the hardware.

The slowest thing these days are the connections between the cache and the RAM. A prefetch can look at an array and make an assumption that you’re going to want what’s next, and start predicatively caching it. So you’re a lot less likely to get what’s called a cache miss, where it has to go the long journey back to RAM to get the data.

When an array gets used and handled this way, it’s almost as if it’s all hanging out in the level 2 cache. Since it’s constantly loading in new data before it’s requested.

Whereas something like a very fast linked list algorithm will be a list of pointers to objects scattered through memory. There is no way for the prefetcher to predict ahead of time where the next data element is going to come from. Even though on paper it touches waaaaaay less items in memory to find the data, it loses out because of the vast amount of time the CPU and cache may have to wait for it’s data to arrive.

Maybe that’s a bit off topic, but hopefully that helps, because it’s a very deep topic, and one can only touch on it from here.

The only responsible prescription one can give for performance is to never assume, and always measure.

avencherus | 2016-10-25 19:53

:bust_in_silhouette: Reply From: rustyStriker

if you want to control each individually i believe you can make a stand-alone script for the node you want to control and spawn multiple times, and add a “Controlled” or “Targeted” variable(as a Boolean probably) so a node will be controlled only when he is selected. that way each of them could get his own commands running on him.