Graphics Parallax Backgrounds

chance

predictably random
Forum Staff
Moderator
I meant to comment on this when it was posted, so I'm glad it was bumped.

This is a simple and intuitive approach to view-based parallax scrolling. Your approach puts the room editor settings to good use. I typically define my background parameters in code. But I may be adopting your approach from now on.

This is an excellent addition to the Tutorials forum. Thank you.
 
Last edited:

NazGhuL

NazTaiL
I like the way you manage it. Same thing as Chance, I will use this method.

It's the first time I saw someone who use large font for a video tutorial. +1 ;)
 

toxigames

Member
Gamemaker supports up to 7 backgrounds through the room editor. Does this mean your solution is limited to using no more than 7 backgrounds? or is there a workaround for this?
 
Last edited:

GMWolf

aka fel666
Gamemaker supports up to 7 backgrounds through the room editor. Does this mean your solution is limited to using no more than 7 backgrounds? or is there a workaround for this?
The workaround would be to define everything in code, including drawing thet backgrounds.
But its fairly rare to need more than 8 backgrounds.

If you are using GMS2, you can have as many backgrounds as necessary.
 
C

Calum

Guest
This is super helpful but I seem to have a problem were just tapping the left or right arrow keys to change the direction of the player, this makes the backgrounds move (Kind of like a judder) very quickly.

I'm a complete noob at this and have so far only completed an Udemy course in making a game in GameMaker. :p Has anyone else experienced this problem?

Thanks in advance

C

EDIT - I seem to have minimised this a lot (though it still happens a smidge) by reducing the * in the first line of code from 5 to .05
 
Last edited by a moderator:
S

samyak

Guest
What is the method to add infinite scrolling backgrounds in GM 2?
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Okay, you need to set the background layers that you want to parallax in the room editor first, and make sure that the "Horizontal Tile" checkbox is flagged for all of them so that they loop while moving. You then need to simply set their layer position relative to the camera view. You WILL need to use some code though, as DnD doesn't have anything for manipulating layers currently. The code itself is fairly straightforward:

Code:
// STEP EVENT OF THE PLAYER OR SOME CONTROLLER OBJECT
var _cam_x = camera_get_view_x(view_camera[0]) ;
layer_x("parallax_background_1", _cam_x * 0.25); // Change the background layer name to whatever you use in the room editor
layer_x("parallax_background_2", _cam_x * 0.5);   // Change the 0.25 and 0.5 values to change the speed of the effect
That code will parallax two backgrounds with the camera used for Viewport[0]. You can add as many backgrounds as you wish too, just change the speed value for each of them...

Hope that helps!
;)
 
S

samyak

Guest
That would be the way :)
But if you would like a video tutorial nonetheless, you may be in luck as I am going to get a lot of free time soon to make a batch of videos. I will probably include one on Paralax scrolling in GMS2.
I have another problem-- I I had created a room(room1) in GM2 , with all objects , etc working. Then I created another room(room0), placed it before the previous room in resource tree. I place an object in the new room(room0) with an event with room_goto_next(); But in-game when I go to the next room(room1) from room0, all objects except a few don't appear. Plz help.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
If you swap the rooms around again does it work? So you go straight to room1?
 
S

samyak

Guest
If you swap the rooms around again does it work? So you go straight to room1?
Yes, by swapping, it works.
Thing to note that, in my problem,1. all objects, except for the o_player object, are invisible. They don't even work.
2. Objects that have health-bar drawn, or have text drawn , work.
 
Last edited by a moderator:
C

CobaltBW

Guest
Hey, great script. I've used a few parallax scrolling methods in the past, and this by far seems to be the best due to its flexibility and long-term ease of use. The only problem is, as stated before, that it has some major compatibility issues with Game Maker Studio 2 due to the transition to the new layer system. I've been able to work around this quite nicely and I'd like to offer up my own code, for the sake of anyone who might be trying to work it into their own GMS2 project. It's quite extensive code-wise, but in the long run it offers the same quality of life as the GMS 1.4 code.

As a bonus, not only have I made the code work with tilemaps and backgrounds, but I've worked in auto-scroll compatibility as well -- not only can your parallax backgrounds autoscroll simultaneously, but they'll scroll in proportion to how much parallax they've been assigned.

