2D Parallax

Introduction

Parallax is an effect used to simulate depth by having textures move at different speeds relative to the camera. Godotprovides theParallax2D node to achieve this effect. It can still be easy to get trippedup though, so this page provides in-depth descriptions of some properties and how to fix some common mistakes.

Note

This page covers how to useParallax2D, which isrecommended to use over theParallaxLayer andParallaxBackground nodes.

Getting started

The parallax node supports adding nodes that render things as children, so you can use one or many nodes to make up eachlayer. To begin, place each node or nodes you want to have scroll independently as a child of their own parallax node.Make sure that the top left of the textures used are at the(0,0) crossing, like in the image below. See the sectiononpositioning for why this is important.

../../_images/2d_parallax_size_viewport.webp

The scene above uses one prepared texture for the higher clouds in aSprite2D, but you couldjust as easily use multiple nodes spaced out to compose the layer.

Scroll scale

The backbone of the parallax effect is thescroll_scale property.It works as a scroll-speed multiplier, allowing layers to move at a different speed than the camera for each axis set.A value of 1 makes the parallax node scroll at the same speed as the camera. If you want your image to look further awaywhen scrolling, use a value lower than 1, with 0 bringing it to a complete stop. If you want something to appear closerto the camera, use a value higher than 1, making it scroll faster.

The scene above is comprised of five layers. Some goodscroll_scalevalues might be:

  • (0.7,1) - Forest

  • (0.5,1) - Hills

  • (0.3,1) - Lower Clouds

  • (0.2,1) - Higher Clouds

  • (0.1,1) - Sky

The video below displays how these values affect scrolling while in-game:

Infinite repeat

Parallax2D provides a bonus effect that gives textures the illusion of repeating infinitely.repeat_size tells the node to snap its position forward or back when thecamera scrolls by the set value. This effect is achieved by adding a single repeat to all the child canvas items offsetby the value. While the camera scrolls between the image and its repeat, it invisibly snaps back giving the appearanceof a looping image.

../../_images/2d_parallax_scroll.gif

Being a delicate effect, it's easy for unfamiliar users to make mistakes with their setup. Let's go over the "how" and"why" of a few common problems users encounter.

Poor sizing

The infinite repeat effect is easiest to work with when you have an image designed to repeat seamlessly and is the samesize or larger than your viewportbefore setting therepeat_size. Ifyou aren't able to obtain assets that are designed for this task, there are some other things you can do to betterprepare your image in regards to size.

Here is an example of a texture that is too small for its viewport:

../../_images/2d_parallax_size_bad.webp

We can see that the viewport size is 500x300 but the texture is 288x208. If we set therepeat_size to the size of our image, the infinite repeat effect doesn'tscroll properly because the original texture doesn't cover the viewport. If we set therepeat_size to the size of the viewport, we have a large gap. What can wedo?

Make the viewport smaller

The simplest answer is to make the viewport the same size or smaller than your textures.InProject Settings > Display > Window, change theViewport WidthandViewport Heightsettings to match your background.

../../_images/2d_parallax_size_viewport.webp

Scale the Parallax2D

If you're not aiming for a pixel-perfect style, or don't mind a little blurriness, you may opt to scale the textureslarger to fit your screen. Set thescale of theParallax2D,and all child textures scale with it.

Scale the child nodes

Similar to scaling theParallax2D, you can scale yourSprite2D nodes tobe large enough to cover the screen. Keep in mind that some settings likeParallax2D.repeat_size andSprite2D.region_rect do not take scaling into account, so it's necessary toadjust these values based on the scale.

../../_images/2d_parallax_size_scale.webp

Repeat the textures

You can also start off on the right foot by preparing child nodes earlier in the process. If you have aSprite2D you'd like to repeat, but is too small, you can do the following to repeat it:

Below, you can see that repeating the image twice makes it large enough to cover the screen.

../../_images/2d_parallax_size_repeat.webp

Poor positioning

It's common to see users mistakenly set all of their textures to be centered at(0,0):

../../_images/2d_parallax_single_centered.webp

This creates problems with the infinite repeat effect and should be avoided. The "infinite repeat canvas" starts at(0,0) and expands down and to the right to the size of therepeat_sizevalue.

../../_images/2d_parallax_single_expand.webp

If the textures are centered on the(0,0) crossing, the infinite repeat canvas is only partly covered, so itonly partly repeats.

