Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: rmonic79 on Fri 28/11/2014 11:57:41

Title: Help about looping background objects [Solved]
Post by: rmonic79 on Fri 28/11/2014 11:57:41
hy guys i'm tryng to make clouds with parallax scrolling on four level. Is it possible to move objects having them reappear on the opposite side of the screen to create a perpetual movement?
Title: Re: Help about looping background objects
Post by: Snarky on Fri 28/11/2014 12:14:03
Yes. Simply write some code in repeatedly_execute() to scroll the clouds a bit each game cycle (something along the lines of cloud1.X = cloud1.X-1 to scroll from right to left), and when they've gone off-screen (cloud1.X + Game.SpriteWidth[cloud1.Graphic] < 0) move them over to the other edge.

I'm sure there's a module for it as well, but it's simple enough to do by yourself.
Title: Re: Help about looping background objects
Post by: rmonic79 on Fri 28/11/2014 19:58:19
Quote from: Snarky on Fri 28/11/2014 12:14:03
Yes. Simply write some code in repeatedly_execute() to scroll the clouds a bit each game cycle (something along the lines of cloud1.X = cloud1.X-1 to scroll from right to left), and when they've gone off-screen (cloud1.X + Game.SpriteWidth[cloud1.Graphic] < 0) move them over to the other edge.

I'm sure there's a module for it as well, but it's simple enough to do by yourself.
thanks for the answer :) i have a little problem with this, because i want that when the cloud reaches the end of the screen, the part offscreen reappears on the other side immediately without wait to all the sprite goes off, i'd tried this method and works using two sprites with the same image but perhaps there's a better way to do this, because with four levels of parallax it will be a little confused. I set timer to have less than 1 because i can't use float like x - 0.5 is there also a solution to this?
Code (ags) Select

function room_FirstLoad()
{SetRestartPoint();

SetTimer(1, 400);
SetTimer(2, 202);
SetTimer(3, 302);
SetTimer(4, 10);
SetTimer(5, 10);
}

function room_RepExec()
{
if (IsTimerExpired(1)){player.Walk(250, 250, eNoBlock, eAnywhere); oCarica.Visible=true;oNewgame.Visible=true;}
if (IsTimerExpired(2)){object[1].Animate(1, 6, eOnce, eNoBlock, eForwards);SetTimer(2, 200);}
if (IsTimerExpired(3)){EnableInterface();}
if (IsTimerExpired(4)){ocloud.X=ocloud.X - 1;SetTimer(4, 10);}
if (IsTimerExpired(5)){ocloud1.X=ocloud1.X - 1;SetTimer(5, 10);}
if (ocloud.X + Game.SpriteWidth[ocloud.Graphic]<0){ocloud.X=321;}
if (ocloud1.X + Game.SpriteWidth[ocloud1.Graphic]<0){ocloud1.X=321;}

Thanks
Title: Re: Help about looping background objects
Post by: Snarky on Fri 28/11/2014 20:37:12
I suppose I should dig up my old cloud code, but let's see if we can get this to work from scratch.

The best way to move less than one pixel per turn is to have a "real position" as a float, and just round it to the nearest integer for display. So (untested code):

Code (AGS) Select
float cloud1_X=Maths.IntToFloat(System.ViewportWidth); // Set to start pos. This is just off the right edge of the screen.
float cloud2_x=Maths.IntToFloat(System.ViewportWidth);
float cloud1_speed=-0.2; // Negative to move left
float cloud2_speed=-0.25;

void moveClouds()
{
  cloud1_X += cloud1_speed;
  cloud2_X += cloud2_speed;

  oCloud1.X = Maths.FloatToInt(cloud1_X);
  oCloud2.X = Maths.FloatToInt(cloud2_X);
 
  if(oCloud1.X + Game.SpriteWidth[oCloud1.Graphic]<0)
    cloud1_X = Maths.IntToFloat(System.ViewportWidth);
  else if(oCloud1.X >= System.ViewportWidth)
    cloud1_X = Maths.IntToFloat(0-Game.SpriteWidth[oCloud1.Graphic]);

  if(oCloud2.X + Game.SpriteWidth[oCloud2.Graphic]<0)
    cloud2_X = Maths.IntToFloat(System.ViewportWidth);
  else if(oCloud2.X >= System.ViewportWidth)
    cloud2_X = Maths.IntToFloat(0-Game.SpriteWidth[oCloud2.Graphic]);
}

function room_RepExec()
{
  moveClouds();
  // Do the other stuff with interface and walking, not sure exactly what that's about.
}


Not sure why they'd disappear as soon as they reach the edge, the Game.SpriteWidth[] bit should take care of that. Are the clouds animating?

If you have more than 2-3 clouds it might be easier to put them in arrays and loop through them rather than duplicate all the code for each cloud, but this is fine for now.
Title: Re: Help about looping background objects
Post by: rmonic79 on Fri 28/11/2014 21:03:18
Quote from: Snarky on Fri 28/11/2014 20:37:12
I suppose I should dig up my old cloud code, but let's see if we can get this to work from scratch.

The best way to move less than one pixel per turn is to have a "real position" as a float, and just round it to the nearest integer for display. So (untested code):

Code (AGS) Select
float cloud1_X=Maths.IntToFloat(System.ViewportWidth); // Set to start pos. This is just off the right edge of the screen.
float cloud2_x=Maths.IntToFloat(System.ViewportWidth);
float cloud1_speed=-0.2; // Negative to move left
float cloud2_speed=-0.25;

void moveClouds()
{
  cloud1_X += cloud1_speed;
  cloud2_X += cloud2_speed;

  oCloud1.X = Maths.FloatToInt(cloud1_X);
  oCloud2.X = Maths.FloatToInt(cloud2_X);
 
  if(oCloud1.X + Game.SpriteWidth[oCloud1.Graphic]<0)
    cloud1_X = Maths.IntToFloat(System.ViewportWidth);
  else if(oCloud1.X >= System.ViewportWidth)
    cloud1_X = Maths.IntToFloat(0-Game.SpriteWidth[oCloud1.Graphic]);

  if(oCloud2.X + Game.SpriteWidth[oCloud2.Graphic]<0)
    cloud2_X = Maths.IntToFloat(System.ViewportWidth);
  else if(oCloud2.X >= System.ViewportWidth)
    cloud2_X = Maths.IntToFloat(0-Game.SpriteWidth[oCloud2.Graphic]);
}

function room_RepExec()
{
  moveClouds();
  // Do the other stuff with interface and walking, not sure exactly what that's about.
}

thanks very interesting :) i will try it later along with manual to understand all steps :)
Quote from: Snarky on Fri 28/11/2014 20:37:12
Not sure why they'd disappear as soon as they reach the edge, the Game.SpriteWidth[] bit should take care of that. Are the clouds animating?
It works fine but (let me try to explain in english, it's hard :) ) the screen is 320px and the front cloud (the one i'm using to try the scroll) is 256 px. in my mind i was thinking that while the first pixel of cloud goes offscreen he can reappear on the other side creating something like this
d          clou
ud          clo
oud          cl   
without waiting that the entire sprite goes offscreen (sorry for the example but maybe it explains better that my bad english)   

