You can see a video of the problem in action here: https://youtu.be/qfL8FFPDjis
After one wave of enemies is defeated, the next wave is set to spawn in with a spawn animation. The twist is that they appear without the animation for a frame, before beginning the animation as expected.
When examining the code for the specific Puffer enemy shown in the video, the code that makes it visible and the part that makes it play its animation are closely related.
for a start, it checks whether or not it is a “frontline” or “reinforcement” of the specific ambush, which determines whether or not it will be visible by default, as well as whether or not it bothers using the spawn animation. The individual in the video is of course a "reinforcement” type, whose code is as follows:
## (There are other elifs and ifs before this for the other types of enemy in an ambush)
elif spawn_type == "reinforcement" and Global.ambush_current == ambush and Global.ambush_wave == ambush_wave:
visually_apparent = true
$AnimationPlayer.play("spawn")
$SpawnTimer.start()
state = States.ACTIVE
## IF THE ENEMY IS VISIBLE
if visually_apparent:
show()
## More code follows this that isn't important here.
By the end of this sequence, the enemy will begin playing its animation and begin being visible. It has never been instructed to play any animation before this. Also, for the record, I checked having the show() function play before the animation rather than setting visually_apparent to true in its stead, though it made no difference.
The Puffer’s node structure is simple, and displays as follows:
Puffer [CharacterBody2D]
Sprite [AnimatedSprite2D]
HealthBar [Instantiated Scene, Node2D]
CollisionBox [CollisionShape2D]
SpawnTimer [Timer]
AnimationPlayer [AnimationPlayer]
The relationship between AnimationPlayer and Sprite is what you’d expect.
Here’s the spawning animation. Needless to say, RESET just sets the Sprite to display at default position and modulate.

Hopefully somewhere along here I have said something that rings as an obvious rookie error. It’s worth stating that all nodes in the game that animate right out of them being visible like this have this same problem, and any that (like the score numbers that come off of defeated enemies) are only seemingly not broken because their RESET has been set to align with the beginning of their spawning animation. This is fine as a workaround for an object that only has one animation and incredibly simple behaviour, but strikes me as unwise for complex enemies.