Parallax problem with resolution

Godot Version

4.2

Question

Hey, I was trying to make an infinite moving background for my menu and I figured that using parallax would be the best way to do it(?)
Though, when I was messing with the stretch flags in the Project Settings so that it’d work with different resolutions, I encountered a bug I couldn’t seem to fix.

My display Stretch settings are:
Mode - canvas_item
Aspect - expand

When the screen is too big, it’ll show the godot default background while the actual parallax slowly creeps in.
This is how it looks like:


(The placeholder dirt should cover the entire screen)

It also happens on the right if i stretch the screen enough to the sides.
I could just make the background bigger, but it’d only take more streching to encounter the problem again.

Add a script to the parallax layer that sets the motion_mirroring variable to the viewport size (or a fraction of it) and link that to the window resize notification.

Im sorry, but im really new to all of this, and didn’t understand half of what you meant.
By “window resize notification” do you mean an event?

I tried changing motion_mirroring every frame in _process, but it really didn’t change anything at all.

oh, I see the problem… you’re supposed to use a texture that is at least half the size of the viewport for the ParallaxLayer to work properly.

If the length of the viewport axis is bigger than twice the repeated axis size, it will not repeat infinitely, as the parallax layer only draws 2 instances of the texture at any given time.

so I think this object will not work at all for your purpose of repeating a smaller texture
I think sprites do not support infinitely repeating, but I know a mesh (a single quad in this case) would work with the right math in the shader.
If you don’t know how to figure that out I’ll provide you an example as soon as I can.

1 Like

Heya there again,
For the background texture im using a tilemap so i just painted it so it’d cover the whole viewport. But because my Test Resolution is different from the actual one im working with, it doesn’t seem to work that well.
I haven’t thought of using a shader until you mentioned it, and it does sound like a good idea, but I have no idea how to work with shaders… :–)

This is all you really need to get an infinite texture. Any CanvasItem-derived Node, queue_redraw() when you want to draw it. Custom _draw callback that renders what you want. In this case a rect the size of the viewport using the texture stored in the Sprite2D object, but you could use any texture that’s registered in the RenderingServer. I set te repeat for the CanvasItem in the editor, but you an also set it in code. You can offset it to simulate movement and do anything you can imagine. I think this is the simplest way to guarantee you’re drawing on the whole viewport. I am sure there are other ways.

extends Sprite2D

func _process(_delta):
	queue_redraw()

func _draw():
	RenderingServer.canvas_item_add_texture_rect(get_canvas_item(), get_viewport_rect(), texture.get_rid(), true)

Thank you so much for the help. It works perfectly now.
It took me some time to understand how the code worked, but after browsing the docs and looking stuff up online, I managed to edit it so that it’d scroll.

extends Sprite2D

var textpos = Vector2(0, 0)

const scroll_angle = 110
const scroll_speed = 65
var angular_speed = Vector2(cos(deg_to_rad(scroll_angle))*scroll_speed, sin(deg_to_rad(scroll_angle))*scroll_speed)

func _process(_delta):
	textpos += angular_speed * _delta
	textpos.x = fmod(textpos.x, texture.get_size().x)
	textpos.y = fmod(textpos.y, texture.get_size().y)
	queue_redraw()

func _draw():
	RenderingServer.canvas_item_add_texture_rect(get_canvas_item(), Rect2(textpos - Vector2(texture.get_width(), texture.get_height()), get_viewport_rect().size + Vector2(texture.get_width()*2, texture.get_height()*2)), texture.get_rid(), true)