DEV Community

Kacper Baryłowicz
Kacper Baryłowicz

Posted on

Godot4 2D: Enemy Spawn Radious - problem with spawning enemy on player, no infinity loops

Hi!

Below is my Godot 4 code that addresses the problem of enemies spawning inside the player. The code is safe from infinite loops and reliably returns the x and y positions where an enemy should spawn. The spawn radius dynamically adjusts based on the player's scale, and you can set both minimum and maximum distances for the enemy's spawn position.

Feel free to discuss if you have better solutions or improvements. This code was used in my game Evolution Conquer, and the full open-source code can be found on my GitHub: evolution-conquer-source-code.

Required Nodes:

Area2D: The script should be attached to an Area2D node.

SpawnRadious: A child node of type Area2D, with a CircleShape2D to define the spawn radius.

You will need to implement your own enemy generation logic. Additionally, it’s advisable to handle cases where the enemy spawns outside the game boundaries, such as by ensuring the enemy moves back towards the playable area.

extends Area2D

# spawn_radius & spawn_center values here are only
# placeholders, they will change from collision shape radious
# and player position
var spawn_radius = 1000
var spawn_center = Vector2(0, 0)

# spawn_radious < x < spawn_radious_limitation 
# x - position where enemy will apear
@export var spawn_radious_limitation = 2000

var parent
var spawn_radious_node
var spawn_radious_node_shape

func _ready():
    parent = get_parent() as Node2D
    spawn_radious_node = get_node("SpawnRadious")
    spawn_radious_node_shape = spawn_radious_node.shape as CircleShape2D
    spawn_radius = spawn_radious_node_shape.radius * parent.scale.x

func get_spawn_position():
    # sometimes is a trouble with getting parent in _ready() funcion
    if parent == null:
        parent = get_parent() as Node2D
        spawn_radious_node = get_node("SpawnRadious")
        spawn_radious_node_shape = spawn_radious_node.shape as CircleShape2D
        spawn_radius = spawn_radious_node_shape.radius * parent.scale.x

    # getting player position
    var spawn_center = parent.position
    print("spawn center: ", spawn_center)
    print("spawn radious: ", spawn_radius)

    # calculation enemy position
    var angle = randf_range(0, PI * 2)
    var distance = randf_range(spawn_radius, spawn_radius + spawn_radious_limitation) 

    var position_x = spawn_center.x + cos(angle) * distance
    var position_y = spawn_center.y + sin(angle) * distance

    var spawn_position = Vector2(position_x, position_y)
    print("spawn_position: ", spawn_position)

    return spawn_position

Enter fullscreen mode Exit fullscreen mode

Top comments (0)