How do I spawn an enemy around the player in so that the enemy doesn't appear in an unnecessary zone?

Godot Version

v4.4.1.stable.steam [49a5bc7b6]

Question

I don’t know how I can check the enemy’s spawn point to keep it within a certain radius, the only code I could think of was this one:

func spawn_enemy_around_player():
var enemy : Enemy = G.enemy_list.pick_random().instantiate()
var angle = randf_range(0,PI*2)
	enemy_spawn_point.position = player.position + Vector2(
	cos(angle)* (enemy_radius_around_player - randf_range(-enemy_radius_around_player/10,0)) ,
	sin(angle) * (enemy_radius_around_player - randf_range(-enemy_radius_around_player/10,0))
	)
	while enemy_spawn_point.position.distance_to(self.position) > area_radius:
		enemy_spawn_point.position = player.position + Vector2(
		cos(angle)* (enemy_radius_around_player - randf_range(-enemy_radius_around_player/10,0)) ,
		sin(angle) * (enemy_radius_around_player - randf_range(-enemy_radius_around_player/10,0))
		if enemy_spawn_point.position.distance_to(self.position) <= area_radius:
			break
	enemy.position = enemy_spawn_point.position
	add_child(enemy)

But it always went into an infinite loop, I want the enemies to spawn around the player and inside the circular arena, is there any other way than just not spawning the enemy, because I want to keep them constantly spawning.
Top-down game.

Hi!

You code seems pretty fine. Just one detail first, you don’t need these lines:

if enemy_spawn_point.position.distance_to(self.position) <= area_radius:
    break

as the while loop condition is already handling that.

The first thing you should try is using global_position instead of position. It’s impossible to tell without seeing your scene tree, but it may be related depending on how you sorted your nodes. Using global position would maybe help.

Also, you randomize the angle with var angle = randf_range(0,PI*2) outside of the while loop; you may also want to randomize it again in each iteration?

Another algorithm idea, just in case you want to try:

  • 1/ Compute a point to the right of the player in a distance within a min and a max.
  • 2/ Rotate that point around the player by a random angle between 0 and 360°.

That way, you’d have a random point inside a ring around the player, without the need of using a while loop (avoiding potential infinite loops). May not be perfect, I don’t know, but it’s an idea.

2 Likes

I was just typing up a response with a similar idea spawning a fixed distance and choosing a random direction but sixrobin wrote it out in better terms than I could. I feel like it would be a good change to make so OP doesn’t have all cos and sin equations in there.

Oh my God, I didn’t realize it myself, I forgot to just pick a random angle again. Thanks!

1 Like

Working code:

func spawn_enemy_around_player():
	var enemy : Enemy = G.enemy_list.pick_random().instantiate()
	var angle = randf_range(0,PI*2)
	enemy_spawn_point.position = player.position + Vector2(
	cos(angle)* (enemy_radius_around_player - randf_range(-enemy_radius_around_player/10,0)) ,
	sin(angle) * (enemy_radius_around_player - randf_range(-enemy_radius_around_player/10,0))
	)
	while enemy_spawn_point.position.distance_to(self.position) > area_radius:
		angle = randf_range(0,PI*2)
		enemy_spawn_point.position = player.position + Vector2(
		cos(angle)* (enemy_radius_around_player - randf_range(-enemy_radius_around_player/10,0)) ,
		sin(angle) * (enemy_radius_around_player - randf_range(-enemy_radius_around_player/10,0))
		)
	enemy.position = enemy_spawn_point.position
	add_child(enemy)
1 Like