Adding parallax layer in Godot offsets sprite

Viewed 353

I added a parallax background and layer in my little world scene. The problem is, when I add a parallax layer, and set the motion scale to some value, the sprite gets offseted when I run the game. The weird offset seems to be related to the dimensions of the Window and the motion scale. I do not want this offset, I just want all my parallax layers to start from the top left corner (as it is in my setup) and then parallax from there. I have a snippet of my set up and the running game: My setup

When I run the game

3 Answers

I think its related to an apparently persistent bug, but you can kinda compensate the offset.

Multiplying the scale by half your window size should give you the proper offset, multiply by -1 and apply it.

Im linking the github issue, comments may interest you.

The big offset jump is caused by the Parallax nodes calculating the offset when the Camera2D updates upon entering the scene tree or the next process frame.

This is a bummer when, you know, your camera doesn't start at (0, 0).

Here's a workaround to offset the parallax layers to the positions they were in editor:

extends ParallaxBackground

func revert_offset(layer: ParallaxLayer) -> void:
    # Cancel out layer's offset. The layer's position already has 
    # its motion_scale applied.
    var ofs := scroll_offset - layer.position
    if not scroll_ignore_camera_zoom:
        # When attention is given to the camera's zoom, we need to account for it.
        # We can use viewport's canvas transform scale to which the camera has
        # already applied its zoom.
        var canvas_scale = get_viewport().canvas_transform.get_scale()
        # This is taken from godot source: parallax_background.cpp
        # I don't know why it works.
        ofs /= canvas_scale.dot(Vector2(0.5, 0.5))
    layer.motion_offset = ofs

func _ready() -> void:
    for layer in get_children():
        if layer is ParallaxLayer:
            revert_offset(layer)

I can think of a couple caveats:

  1. This only works if the Camera2D is after the ParallaxBackground node in the scene tree.

ParallaxBackground waits for moved events from the camera. If the camera enters the scene tree before ParallaxBackground, it will emit the moved event, but PB will not receive it to update its offset. Then when PB is ready it will try to revert offsets that haven't been applied yet.

  1. Does not account for rotation (nor did I test it).

A last note: If the camera is moving and a parallax layer is moving too much and showing the clear color, look into Camera2D and ParallaxBackground limit properties.

Alright, I figured out a solution to this issue. I manually tried offsetting with different motion scale values to see what works with what and used desmos to figure out a simple linear expression. You are going to create a script and attach it to every parallax layer you have. In the script, calculate offset by with the following:

motion_offset.x = ((window_width / 2) * (motion_scale.x)) - (widow_width / 2)

Until the developers fix this issue, this is probably going to be your best bet imo.

Related