How to set different targets for each enemy instance?

Godot Version

4.3

Question

`So I have an enemy which targets and attacks sheep that are being spawned and are moving towards a certain point. I have an area2d node within the enemy scene that detects these sheep. I use signals to append these to an array:

var target: CharacterBody2D
var sheep_inside: Array[CharacterBody2D]
func _on_detection_area_body_entered(body: CharacterBody2D) -> void:
	sheep_inside.append(body)


func _on_detection_area_body_exited(body: CharacterBody2D) -> void:
	sheep_inside.erase(body)

then in the physics process:

func _physics_process(_delta) -> void:
	if not sheep_inside.is_empty():
		target = sheep_inside[0]
		(the rest of the movement functionality and all that)

The problem here is that whenever I spawn another enemy instance, if there are more than one enemy, and if they are close together, they target the same sheep since the target is set to the array’s index 0. I can’t just set it to 1 or something else since it would say that the index is out of bounds. If I check if there are this amount of sheep and set the target to a certain index of the array, it switches immediately right when another sheep enters its area2d for detection which is a weird behavior that I do not want.

What I want to happen is if another instance of the enemy scene is already attacking the target_sheep, the other instance would find another target to attack. How can I do that? If there are better approaches to this, please don’t hesitate to suggest it as well. Thanks in advance!
`

Try to tuse shape cast node, it the not the work of area.
Like this:

for i in range(shape_cast.get_collision_count()):
   var body = shape_cast.get_collider(i)
   #Check if body is sheep, then append it to the array if it does not exist in it.

Also you need to setup the shape cast properly.
You can read the docs for learn more.

Then define a variable like attacking or anything else, then make it true/false based on condition so from another enemy, it can detect it. Or for make it more easy, define the variable in the sheep script and change it based on condition, so enemy can detect it.

I don’t really see why I need to use shapecast2d instead of area2d since I still haven’t used that node yet and I don’t think more collision detection is necessary for every instance of the enemy. Can you explain it more clearly if that’s alright? Also what do you mean by

Then define a variable like attacking or anything else, then make it true/false based on condition so from another enemy, it can detect it.

And where exactly?

Also, I think the main problem is that I am setting the target as the array’s index 0 but as you’ve read in my post above, there seems to be no other way. I don’t think the problem related to that has been solved yet? Or am I tripping?

1 Like

Oh sorry, misread the topic.

So I have different concept for it, one of them is that enemies will have the array of all sheeps (not only inside the area), so they will find the nearest one and if a enemy already attacking that, then another enemy will find the next target. Agree it if you like, then I can guide/help you further.

1 Like

Yes please elaborate, that would be great!

1 Like

Ok, I will continue at night (5-6 hrs later).
Edited: Tommorow, I will tell it properly for sure. You need to wait more 8-9 hrs. Actually I was busy.

1 Like

So I worked it out a couple of days ago, it just slipped my mind to update, woops…

So I still used an area2d to detect things. I added a global variable(an array to track all sheeps)

var all_sheep: Array[CharacterBody2D]

Then the changes I made inside the sheep’s script is to append them whenever they spawn and erase then whenever their health is <= 0.

func _ready() -> void:
	GlobalData.all_sheep.append(self)

func _process(_delta) -> void:
	if attacker_health <= 0:
		GlobalData.all_sheep.erase(self)
		queue_free()

The changes I made inside the enemy’s script is as follows:

  1. Whenever a body enters a detection area, if the body is in GlobalData.all_sheep, then append it to sheep_inside and erase it when it exits the area:
func _on_detection_area_body_entered(body: CharacterBody2D) -> void:
	if body in GlobalData.all_sheep:
		sheep_inside.append(body)


func _on_detection_area_body_exited(body: CharacterBody2D) -> void:
	sheep_inside.erase(body)
  1. Created a variable to track if the enemy variable already as a value assigned to it. I then used it as a condition to have the enemies value get randomized.
var have_no_target: bool = true

func _physics_process(_delta) -> void:
	if not sheep_inside.is_empty():
		if have_no_target and target == null and not is_instance_valid(target):
				target = sheep_inside.pick_random()
				
			if not target == null:
				GlobalData.all_sheep.erase(target)
				have_no_target = false
			elif target == null:
				have_no_target = true

I also erase the target from the GlobalData.all_sheep array when it is not null, it is so that the sheep instance (the target’s current value) won’t be appended inside the sheep_inside array of other enemy instances.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.