Quote from: Snarky on Fri 28/11/2014 20:37:12
If you have more than 2-3 clouds it might be easier to put them in arrays and loop through them rather than duplicate all the code for each cloud, but this is fine for now.
i never worked with array in ags but i 'll give it a try.

thanks for advice ;)

Title: Re: Help about looping background objects
Post by: Vincent on Fri 28/11/2014 21:21:49
Uncreative hint,

Likewise, use Y++; to move the cloud down or  Y--; to move it up.
X--; to move it left, X++; to move it to the right   :)
Title: Re: Help about looping background objects
Post by: Snarky on Fri 28/11/2014 21:49:32
It's pretty simple, really. All the Maths.IntToFloat/FloatToInt is just to convert between floats and ints (floats are numbers with decimals, while ints are whole numbers). If you move -0.2 pixels per turn, it will take 5 turns to move a whole pixel (note that when things move this slowly, it starts to look jerky). I made it so you can change the speed and direction easily, and a test to check if they've gone off the right side of the screen as well.

Quote from: Vincent on Fri 28/11/2014 21:21:49
X--; to move it left, X++; to move it to the right   :)

We're already doing (essentially) that, Vincent.

Quote from: rmonic79 on Fri 28/11/2014 21:03:18in my mind i was thinking that while the first pixel of cloud goes offscreen he can reappear on the other side creating something like this
d          clou
ud          clo
oud          cl   
without waiting that the entire sprite goes offscreen (sorry for the example but maybe it explains better that my bad english)

Oh right. No, you can't do that, I'm afraid. A sprite can't "wrap around" the screen, and an object can only be in one place at one time. To get this effect, you'll need two copies of each cloud (i.e. two objects which both use the same sprite as their graphic).

Exactly how to best write the code depends on the details of the situation. It really depends on how many clouds you're going to want on-screen at the same time, in how many layers, how quickly they should move, and whether they need to "interact" with other things in the scene (move in front of or behind parts of the background, like a mountain for example).
Title: Re: Help about looping background objects
Post by: rmonic79 on Fri 28/11/2014 22:11:49
Quote from: Snarky on Fri 28/11/2014 21:49:32
It's pretty simple, really. All the Maths.IntToFloat/FloatToInt is just to convert between floats and ints (floats are numbers with decimals, while ints are whole numbers). If you move -0.2 pixels per turn, it will take 5 turns to move a whole pixel (note that when things move this slowly, it starts to look jerky). I made it so you can change the speed and direction easily, and a test to check if they've gone off the right side of the screen as well.

