|
@@ -0,0 +1,231 @@
|
|
|
+.. doc_2d_parallax:
|
|
|
+
|
|
|
+2D Parallax
|
|
|
+===========
|
|
|
+
|
|
|
+Introduction
|
|
|
+------------
|
|
|
+
|
|
|
+Parallax is an effect used to simulate depth by having textures move at different speeds relative to the camera. Godot
|
|
|
+provides the :ref:`Parallax2D<class_parallax2d>` node to achieve this effect. It can still be easy to get tripped
|
|
|
+up though, so this page provides in-depth descriptions of some properties and how to fix some common mistakes.
|
|
|
+
|
|
|
+.. note::
|
|
|
+ This page only covers how to use :ref:`Parallax2D<class_parallax2d>`. This node is still experimental, so the
|
|
|
+ implementation might change in future versions of Godot. However, it is still recommended to use over the
|
|
|
+ :ref:`ParallaxLayer<class_parallaxlayer>` and :ref:`ParallaxBackground<class_parallaxbackground>` nodes.
|
|
|
+
|
|
|
+Scroll scale
|
|
|
+------------
|
|
|
+
|
|
|
+The backbone of the parallax effect is the :ref:`scroll_scale <class_parallax2d_property_scroll_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 away
|
|
|
+when scrolling, use a value lower than 1, with 0 bringing it to a complete stop. If you want something to appear closer
|
|
|
+to the camera, use a value higher than 1, making it scroll faster.
|
|
|
+
|
|
|
+.. image:: img/2d_parallax_size_viewport.webp
|
|
|
+
|
|
|
+The scene above is comprised of five layers. Some good :ref:`scroll_scale <class_parallax2d_property_scroll_scale>`
|
|
|
+values 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:
|
|
|
+
|
|
|
+.. video:: video/2d_parallax_scroll_scale.webm
|
|
|
+ :alt: A scene with five layers scrolling at different speeds
|
|
|
+ :autoplay:
|
|
|
+ :loop:
|
|
|
+ :muted:
|
|
|
+
|
|
|
+Infinite repeat
|
|
|
+---------------
|
|
|
+
|
|
|
+:ref:`Parallax2D<class_parallax2d>` provides a bonus effect that gives textures the illusion of repeating infinitely.
|
|
|
+:ref:`repeat_size<class_parallax2d_property_repeat_size>` tells the node to snap its position forward or back when the
|
|
|
+camera scrolls by the set value. This effect is achieved by adding a single repeat to all the child canvas items offset
|
|
|
+by the value. While the camera scrolls between the image and its repeat, it invisibly snaps back giving the appearance
|
|
|
+of a looping image.
|
|
|
+
|
|
|
+.. image:: img/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 same
|
|
|
+size or larger than your viewport **before** setting the :ref:`repeat_size<class_parallax2d_property_repeat_size>`. If
|
|
|
+you aren't able to obtain assets that are designed for this task, there are some other things you can do to better
|
|
|
+prepare your image in regards to size.
|
|
|
+
|
|
|
+Here is an example of a texture that is too small for its viewport:
|
|
|
+
|
|
|
+.. image:: img/2d_parallax_size_bad.webp
|
|
|
+
|
|
|
+We can see that the viewport size is 500x300 but the texture is 288x208. If we set the
|
|
|
+:ref:`repeat_size<class_parallax2d_property_repeat_size>` to the size of our image, the infinite repeat effect doesn't
|
|
|
+scroll properly because the original texture doesn't cover the viewport. If we set the
|
|
|
+:ref:`repeat_size<class_parallax2d_property_repeat_size>` to the size of the viewport, we have a large gap. What can we
|
|
|
+do?
|
|
|
+
|
|
|
+Make the viewport smaller
|
|
|
+^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
+
|
|
|
+The simplest answer is to make the viewport the same size or smaller than your textures. Click on
|
|
|
+``Project -> Project Settings -> Window`` and change the viewport height and width to match your background.
|
|
|
+
|
|
|
+.. image:: img/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 textures
|
|
|
+larger to fit your screen. Set the :ref:`scale<class_node2d_property_scale>` of the :ref:`Parallax2D<class_parallax2d>`,
|
|
|
+and all child textures scale with it.
|
|
|
+
|
|
|
+Scale the child nodes
|
|
|
+^^^^^^^^^^^^^^^^^^^^^
|
|
|
+
|
|
|
+Similar to scaling the :ref:`Parallax2D<class_parallax2d>`, you can scale your :ref:`Sprite2D<class_sprite2d>` nodes to
|
|
|
+be large enough to cover the screen. Keep in mind that some settings like
|
|
|
+:ref:`Parallax2D.repeat_size<class_parallax2d_property_repeat_size>` and
|
|
|
+:ref:`Sprite2D.region_rect<class_sprite2d_property_region_rect>` do not take scaling into account, so it's necessary to
|
|
|
+adjust these values based on the scale.
|
|
|
+
|
|
|
+.. image:: img/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 a
|
|
|
+:ref:`Sprite2D<class_sprite2d>` you'd like to repeat, but is too small, you can do the following to repeat it:
|
|
|
+
|
|
|
+- set :ref:`texture_repeat<class_canvasitem_property_texture_repeat>` to :ref:`CanvasItem.TEXTURE_REPEAT_ENABLED<class_canvasitem_constant_TEXTURE_REPEAT_ENABLED>`
|
|
|
+- set :ref:`region_enabled<class_sprite2d_property_region_enabled>` to ``true``
|
|
|
+- set the :ref:`region_rect<class_sprite2d_property_region_rect>` to a multiple of the size of your texture large enough to cover the viewport.
|
|
|
+
|
|
|
+Below, you can see that repeating the image twice makes it large enough to cover the screen.
|
|
|
+
|
|
|
+.. image:: img/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)``:
|
|
|
+
|
|
|
+.. image:: img/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 the :ref:`repeat_size<class_parallax2d_property_repeat_size>`
|
|
|
+value.
|
|
|
+
|
|
|
+.. image:: img/2d_parallax_single_expand.webp
|
|
|
+
|
|
|
+If the textures are centered on the ``(0,0)`` crossing, the infinite repeat canvas is only partly covered, so it
|
|
|
+only partly repeats.
|
|
|
+
|
|
|
+Would increasing ``repeat_times`` fix this?
|
|
|
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
+
|
|
|
+Increasing :ref:`repeat_times<class_parallax2d_property_repeat_times>` technically *would* work in some scenarios, but
|
|
|
+is 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 to
|
|
|
+understand 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 textures
|
|
|
+used in the parallax nodes fit inside the "infinite repeat canvas" starting at ``(0,0)``. That way, if
|
|
|
+:ref:`Parallax2D.repeat_size<class_parallax2d_property_repeat_size>` is set correctly, it should look something like
|
|
|
+this, with one single loop of the image the same size or larger than the viewport:
|
|
|
+
|
|
|
+.. image:: img/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 by :ref:`repeat_size<class_parallax2d_property_repeat_size>`), and when it reaches what's inside the yellow
|
|
|
+rectangle it zips the image forward to give the illusion of scrolling forever.
|
|
|
+
|
|
|
+.. image:: img/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:
|
|
|
+
|
|
|
+.. image:: img/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,
|
|
|
+:ref:`Parallax2D<class_parallax2d>` comes with a :ref:`scroll_offset<class_parallax2d_property_scroll_offset>` property
|
|
|
+used to offset where the infinite repeat canvas starts. As an example, if your image is 288x208, setting
|
|
|
+the :ref:`scroll_offset<class_parallax2d_property_scroll_offset>` to ``(-144,0)`` or ``(144,0)`` allows it to begin
|
|
|
+halfway 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, problems
|
|
|
+occur when we zoom out by setting the :ref:`Camera2D.zoom<class_camera2d_property_zoom>` to ``(0.5, 0.5)``:
|
|
|
+
|
|
|
+.. image:: img/2d_parallax_zoom_single.webp
|
|
|
+
|
|
|
+Even though everything is correctly set for the viewport at the default zoom level, zooming out makes it smaller than
|
|
|
+the viewport, breaking the infinite repeat effect. This is where
|
|
|
+:ref:`repeat_times<class_parallax2d_property_repeat_times>` can help out. Setting a value of ``3`` (one extra
|
|
|
+repeat behind and in front), it is now large enough to accommodate the infinite repeat effect.
|
|
|
+
|
|
|
+.. image:: img/2d_parallax_zoom_repeat_times.webp
|
|
|
+
|
|
|
+If these textures were meant to be repeated vertically, we would have specified a ``y`` value for the
|
|
|
+:ref:`repeat_size<class_parallax2d_property_repeat_size>`. The
|
|
|
+:ref:`repeat_times<class_parallax2d_property_repeat_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? We
|
|
|
+need to get creative! In this example, we stretch the sky higher, and grass sprite lower. The textures now support the
|
|
|
+normal zoom level and zooming out to half size.
|
|
|
+
|
|
|
+.. image:: img/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 assign
|
|
|
+the :ref:`Viewport.world_2d<class_viewport_property_world_2d>` of the first SubViewport to the second, so they have a
|
|
|
+shared 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 is
|
|
|
+understandably 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)
|
|
|
+:ref:`SubViewport<class_subviewport>`. Here's how it looks for a two player game:
|
|
|
+
|
|
|
+.. image:: img/2d_parallax_splitscreen.webp
|
|
|
+
|
|
|
+Of course, now both backgrounds show in both SubViewports. What we want is for some nodes to be visible in one viewport
|
|
|
+but not another. While technically possible, this is not a feature officially supported by Godot at the moment. There is
|
|
|
+currently a proposal to make this much simpler, so please stay tuned.
|
|
|
+
|
|
|
+As a workaround, you can do the following:
|
|
|
+
|
|
|
+- Set the first SubViewport's :ref:`canvas_cull_mask<class_viewport_property_canvas_cull_mask>` to only layer 1, so it displays all nodes with a :ref:`visibility_layer<class_canvasitem_property_visibility_layer>` of layer 1.
|
|
|
+- Set the second SubViewport's :ref:`canvas_cull_mask<class_viewport_property_canvas_cull_mask>` to only layer 2, so it displays all nodes with a :ref:`visibility_layer<class_canvasitem_property_visibility_layer>` of layer 2.
|
|
|
+- Set the :ref:`visibility_layer<class_canvasitem_property_visibility_layer>` of every node you want to display in both viewports to both layers 1 and 2.
|
|
|
+- Set the :ref:`visibility_layer<class_canvasitem_property_visibility_layer>` of the :ref:`Parallax2D<class_parallax2d>` node and all its descendants in the first :ref:`SubViewport<class_subviewport>` to layer 1.
|
|
|
+- Set the :ref:`visibility_layer<class_canvasitem_property_visibility_layer>` of the :ref:`Parallax2D<class_parallax2d>` node and all its descendants in the second :ref:`SubViewport<class_subviewport>` to layer 2.
|
|
|
+
|
|
|
+Previewing in the editor
|
|
|
+------------------------
|
|
|
+
|
|
|
+Prior to 4.3, the recommendation was to place every layer in their own
|
|
|
+:ref:`ParallaxBackground<class_parallaxbackground>`, enable the
|
|
|
+:ref:`follow_viewport_enabled<class_canvaslayer_property_follow_viewport_enabled>` property, and scale the individual
|
|
|
+layer. This method has always been tricky to get right, but is still achievable by using a
|
|
|
+:ref:`CanvasLayer<class_canvaslayer>` instead of a :ref:`ParallaxBackground<class_parallaxbackground>`.
|
|
|
+
|
|
|
+.. note::
|
|
|
+ Another recommendation is `KoBeWi's "Parallax2D Preview" addon <https://github.com/KoBeWi/Godot-Parallax2D-Preview>`_.
|
|
|
+ It provides a few different preview modes and is very handy!
|