This code should go into the Create or Room Start event of your parallax object:
Code:
/// @description Get layer, tilemap, and background properties

//Get all layers
layers = layer_get_all();
var layers_length = array_length_1d(layers);

//Get all elements
elements = 0;
tilemaps = 0;
backgrounds = 0;
for (var l = 0; l < layers_length; l++;) {
    layer_elements = layer_get_all_elements(layers[l]);
    var layer_elements_length = array_length_1d(layer_elements);
    elements += layer_elements_length;
    //Get element types
    for (var e = 0; e < layer_elements_length; e++)
        switch layer_get_element_type(layer_elements[e]) {
        case layerelementtype_background:
            //Get background
            var bg = backgrounds;
            background_id[bg] = layer_elements[e];
            background_time[bg] = 0; //This is used to keep track of autoscrolling. We'll need it since the parallax will naturally override any autoscroll.
            background_layer[bg] = layers[l];
            var xo = layer_get_x(background_layer[bg]);
            var yo = layer_get_x(background_layer[bg]);
            background_parallax_hspeed[bg] = xo/100;
            background_parallax_vspeed[bg] = yo/100;
            backgrounds++;
            break;
        case layerelementtype_tilemap:
            //Get tilemap
            var tm = tilemaps;
            tilemap_id[tm] = layer_elements[e];
            tilemap_layer[tm] = layers[l];
            var xo = layer_get_x(tilemap_layer[tm]);
            var yo = layer_get_y(tilemap_layer[tm]);
            tilemap_parallax_hspeed[tm] = xo/100;
            tilemap_parallax_vspeed[tm] = yo/100;
            tilemaps++;
            break;
    }
}

//Enable this line of code if you need to debug
/*show_message("Found "
+ string(layers_length) + " layers, "
+ string(elements) + " elements, "
+ string(backgrounds) + " backgrounds, and "
+ string(tilemaps) + " tilemaps."
);*/
What this code does is get all of the layer, background, and tilemap information of the current room, so that we can reference it later when we try to scroll the background.

Put this code into one of your step or draw events (I personally recommend Draw Begin):

Code:
var cx = <<<insert camera view x, or whatever you happen to be using>>>
var cy = <<<camera view y>>>

//Update background properties
for (var bg = 0; bg < backgrounds; bg++) {
    var l = background_layer[bg];
    //Scrolling formulas
    var lx =(cx+background_time[bg]*layer_get_hspeed(l))*background_parallax_hspeed[bg];
    var ly =(cy+background_time[bg]*layer_get_vspeed(l))*background_parallax_vspeed[bg];
    //Perform parallax and autoscroll
    layer_x(l,lx);
    layer_y(l,ly);
    //Update autoscroll position
    background_time[bg]++; //Note: If you have a pause function or something similar, you may want to add an if statement here so that your background doesn't autoscroll when it's not supposed to.
}

//Update tilemap properties
for (var tm = 0; tm < tilemaps; tm++) {
    tilemap_x(tilemap_id[tm],cx*tilemap_parallax_hspeed[tm]);
    tilemap_y(tilemap_id[tm],cy*tilemap_parallax_vspeed[tm]);
}
The only thing you'll really need to do here is plug in your own views, which you may have set up differently than I do in my project. Other than that, the code should be pretty much good to go. Tell me if this helps.
 

GMWolf

aka fel666
Hey, great script. I've used a few parallax scrolling methods in the past, and this by far seems to be the best due to its flexibility and long-term ease of use. The only problem is, as stated before, that it has some major compatibility issues with Game Maker Studio 2 due to the transition to the new layer system. I've been able to work around this quite nicely and I'd like to offer up my own code, for the sake of anyone who might be trying to work it into their own GMS2 project. It's quite extensive code-wise, but in the long run it offers the same quality of life as the GMS 1.4 code.

As a bonus, not only have I made the code work with tilemaps and backgrounds, but I've worked in auto-scroll compatibility as well -- not only can your parallax backgrounds autoscroll simultaneously, but they'll scroll in proportion to how much parallax they've been assigned.

This code should go into the Create or Room Start event of your parallax object:
Code:
/// @description Get layer, tilemap, and background properties

//Get all layers
layers = layer_get_all();
var layers_length = array_length_1d(layers);

