• Godot Help
  • Randomize Character's starting animation frame

Hi fellow godots

I have an enemy character that shoots projectiles whenever its animations lands on a certain frame. I also want to duplicate this enemy all over the level.

Simply put, I want to randomize when this enemy starts its animation frame, to offset when its projectiles are fired. At the moment, ALL enemies fire their projectiles at the same time, eek.

This is what I've tried so far...

1) Exporting an integer variable on the enemy, to be used to manually set the animation frame of each duplicated enemy.

extends CharacterBody2D
@export var anim_start_frame :int
func _ready():
	$AnimatedSprite2D.frame = anim_start_frame

2) No export variable, only using the randi() function.

extends CharacterBody2D
func _ready():
	$AnimatedSprite2D.frame = randi() % $AnimatedSprite2D.frames.get_frame_count("Idle")

Neither of these approaches did the trick, the latter throwing an error...

Invalid get index 'frames' (on base: AnimatedSprite2D ()')

I'm also using an AnimationPlayer with this enemy and have a script on there signalling when it changes animation frames, wondering if I can use that for this?

  • I have found a solution elsewhere on the interwebs, simple as I thought and sharing here for posterity.

    I created a new function where all the magic happens referring to the AnimationPlayer node.

    func play_randomized(Idle : String):
    	randomize()
    	$AnimationPlayer.play(Idle)
    	var offset : float = randf_range(0, $AnimationPlayer.current_animation_length)
    	$AnimationPlayer.advance(offset)

    Then under the on_ready() area, simply...

    func _ready():
    	play_randomized("Idle")

I added a Timer control to randomize the frame.

By using print statements, I can see this works, in that different frames are chosen for the different duplicated enemies at on_ready(). However, only the first iteration is realised, the cycling syncs up again on subsequent frames.

func _ready():
	$Timer.start()

func _on_timer_timeout():
	$AnimatedSprite2D.frame = randi_range(0,7)
	print("FRAME SELECTION DONE")
	print($AnimatedSprite2D.frame)

Hmmm, now just to figure out how to continue playing from the starting frame instead of reverting back to start...

I have found a solution elsewhere on the interwebs, simple as I thought and sharing here for posterity.

I created a new function where all the magic happens referring to the AnimationPlayer node.

func play_randomized(Idle : String):
	randomize()
	$AnimationPlayer.play(Idle)
	var offset : float = randf_range(0, $AnimationPlayer.current_animation_length)
	$AnimationPlayer.advance(offset)

Then under the on_ready() area, simply...

func _ready():
	play_randomized("Idle")