Quote from: Vincent on Fri 28/11/2014 21:21:49
X--; to move it left, X++; to move it to the right   :)

We're already doing (essentially) that, Vincent.

Quote from: rmonic79 on Fri 28/11/2014 21:03:18in my mind i was thinking that while the first pixel of cloud goes offscreen he can reappear on the other side creating something like this
d          clou
ud          clo
oud          cl   
without waiting that the entire sprite goes offscreen (sorry for the example but maybe it explains better that my bad english)

Oh right. No, you can't do that, I'm afraid. A sprite can't "wrap around" the screen, and an object can only be in one place at one time. To get this effect, you'll need two copies of each cloud (i.e. two objects which both use the same sprite as their graphic).

Exactly how to best write the code depends on the details of the situation. It really depends on how many clouds you're going to want on-screen at the same time, in how many layers, how quickly they should move, and whether they need to "interact" with other things in the scene (move in front of or behind parts of the background, like a mountain for example).
perfect! all clear. Thanks so much. :)
Title: Re: Help about looping background objects [Solved]
Post by: Monsieur OUXX on Fri 28/11/2014 23:16:42
Please note that more and more people go for the "Tween module" solution. You'll probably start using it at some stage in your project, even though you thought you could spare it at the beginning.
This demo  (https://www.dropbox.com/s/8efsm6jxgtvxmql/Stars%201.0.zip?dl=0)uses the Tween module to scroll a background image continuously right-to-left.
Title: Re: Help about looping background objects [Solved]
Post by: Snarky on Sat 29/11/2014 00:19:07
I love the Tween module, but what I don't like about it for situations like this is that you control the overall duration rather than the speed. Rather than saying "this cloud should move 1 pixel every 4 loops" (or whatever), you have to say "this cloud should cross the screen in 30 seconds." I find it takes more tweaking to get right. Depends on what exactly you're trying to do, of course.
Title: Re: Help about looping background objects [Solved]
Post by: Monsieur OUXX on Sat 29/11/2014 01:07:32
Quote from: Snarky on Sat 29/11/2014 00:19:07
Rather than saying "this cloud should move that-many pixels every that-many loops" you have to say "this cloud should cross the screen in 30 seconds."
You are right, that's a completely different approach. I just mentioned it for exhaustiveness's sake. The issues are usually solved by just checking every game loop if the tween's movement is over.
Title: Re: Help about looping background objects
Post by: rmonic79 on Sat 29/11/2014 17:38:45
Quote from: Snarky on Fri 28/11/2014 20:37:12
I suppose I should dig up my old cloud code, but let's see if we can get this to work from scratch.

The best way to move less than one pixel per turn is to have a "real position" as a float, and just round it to the nearest integer for display. So (untested code):

Code (AGS) Select
float cloud1_X=Maths.IntToFloat(System.ViewportWidth); // Set to start pos. This is just off the right edge of the screen.
float cloud2_x=Maths.IntToFloat(System.ViewportWidth);
float cloud1_speed=-0.2; // Negative to move left
float cloud2_speed=-0.25;

void moveClouds()
{
  cloud1_X += cloud1_speed;
  cloud2_X += cloud2_speed;

  oCloud1.X = Maths.FloatToInt(cloud1_X);
  oCloud2.X = Maths.FloatToInt(cloud2_X);
 
  if(oCloud1.X + Game.SpriteWidth[oCloud1.Graphic]<0)
    cloud1_X = Maths.IntToFloat(System.ViewportWidth);
  else if(oCloud1.X >= System.ViewportWidth)
    cloud1_X = Maths.IntToFloat(0-Game.SpriteWidth[oCloud1.Graphic]);

  if(oCloud2.X + Game.SpriteWidth[oCloud2.Graphic]<0)
    cloud2_X = Maths.IntToFloat(System.ViewportWidth);
  else if(oCloud2.X >= System.ViewportWidth)
    cloud2_X = Maths.IntToFloat(0-Game.SpriteWidth[oCloud2.Graphic]);
}

function room_RepExec()
{
  moveClouds();
  // Do the other stuff with interface and walking, not sure exactly what that's about.
}


Not sure why they'd disappear as soon as they reach the edge, the Game.SpriteWidth[] bit should take care of that. Are the clouds animating?

If you have more than 2-3 clouds it might be easier to put them in arrays and loop through them rather than duplicate all the code for each cloud, but this is fine for now.

it gives me this error

(http://i.imgur.com/b7kA6X1.jpg)

i  tried also without math like manual but it's the same

(http://i.imgur.com/pn8Exwu.jpg)
Title: Re: Help about looping background objects [Solved]
Post by: rmonic79 on Sat 29/11/2014 17:46:23
Quote from: Monsieur OUXX on Fri 28/11/2014 23:16:42
Please note that more and more people go for the "Tween module" solution. You'll probably start using it at some stage in your project, even though you thought you could spare it at the beginning.
This demo  (https://www.dropbox.com/s/8efsm6jxgtvxmql/Stars%201.0.zip?dl=0)uses the Tween module to scroll a background image continuously right-to-left.
thanks for advice i'll take a look ;)
Title: Re: Help about looping background objects [Solved]
Post by: Snarky on Sat 29/11/2014 19:00:41
Quote from: rmonic79 on Sat 29/11/2014 17:38:45
it gives me this error

It probably doesn't allow using a function call in a global assignment (outside of any function). Try moving the assignment to room_FirstLoad():
Code (AGS) Select
float cloud1_X;
float cloud2_x;

function room_FirstLoad()
{
  cloud1_X=Maths.IntToFloat(System.ViewportWidth); // Set to start pos. This is just off the right edge of the screen.
  cloud2_x=Maths.IntToFloat(System.ViewportWidth);
}
Title: Re: Help about looping background objects [Solved]
Post by: rmonic79 on Sun 30/11/2014 00:14:57
Quote from: Snarky on Sat 29/11/2014 19:00:41
Quote from: rmonic79 on Sat 29/11/2014 17:38:45
it gives me this error

It probably doesn't allow using a function call in a global assignment (outside of any function). Try moving the assignment to room_FirstLoad():
Code (AGS) Select
float cloud1_X;
float cloud2_x;

function room_FirstLoad()
{
  cloud1_X=Maths.IntToFloat(System.ViewportWidth); // Set to start pos. This is just off the right edge of the screen.
  cloud2_x=Maths.IntToFloat(System.ViewportWidth);
}


it works  assigning a float number directly like this(otherwise the objects with the same image are overlapped)

Code (ags) Select

float cloud1_X= 318.0;
float cloud2_X=43.0;
float cloud1_speed=-0.05; // Negative to move left
float cloud2_speed=-0.05;

void moveClouds()
{
  cloud1_X += cloud1_speed;
  cloud2_X += cloud2_speed;

  ocloud.X = FloatToInt(cloud1_X);
  ocloud1.X = FloatToInt(cloud2_X);
 
  if(ocloud.X + Game.SpriteWidth[ocloud.Graphic]<0)
    cloud1_X = IntToFloat(System.ViewportWidth);
  else if(ocloud.X >= System.ViewportWidth)
    cloud1_X = IntToFloat(0-Game.SpriteWidth[ocloud.Graphic]);

  if(ocloud1.X + Game.SpriteWidth[ocloud1.Graphic]<0)
    cloud2_X = IntToFloat(System.ViewportWidth);
  else if(ocloud1.X >= System.ViewportWidth)
    cloud2_X = IntToFloat(0-Game.SpriteWidth[ocloud1.Graphic]);
}



function room_Load()
{//float cloud1_X =IntToFloat(System.ViewportWidth); // Set to start pos. This is just off the right edge of the screen.
//float cloud2_X=IntToFloat(System.ViewportWidth);


The assignment works inside room load but there's no need with direct coordinates on top i think

or


float cloud1_X;
float cloud2_X;
float cloud1_speed=-0.05; // Negative to move left
float cloud2_speed=-0.05;

void moveClouds()
{
  cloud1_X += cloud1_speed;
  cloud2_X += cloud2_speed;

  ocloud.X = FloatToInt(cloud1_X);
  ocloud1.X = FloatToInt(cloud2_X);
 
  if(ocloud.X + Game.SpriteWidth[ocloud.Graphic]<0)
    cloud1_X = IntToFloat(System.ViewportWidth);
  else if(ocloud.X >= System.ViewportWidth)
    cloud1_X = IntToFloat(0-Game.SpriteWidth[ocloud.Graphic]);

  if(ocloud1.X + Game.SpriteWidth[ocloud1.Graphic]<0)
    cloud2_X = IntToFloat(System.ViewportWidth);
  else if(ocloud1.X >= System.ViewportWidth)
    cloud2_X = IntToFloat(0-Game.SpriteWidth[ocloud1.Graphic]);
}



function room_FirstLoad()
{ cloud1_X =IntToFloat(ocloud.X); // Set to start pos. This is just off the right edge of the screen.
cloud2_X=IntToFloat(ocloud1.X)

this way i get the position of the object as in the graphical interface

thanks very, very interesting  :-D
Title: Re: Help about looping background objects [Solved]
Post by: Nixxon on Fri 11/08/2017 04:31:32
Hey Guys,

I'm desperately trying to achieve the same thing for my game.

Don't suppose I could borrow the room code? Just not sure where to put things (less than rudimentary understanding).