//Get all elements
elements = 0;
tilemaps = 0;
backgrounds = 0;
for (var l = 0; l < layers_length; l++;) {
    layer_elements = layer_get_all_elements(layers[l]);
    var layer_elements_length = array_length_1d(layer_elements);
    elements += layer_elements_length;
    //Get element types
    for (var e = 0; e < layer_elements_length; e++)
        switch layer_get_element_type(layer_elements[e]) {
        case layerelementtype_background:
            //Get background
            var bg = backgrounds;
            background_id[bg] = layer_elements[e];
            background_time[bg] = 0; //This is used to keep track of autoscrolling. We'll need it since the parallax will naturally override any autoscroll.
            background_layer[bg] = layers[l];
            var xo = layer_get_x(background_layer[bg]);
            var yo = layer_get_x(background_layer[bg]);
            background_parallax_hspeed[bg] = xo/100;
            background_parallax_vspeed[bg] = yo/100;
            backgrounds++;
            break;
        case layerelementtype_tilemap:
            //Get tilemap
            var tm = tilemaps;
            tilemap_id[tm] = layer_elements[e];
            tilemap_layer[tm] = layers[l];
            var xo = layer_get_x(tilemap_layer[tm]);
            var yo = layer_get_y(tilemap_layer[tm]);
            tilemap_parallax_hspeed[tm] = xo/100;
            tilemap_parallax_vspeed[tm] = yo/100;
            tilemaps++;
            break;
    }
}

//Enable this line of code if you need to debug
/*show_message("Found "
+ string(layers_length) + " layers, "
+ string(elements) + " elements, "
+ string(backgrounds) + " backgrounds, and "
+ string(tilemaps) + " tilemaps."
);*/
What this code does is get all of the layer, background, and tilemap information of the current room, so that we can reference it later when we try to scroll the background.

Put this code into one of your step or draw events (I personally recommend Draw Begin):

Code:
var cx = <<<insert camera view x, or whatever you happen to be using>>>
var cy = <<<camera view y>>>

//Update background properties
for (var bg = 0; bg < backgrounds; bg++) {
    var l = background_layer[bg];
    //Scrolling formulas
    var lx =(cx+background_time[bg]*layer_get_hspeed(l))*background_parallax_hspeed[bg];
    var ly =(cy+background_time[bg]*layer_get_vspeed(l))*background_parallax_vspeed[bg];
    //Perform parallax and autoscroll
    layer_x(l,lx);
    layer_y(l,ly);
    //Update autoscroll position
    background_time[bg]++; //Note: If you have a pause function or something similar, you may want to add an if statement here so that your background doesn't autoscroll when it's not supposed to.
}

//Update tilemap properties
for (var tm = 0; tm < tilemaps; tm++) {
    tilemap_x(tilemap_id[tm],cx*tilemap_parallax_hspeed[tm]);
    tilemap_y(tilemap_id[tm],cy*tilemap_parallax_vspeed[tm]);
}
The only thing you'll really need to do here is plug in your own views, which you may have set up differently than I do in my project. Other than that, the code should be pretty much good to go. Tell me if this helps.
Hey that very Cool, thanks for sharing the code!

I have been planning to make a tutorial for CMS 2. I may inspire myself by some of your code!
 

Landonbay

Member
Hey, great script. I've used a few parallax scrolling methods in the past, and this by far seems to be the best due to its flexibility and long-term ease of use. The only problem is, as stated before, that it has some major compatibility issues with Game Maker Studio 2 due to the transition to the new layer system. I've been able to work around this quite nicely and I'd like to offer up my own code, for the sake of anyone who might be trying to work it into their own GMS2 project. It's quite extensive code-wise, but in the long run it offers the same quality of life as the GMS 1.4 code.

As a bonus, not only have I made the code work with tilemaps and backgrounds, but I've worked in auto-scroll compatibility as well -- not only can your parallax backgrounds autoscroll simultaneously, but they'll scroll in proportion to how much parallax they've been assigned.

This code should go into the Create or Room Start event of your parallax object:
Code:
/// @description Get layer, tilemap, and background properties

//Get all layers
layers = layer_get_all();
var layers_length = array_length_1d(layers);

