I’d like to make parallax background but what I see in the tutorial section about parallax is more like faux parallax effect. It’s not showing how the majority of games use the parallax background (scrolling tiled image).
Godot has nodes dedicated to having a parallax background - ParallaxBackground>ParallaxLayer>sprite.
Gamemaker has a checkbox for a sprite to have it tile horizontally/ vertically.
I’d like to know how to get that in Defold.
You create a sprite that moves itself in a direction constantly, and resets it’s position to the initial position when it goes out of bounds, pretty much like what the Runner tutorial does for the platforms
Seems pretty bad workaround, since in situation where it’s needed to have image repeat 2x time to cover screen, it’s needed to manage 3 images to do movement. And adding more layers of parallax multiply sprites needed to manage.
@Pkeod says that it needs to be power of 2. In real world it’s rare to have parallax layers to be power of 2. Although I thought that it should be possible with shaders, but my knowledge of them is close to 0.
It’s because of the way Defold makes atlases and uvs. The width and height don’t have to be even. You could have 256x512 and it would work. You could also make some blank space in your image such as having top 50px of your image be transparent, but important thing is width and height both be powers of 2 otherwise that method won’t work right.
Neither of TheKing’s methods are bad or a workaround, they are -the- ways to do it. Godot and Gamemaker have these options built-in…but how do you think they are doing it? It is either in a shader, or by drawing the same image repeatedly and offsetting them.
In fact you can look at Godot’s code (background, layer) and see. Basically all the ParallaxBackground node does is offset all its child layers whenever the camera moves. The mirroring feature looks like a shader thing, presumably the same as Pkeod’s method (but with all the work done for you already).
Anyway. So are you using premade assets you find? Can you simply scale them to a power of 2 size? I imagine it’s hard to find assets that match the exact size you want anyway. It should also be possible to wrap the UVs with a non-power of 2 size, provided you input the image size into your shader. I seem to recall there was a way to calculate the remapped UVs inside an atlas (see this thread), but I don’t remember how much of pain it was to do. Defold definitely could be better in this area.
The easiest way is to have each layer of the parallax scroll in a separate game object each containing enough images to cover your screen and then move them with a speed dependent upon the z value of the game object. Easy and not a workaround, but you have to do some work yourself.
This is what I’ve done a couple times. Works perfectly well. Calculate it out before hand, and pretty simple. If you have a tile-able (repeating) image and set it to update position at a percentage of camera position, basically making it scroll slower than your mid-ground tilemap, you will know based on total level size and image size how many sprites you need, OR, in code spawn/delete them end-to-end as needed, so there are never more than 2 (if the image is full screen width).
At the moment separate object route for me would be easiest, but I’d like to get shader working which is not cooperating with me.
this is supposed to be 10x tiling like @Pkeod showed in example (at the moment moving offset):
go.property("move_vertical", false)
function init(self)
BG_CTRL_URL = msg.url()
self.bgs = {}
self.speeds = {}
self.pos_y = go.get_position().y
end
function update(self, dt)
local cam_x = CAM_POS.x
local cam_y = CAM_POS.y
for _,bg in ipairs(self.bgs) do
go.set(bg.id, "position.x", (1-(0.1*bg.no))*cam_x)
if self.move_vertical then go.set(bg.id, "position.y", self.pos_y + 0.5*(1-(0.05*bg.no))*cam_y) end
if bg.speed ~= 0 then
local pos = go.get_position(bg.id).x
if self.speeds[bg.no] == nil then self.speeds[bg.no] = 0 end
self.speeds[bg.no] = self.speeds[bg.no] + bg.speed
go.set(bg.id, "position.x", pos + self.speeds[bg.no])
end
end
end
function on_message(self, message_id, message, sender)
if message_id == m.REGISTER then
table.insert(self.bgs, {id = message.id, no = message.no, speed = message.speed} )
end
end
function final(self)
BG_CTRL_URL = nil
end
You can check move_vertical property, if you want also vertical parallax effect.
bg.script:
go.property("no", 0)
go.property("speed", 0)
local m = require "messages" -- module with available messages, for convenience and pre-hashing
function init(self)
assert(self.no ~= 0, "Provide no of bg")
if self.no < 10 then
timer.delay(0.1, false, function()
msg.post(BG_CTRL_URL, m.REGISTER, {id = go.get_id(), no = self.no, speed = self.speed} )
end)
end
end
where m.REGISTER is:
hash("register")
I do specify in each bg properties:
No - is my arbitrary number of layer - closer to 0 are far layers, and closer to 10 are slower, closer layers (10 is a static layer - not moving)
Speed - it is used for some constantly floating layers like clouds
All you need to do for this collection to work is to constantly save camera’s (or just hero’s) position in this global variable - CAM_POS
Since several people told me that Defold get imprecise positioning when moving the camera far from 0,0, so I’m playing it safe and move world instead (just like in my example of TrueTileCollision). I have a bit simpler solution in my head for moving multiple sprites for a background but I wanted to get a more elegant approach for that.
This is not unique to Defold it’s every game engine because of the way computer numbers work. Most major games move the world around the player to solve this common problem.
A good suggestions is to read up on what floating point precision actually is and how it manifests itself. It’s a vital thing that is recurring in all engines.
please help me! I don’t understand this code: “m.REGISTER is hash(“register”)”…how and where can I declarate this “m”?
I’m sorry but I’m new in Defold and Lua!!