What is the best way to accomplish dynamic-based movement of Area2D nodes?

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

Forgive me, I am a total noob to Godot, and this problem is probably much more simple than I am making it.

I am currently building a top-down twin stick shooter for 4 (local) players. I have been running into problems with two chunks of my scripting for the past 20 hours of development, and they are pretty similar in nature.

The objective here is to take an Area2D node (specifically I am having issues with enemy and bullet scenes) and move them in a direction that may be different from second-to-second/frame-by-frame.

The first problem I am running into is that, I want multiple instances of enemy scenes to move to the Player scene that is closest to that scenes current position. I am trying to do this using the Navigation2D and NavigationPolygonInstance nodes, with a script on the Navigation2D node that, for each enemy instance checks through an array of Player positions, returns the closest player location, and sets the enemy’s path to the player position. The function is returning the enemy and player positions properly, but when I try to set the path, it is returning an Object:null error.

See (terrible, torn apart) code below:

extends Navigation2D
var path = []
var playerPos = []
var closestPos = Vector2(0,0)
var enemyPos = Vector2(0,0)
func _ready():
    set_process(true)

func _process(delta):
    playerPos =[get_parent().get_parent().get_node("Player0"),get_parent().get_parent().get_node("Player1"),get_parent().get_parent().get_node("Player2"),get_parent().get_parent().get_node("Player3")]

for N in self.get_children():
	if N.get_child_count() >0:
		enemyPos = N.get_pos()
		var closest_node2d = get_closest_node2d(playerPos, enemyPos)
		path = get_simple_path(enemyPos, closest_node2d)
		#print (closest_node2d.get_pos())
		#print (enemyPos)

func get_closest_node2d(array_of_node2ds, enemyLocation):
    var min_node = null
var min_distance_squared = 9999999999999
for node2d in array_of_node2ds:
	var distance_squared = enemyLocation.distance_squared_to(node2d.get_pos())
	if distance_squared < min_distance_squared:
		min_distance_squared = distance_squared
		min_node = Node2D
return min_node

Second issue is with bullets, I am essentially creating instances of bullets that are NOT children of the player, but associating their spawn location with a Position2D node in front of the player, grabbing the Player’s rotation, and trying to move the bullet in a straight line in that same angle.

I have accomplished this to a degree, but whenever more than a single bullet is fired, the first bullet stops it’s movement, and the second bullet moves until another is fired.

Thank you in advance to anyone who takes the time to help me out, I hate to take your time away, but I am sure that there are people that do stuff like this in their sleep, and I am in dire need of your sage wisdom. :slight_smile:

:bust_in_silhouette: Reply From: aozasori

I see a problem in get_closest_node2d. It is returning the Node2D class… I’m guessing you wanted your loop var node2d, and autocomplete made a substitution.

for node2d in array_of_node2ds:
    var distance_squared = enemyLocation.distance_squared_to(node2d.get_pos())
    if distance_squared < min_distance_squared:
        min_distance_squared = distance_squared
        min_node = Node2D ## <-- here

Other common reasons for null are the path to the node is wrong or the node at that path is not yet ready.

I suggest this as an alternative method for accessing the players.
First add the player nodes to a group (eg, "players"), then make these changes to the script:

extends Navigation2D
var path = []
var closestPos = Vector2(0,0)
var enemyPos = Vector2(0,0)

func _ready():
    set_process(true)

func _process(delta):
	## use the group to get the players instead
	var playerPos = get_tree().get_nodes_in_group("players")

	for N in self.get_children():
		if N.get_child_count() >0:
			enemyPos = N.get_pos()
			var closest_node2d = get_closest_node2d(playerPos, enemyPos)
			path = get_simple_path(enemyPos, closest_node2d)

## make sure you are returning the intended value
func get_closest_node2d(array_of_node2ds, enemyLocation):
	var min_node = null
	var min_distance_squared = 9999999999999
	for node2d in array_of_node2ds: ## <--
		var distance_squared = enemyLocation.distance_squared_to(node2d.get_pos())
		if distance_squared < min_distance_squared:
			min_distance_squared = distance_squared
			min_node = node2d ## <--
	return min_node

As for your other problem, i don’t think you’ve provided enough information. Seeing the bullet’s scipt would be helpful.