//Get all elements
elements = 0;
tilemaps = 0;
backgrounds = 0;
for (var l = 0; l < layers_length; l++;) {
    layer_elements = layer_get_all_elements(layers[l]);
    var layer_elements_length = array_length_1d(layer_elements);
    elements += layer_elements_length;
    //Get element types
    for (var e = 0; e < layer_elements_length; e++)
        switch layer_get_element_type(layer_elements[e]) {
        case layerelementtype_background:
            //Get background
            var bg = backgrounds;
            background_id[bg] = layer_elements[e];
            background_time[bg] = 0; //This is used to keep track of autoscrolling. We'll need it since the parallax will naturally override any autoscroll.
            background_layer[bg] = layers[l];
            var xo = layer_get_x(background_layer[bg]);
            var yo = layer_get_x(background_layer[bg]);
            background_parallax_hspeed[bg] = xo/100;
            background_parallax_vspeed[bg] = yo/100;
            backgrounds++;
            break;
        case layerelementtype_tilemap:
            //Get tilemap
            var tm = tilemaps;
            tilemap_id[tm] = layer_elements[e];
            tilemap_layer[tm] = layers[l];
            var xo = layer_get_x(tilemap_layer[tm]);
            var yo = layer_get_y(tilemap_layer[tm]);
            tilemap_parallax_hspeed[tm] = xo/100;
            tilemap_parallax_vspeed[tm] = yo/100;
            tilemaps++;
            break;
    }
}

//Enable this line of code if you need to debug
/*show_message("Found "
+ string(layers_length) + " layers, "
+ string(elements) + " elements, "
+ string(backgrounds) + " backgrounds, and "
+ string(tilemaps) + " tilemaps."
);*/
What this code does is get all of the layer, background, and tilemap information of the current room, so that we can reference it later when we try to scroll the background.

Put this code into one of your step or draw events (I personally recommend Draw Begin):

Code:
var cx = <<<insert camera view x, or whatever you happen to be using>>>
var cy = <<<camera view y>>>

//Update background properties
for (var bg = 0; bg < backgrounds; bg++) {
    var l = background_layer[bg];
    //Scrolling formulas
    var lx =(cx+background_time[bg]*layer_get_hspeed(l))*background_parallax_hspeed[bg];
    var ly =(cy+background_time[bg]*layer_get_vspeed(l))*background_parallax_vspeed[bg];
    //Perform parallax and autoscroll
    layer_x(l,lx);
    layer_y(l,ly);
    //Update autoscroll position
    background_time[bg]++; //Note: If you have a pause function or something similar, you may want to add an if statement here so that your background doesn't autoscroll when it's not supposed to.
}

//Update tilemap properties
for (var tm = 0; tm < tilemaps; tm++) {
    tilemap_x(tilemap_id[tm],cx*tilemap_parallax_hspeed[tm]);
    tilemap_y(tilemap_id[tm],cy*tilemap_parallax_vspeed[tm]);
}
The only thing you'll really need to do here is plug in your own views, which you may have set up differently than I do in my project. Other than that, the code should be pretty much good to go. Tell me if this helps.

Just ran this code straight, and it does part of what I want to. (would I be allowed to use this code for the game?)
so what if I have other layers that need to move at different speeds? is it the same process, what do I need to do?
 
I

Izumi

Guest
Hello! My code is just like yours but the Create event of the parallax object is running forever, so the game won't even load :(
Code:
parallax[0] = 0

for (var i=0; background_visible[i]; i++)
{
    parallax[i] = background_x[i]/100;
}
All my backgrounds are visible, do you have any idea what might be causing this?
 

GMWolf

aka fel666
Hello! My code is just like yours but the Create event of the parallax object is running forever, so the game won't even load :(
Code:
parallax[0] = 0

for (var i=0; background_visible[i]; i++)
{
    parallax[i] = background_x[i]/100;
}
All my backgrounds are visible, do you have any idea what might be causing this?
As far as i can tell, This should terminate. How many backgrounds do you have?
are you sure this code snippet is the one that istn terminating? (add a show_message at the end to check)
 
I

Izumi

Guest
As far as i can tell, This should terminate. How many backgrounds do you have?
are you sure this code snippet is the one that istn terminating? (add a show_message at the end to check)
I'm using 7 backgrounds. At the debugger, the value for i is tending to infinite. I added a show_message after the loop but it was never activated