Would increasingrepeat_times fix this?

Increasingrepeat_times technicallywould work in some scenarios, butis a brute force solution and not the problem it is designed to solve (we'll go over this in a bit). A better fix is tounderstand how the repeat effect works and set up the parallax textures appropriately to begin with.

First, check to see if any textures are spilling over onto the negative parts of the canvas. Make sure the texturesused in the parallax nodes fit inside the "infinite repeat canvas" starting at(0,0). That way, ifParallax2D.repeat_size is set correctly, it should look something likethis, with one single loop of the image the same size or larger than the viewport:

../../_images/2d_parallax_repeat_good_norect.webp

If you think of how the image scrolls across the screen, it starts by displaying what's inside the red rectangle(determined byrepeat_size), and when it reaches what's inside the yellowrectangle it zips the image forward to give the illusion of scrolling forever.

../../_images/2d_parallax_repeat_good.webp

If you have the image positioned away from the "infinite repeat canvas", when the camera reaches the yellow rectangle,half of the image is cut off before it jumps forward like in the image below:

../../_images/2d_parallax_repeat_bad.webp

Scroll offset

If your parallax textures are already working correctly, but you prefer it to start at a different point,Parallax2D comes with ascroll_offset propertyused to offset where the infinite repeat canvas starts. As an example, if your image is 288x208, settingthescroll_offset to(-144,0) or(144,0) allows it to beginhalfway across the image.

Repeat times

Ideally, following this guide, your parallax textures are large enough to cover the screen even when zoomed out.Until now, we have had a perfectly fitting 288x208 texture inside of a 288x208 viewport. However, problemsoccur when we zoom out by setting theCamera2D.zoom to(0.5,0.5):

../../_images/2d_parallax_zoom_single.webp

Even though everything is correctly set for the viewport at the default zoom level, zooming out makes it smaller thanthe viewport, breaking the infinite repeat effect. This is whererepeat_times can help out. Setting a value of3 (one extrarepeat behind and in front), it is now large enough to accommodate the infinite repeat effect.

../../_images/2d_parallax_zoom_repeat_times.webp

If these textures were meant to be repeated vertically, we would have specified ay value for therepeat_size. Therepeat_times would automatically add a repeat above and below as well.This is only a horizontal parallax, so it leaves an empty block above and below the image. How do we solve this? Weneed to get creative! In this example, we stretch the sky higher, and grass sprite lower. The textures now support thenormal zoom level and zooming out to half size.

../../_images/2d_parallax_zoom_repeat_adjusted.webp

Split screen

Most tutorials for making a split screen game in Godot begin by writing a small script to assigntheViewport.world_2d of the first SubViewport to the second, so they have ashared display. Questions often pop up about how to share a parallax effect between both screens.

The parallax effect fakes a perspective by moving the positions of different textures in relation to the camera. This isunderstandably problematic if you have multiple cameras, because your textures can't be in two places at once!

This is still achievable by cloning the parallax nodes into the second (or third or fourth)SubViewport. Here's how a setup looks for a two player game:

../../_images/2d_parallax_splitscreen.webp

Of course, now both backgrounds show in both SubViewports. What we want is for each parallax to only show in theircorresponding viewport. We can achieve this by doing the following:

  • Leave all parallax nodes at their defaultvisibility_layer of 1.

  • Set the first SubViewport'scanvas_cull_mask to only layers 1 and 2.

  • Do the same for the second SubViewport but use layers 1 and 3.

  • Give your parallax nodes in the first SubViewport a common parent and set itsvisibility_layer to 2.

  • Do the same for the second SubViewport's parallax nodes, but use a layer of 3.

How does this work? If a canvas item has avisibility_layer thatdoesn't match the SubViewport'scanvas_cull_mask, it will hide allchildren, even if they do. We use this to our advantage, letting the SubViewports cut off rendering of parallax nodeswhose parent doesn't have a supportedvisibility_layer.

Previewing in the editor

Prior to 4.3, the recommendation was to place every layer in their ownParallaxBackground, enable thefollow_viewport_enabled property, and scale the individuallayer. This method has always been tricky to get right, but is still achievable by using aCanvasLayer instead of aParallaxBackground.

Note

Another recommendation isKoBeWi's "Parallax2D Preview" addon.It provides a few different preview modes and is very handy!


User-contributed notes

Please read theUser-contributed notes policy before submitting a comment.