Tween rotation of ennemies are all synced

Godot Version

4.3

Question

Hi,
I’m spwaning a lot of ennemies on screen and I make them rotate through a tween a bit instead of animating them.

After some trials I get something “cute”, which is continuously rotating from -5 to +5 degrees in 1second:

# Ennemy spawning script 
func _ready():
	var tween = create_tween().set_loops()
	tween.tween_property($Sprite2D,"rotation", deg_to_rad(5),0.5)
	tween.tween_property($Sprite2D,"rotation", deg_to_rad(-5),0.5)

The issue I have is that ALL ennemies on screen are synchronized even if they appear at different times. Any idea how can I make a small rotation or time offset to the tween when spawning multiple ennemies ?

Thanks !

Can you show the REMOTE tree structure, please?

My first inclination is to recommend putting the initial animation inside the enemy script and not the enemy spawning manager script.

I have:
Root:

  • main scene
    L_ main script
    L_ spawner script
  • ennemy scene (characterbody2D)
    L_ Sprite2D
    L_ Collisionshape2D
    L_ ennemy script

The spawner calls an instance of ennemy with a timer.
I have no animation whatsoever anywhere so far

So far I used a randf_range function inside tween to change speed and it works. But I’m still looking fowrward to understand how to spawn tweens not all synchronized since spawns happens not all at the same time.

func _ready():
	var tween = create_tween().set_loops()
	tween.tween_property($Sprite2D,"rotation", deg_to_rad(5),randf_range(0.1, 0.5))
	tween.tween_property($Sprite2D,"rotation", deg_to_rad(-5),randf_range(0.1, 0.5))

Show us your Spawner script please.

If you’re preloading the enemy script, it might start the _ready() function before you even put it into the scene. You can easily check it with a print() statement.
You might want to consider having a separate function something like start_rotation() inside of which you create the Tween instead of the _ready() function, and you call that function only after your spawn the enemy into the scene.

Hi, this is the spawning script.
It only instantiate ennemies using random positions.

extends Node2D

@export var player : CharacterBody2D
@export var ennemy : PackedScene

var distance : float = 800
var can_spawn : bool

@export var ennemy_types : Array[Ennemy]

func _physics_process(delta):
	if get_tree().get_node_count_in_group("Ennemy") < 1500:
		can_spawn = true
	else:
		can_spawn = false

func spawn(pos : Vector2, elite: bool = false):
	var ennemy_instance = ennemy.instantiate()
	
	ennemy_instance.type = ennemy_types[min(minute, ennemy_types.size()-1)]
	ennemy_instance.position = pos
	ennemy_instance.player_reference = player
	get_tree().current_scene.add_child(ennemy_instance)
	
func get_random_position() -> Vector2:
	return player.position + distance * Vector2.RIGHT.rotated(randf_range(0,2 * PI))

func amount(number : int = 1):
	for i in range(number):
		spawn(get_random_position())

func _on_pattern_timeout():
	for i in range(75):
		spawn(get_random_position())

Where does the _on_pattern_timeout callback come from? I assume this is from a Timer Node? What’s the setting on that Timer Node?
If it’s a multiple of 0.5 (which is a duration of your Tween in the original code), then you have accidentally synchronised your spawning to the Tween rotation, so it will always look like they’re synchronised. You’d need to either set it off phase, or randomize the timer.

1 Like

Indeed ! timer was either a 1s or 10s !
Then I changed it to 1.1s and it now changes a bit the rotation when ennemies are spawn continuously, nevertheless when I pop-up 75 ennemies at the same time for a wave, they all appear synchronized still.

With your timer tweak and my rand_f function in the tween I now have something I wanted !
Thanks !!

1 Like