Parallax Background with FPS motion?

Hello.

I’m trying to use some parallax background layers in my game, it works perfectly, but I have a problem:

  • I have independent Draw(draw everything) and Calc(calculate everything) methods.
  • Draw is called in every loop.
  • Calc is called in every loop but is limited to FPS, so If the game is running in 30 FPS or 60FPS, all the moviments in the game will not be changed with the fps difference, this is really good.
  • I can’t adapt and separate the code of Parallax Background in Draw and Calc, I’m trying and trying but nothing works, because I need to calculate and draw the parallax background at same time(one inside other).
  • If I run this in default “render”, it works, but If I have 30FPS the background move slower than 60FPS. I want to separate Calc from Draw to calculate the moviment of the Parallax Background based on my FPS motion code.

Is there a way to do this?

ParralaxBackground (this code I need to separate):
Code:

public class ParallaxBackground {
   
   private ParallaxLayer[] layers;
   private Camera camera;
   private SpriteBatch batch;
   public Vector2 speed = new Vector2();
   
   public ParallaxBackground(ParallaxLayer[] layers,float width,float height,Vector2 speed){
      this.layers = layers;
      this.speed.set(speed);
      camera = new OrthographicCamera(width, height);
      batch = new SpriteBatch();
   }
   
   public void render(float delta)
   {
      camera.position.add(speed.x*delta,speed.y*delta, 0);
      for(ParallaxLayer layer:layers)
      {
         batch.setProjectionMatrix(camera.projection);
         batch.begin();
         float currentX = - camera.position.x*layer.parallaxRatio.x % ( layer.region.getRegionWidth() + layer.padding.x) ;
         
         if( speed.x < 0 )
        	 currentX += -( layer.region.getRegionWidth() + layer.padding.x);
         
         do
         {
            float currentY = - camera.position.y*layer.parallaxRatio.y % ( layer.region.getRegionHeight() + layer.padding.y) ;
            if ( speed.y < 0 )
            	currentY += - (layer.region.getRegionHeight()+layer.padding.y);
            
            do
            {
               batch.draw(layer.region,
                     -camera.viewportWidth + currentX + layer.startPosition.x ,
                     -camera.viewportHeight + camera.position.y + layer.startPosition.y);
               currentY += ( layer.region.getRegionHeight() + layer.padding.y );
            } while( currentY < camera.viewportHeight);
            
            currentX += ( layer.region.getRegionWidth()+ layer.padding.x);
            
         }while( currentX < camera.viewportWidth);
         
         batch.end();
      }
   }
}

Parralaxlayer:

public class ParallaxLayer{
   public TextureRegion region ;
   public Vector2 parallaxRatio;
   public Vector2 startPosition;
   public Vector2 padding ;
   public ParallaxLayer(TextureRegion region,Vector2 parallaxRatio,Vector2 padding){
      this(region, parallaxRatio, new Vector2(0,0),padding);
   }

   public ParallaxLayer(TextureRegion region,Vector2 parallaxRatio,Vector2 startPosition,Vector2 padding){
	  this.region  = region;
      this.parallaxRatio = parallaxRatio;
      this.startPosition = startPosition;
      this.padding = padding;
   }
}

Create:

        //BG1
        rbg = new ParallaxBackground(new ParallaxLayer[]
        		{
	                new ParallaxLayer(new TextureRegion (new Texture("images/bg_1.png")),new Vector2(1.0f,1.0f), new Vector2(camera.position.x+viewport.getWorldWidth()/6, (viewport.getWorldHeight() * 0.5f)+groundHeight), new Vector2(0, 0)),
        		}, viewport.getWorldWidth(), viewport.getWorldHeight(),new Vector2(50,0));

Render:

			//BG
			rbg.render(0.01f);

E.g of Draw and Calc:

Draw:

sprite.draw (batch); //Draw everytime

Calc:

			//FPS Independent TICK = FPS based.
			accum += getDeltaTime();
			while(accum >= TICK)
			{
			    accum -= TICK; 

			    sprite.x + = 5;
			}

With this code, the sprite is continuously drawn and the moviment in 10/20/30/50/60/120FPS is always the same.

I solved the problem, but is just a quick fix… I think this is not a good practice… I changed the code to group all positions, so I use it to draw. Then I override the positions with new positions and draw again. I had to change some code to increase +1 image in horizontal, because sometimes the last don’t back to original position after the looping (back late). I removed the Y code too, because my camera only moves on X.

The Parallax Background is moving based on FPS now.

:frowning:

ParallaxBackground:

public class ParallaxBackground {
   
   private ParallaxLayer[] layers;
   private Camera camera;
   private SpriteBatch batch;
   public Vector2 speed = new Vector2();
   private Array<Float> regionPosX;
   private Array<Float> regionPosY;
   
   public ParallaxBackground(ParallaxLayer[] layers,float width,float height,Vector2 speed){
      this.layers = layers;
      this.speed.set(speed);
      camera = new OrthographicCamera(width, height);
      batch = new SpriteBatch();
      regionPosX = new Array<Float>();
      regionPosY = new Array<Float>();
   }
   
   public void draw()
   {
	   for (ParallaxLayer layer: layers)
	   {
		   if (regionPosX.size > 0)
			   for (int i=0; i < regionPosX.size; i++)
			   {
			       batch.setProjectionMatrix(camera.projection);
				   batch.begin();
					   batch.draw(layer.region, regionPosX.get(i), regionPosY.get(i));
				   batch.end();
			   }
	   }
   }
   
   public void render(float velocity)
   {	
      camera.position.add(speed.x*velocity,speed.y*velocity, 0);
      for(ParallaxLayer layer:layers)
      {
         float currentX = - camera.position.x*layer.parallaxRatio.x % ( layer.region.getRegionWidth() + layer.padding.x) ; 

         int i=0;
         do
         {
        	 if (i < regionPosX.size)
        	 {
	        	 regionPosX.set(i, -camera.viewportWidth + currentX+ layer.startPosition.x);
	        	 regionPosY.set(i,-camera.viewportHeight + camera.position.y + layer.startPosition.y);
        	 }
        	 else
        	 {
	        	 regionPosX.add(-camera.viewportWidth + currentX + layer.startPosition.x);
	        	 regionPosY.add(-camera.viewportHeight + camera.position.y + layer.startPosition.y);
        	 }
        	 currentX += ( layer.region.getRegionWidth()+ layer.padding.x);  System.out.println(currentX);
        	 i++;
         }while(currentX < camera.viewportWidth+(camera.viewportWidth-layer.region.getRegionWidth()));
      }
   }

Render (Draw):

			//BG
			rbg.draw();

Render (FPS motion):

			    //BG
			    rbg.render(0.01f);