EDIT:
Since my backgrounds will be visible all the time I just changed the loop stop condition to "i <= 7". Now is working fine
 
Last edited by a moderator:
C

CobaltBW

Guest
Just ran this code straight, and it does part of what I want to. (would I be allowed to use this code for the game?)
so what if I have other layers that need to move at different speeds? is it the same process, what do I need to do?
Sure, knock yourself out.

If you're talking about having different autoscroll speeds, it should already be set up for that. The code defines each layer's speed individually based on the background speed defined in the room editor.
The only problem with the way I have it set up is that if your parallax (x/y background offset) is 0, autoscroll speed will also be 0 by proxy of it being multiplied by parallax. If you don't want it to be affected by parallax, change lines 41-42 in the draw/step event so that it calculates the autoscroll offset separate from parallax, like so:
Code:
    var lx =(cx*background_parallax_hspeed[bg])+background_xoffset[bg];
    var ly =(cy*background_parallax_vspeed[bg])+background_yoffset[bg];
 
Sure, knock yourself out.

If you're talking about having different autoscroll speeds, it should already be set up for that. The code defines each layer's speed individually based on the background speed defined in the room editor.
The only problem with the way I have it set up is that if your parallax (x/y background offset) is 0, autoscroll speed will also be 0 by proxy of it being multiplied by parallax. If you don't want it to be affected by parallax, change lines 41-42 in the draw/step event so that it calculates the autoscroll offset separate from parallax, like so:
Code:
    var lx =(cx*background_parallax_hspeed[bg])+background_xoffset[bg];
    var ly =(cy*background_parallax_vspeed[bg])+background_yoffset[bg];
Hey man, nice job, I implemented your code to my game. The only problem is that one of the backgrounds(once it reaches the end) doesn't wrap and start again, it just diasappers, how would I make it to wrap around the screen?
 
G

Geoff Moore

Guest
This is awesome!! Is there any way I can still give the baclgrounds an x offset, so they don't all start at the 0 position of the room? Or will I just have to include blank space in the image?
 

GMWolf

aka fel666
This is awesome!! Is there any way I can still give the baclgrounds an x offset, so they don't all start at the 0 position of the room? Or will I just have to include blank space in the image?
You would have to define the offsets and paralax factors in code.
 
G

Geoff Moore

Guest
I see. How about if I wanted a background to scroll by itself (for example, a sky background with clouds), even when the view isn't moving? It would also be affected by the view's movement. Is it possible to do that and still use this method?
 
Last edited by a moderator:
C

CleanWater

Guest
Great tutorial! But I'm already using the view_xview and view_yview to follow my player. This code makes the "camera" shake in a strange way when I'm moving the player on my platform game.

Is there any workaround for this?
 

GMWolf

aka fel666
Great tutorial! But I'm already using the view_xview and view_yview to follow my player. This code makes the "camera" shake in a strange way when I'm moving the player on my platform game.

Is there any workaround for this?
Try changing the depth of the parallax controller so it updates the background after the camera is updated.
 
T

TyrantZERO

Guest
I'm having the same issue and changing the depth of the parallax controller doesn't seem to be fixing the issue. Any ideas? It's a great tutorial and the scrolling looks great, apart from the stuttering of course :)
 
T

TyrantZERO

Guest
*EDIT Never mind, my question was answered earlier in the thread.
 
Last edited by a moderator:
T

TyrantZERO

Guest
I'm using 7 backgrounds. At the debugger, the value for i is tending to infinite. I added a show_message after the loop but it was never activated

EDIT:
Since my backgrounds will be visible all the time I just changed the loop stop condition to "i <= 7". Now is working fine
Where exactly did you change the loop code? I'm having trouble figuring it out.
 
GM Version: GameMaker:Studio v1.4.1757
Target Platform: ALL
Download: N/A
Links: YouTube Video
Summary:
Add parallax scrolling backgrounds easily in gamemaker, with a procedural script to automatically detect settings set in the room editor.

Tutorial:
I would love to see what you guys come up with!
I love this! Parralaxing looks so good, I cant wait til my game gets to the point of this. Nice job friend.
 
Top