Repeating AnimatedSprite

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By theboifgyapi

Recently I asked a question about how to fix a sprite to the camera on the x axis. the solution i was given did infact work, but it locked down the y axis as well. the effect i am trying to create is lava rising up on the screen, but the level is not fixed to the camera, rather it has its own y position, which is rising constantly. Now I’ve given up on locking it to the camera, rather now I want to know if It’s possible to make an AnimatedSprite repeat horizontally. the only three criteria are that it needs to be animateable, the y position can be changed, and the camera always sees it, unless its above it enough to be offscreen.

:bust_in_silhouette: Reply From: Zylann

There are many ways to do this, but I can explain one.

You should be able to do this in several steps.
First, your animation needs to be tileable, so it can be repeated horizontally across the screen without seams.
This raises the question about how your animation should look like:

  • Is is the same pattern repeating vertically as well?
  • Or does it have two animations, one at the top (splashes) and then something repeating downwards (bubbles) ?
  • Or is it an entire animated vertical strip, high enough so it can cover the screen?

Once you figured out how to make one vertical strip arranged in one of those three ways, you can save one strip as a LavaStrip scene, then look into repeating it horizontally.
Create a LavaRoot node under the root of your level, and put one lava strip as child. Then, duplicate it several times horizontally, so that you end up with something like this:

- LavaRoot (Node2D) <-- this one will raise slowly
    - LavaVerticalStrip
    - LavaVerticalStrip2
    - LavaVerticalStrip3
    - ...

You can do that in editor, or using a script by calling duplicate() and moving the copy to the right using something like .position += Vector2(lava_strip_width, 0).
The amount of copies required should be just enough to cover the area visible by the camera.

Then, to make it look infinite, we can translate LavaRoot along the X axis by some amount depending on the camera X position, so that it will always be shown.

You can do this in a script on LavaRoot:

func _process(delta):
    position.x = camera_position.x

However that will make the lava follow the camera along X, which will look static. Here is a trick to make it look like it is part of the level:

func _process(delta):
    position.x = stepify(camera_position.x, lava_strip_width)

This will make the X position change by increments that are the same width as the repeated strips of lava, so it will appear fixed inside the world, while in fact it keeps all strips of lava in view. Since all strips are the same, the illusion is seamless.

I wrote two variables here without explaining how to get them, to keep the logic clear.
lava_strip_width is basically the width of each of your strips, you should be able to get it from the texture you used for the animation.
camera_position can be obtained either by using get_node(path).position with the path to your camera, or by using the following code:

func _get_camera_center():
	var ctrans = get_canvas_transform()
	var top_left = -ctrans.get_origin()
	var vsize = get_viewport_rect().size
	var center = (top_left + 0.5*vsize) / ctrans.get_scale()
	return center

Note 2:
I wrote all this by head, I haven’t tested any of this, so it’s possible that some adjustments may be needed. I know however that this approach should work well, I hope it is what you were looking for.