Infinite side scrolling issue

I’m trying to create a simple infinite side scrolling and I made a class to do the trick, but I’m facing a weird issue where I get a little gap between the two meshes when repositioning that I can’t figure out the issue.

On the algorithm I made I create 2 clones of the same mesh, one starting at the 0 x and the other 1 “mesh” of distance of the first mesh at x too. With this I keep running through the array of meshes changing its positions and, if it’s rightEdge reach the threshold that mesh gets re-positioned to the initial spawnPlace.

When I run the class it works, but I got this:
image

That gap only occurs on “even” threshold validation, not on the odds. So on the first render the 2 meshes are positioned perfectly, on the second I got the gap, on the third, again, perfectly positioned and so on…

When work I got this:
image

I spend a couple of hour debugging this and I can’t find anything. What am I doing wrong? Is this suppose to work or its a issue on my algorithm? :sweat_smile:

The class I've made:
import { Mesh, Scene } from '@babylonjs/core';

export class InfiniteBackground {
  instances: Mesh[] = [];
  threshold: number;
  spawnPlace: number;

  constructor(private mesh: Mesh, private scene: Scene) {
    this.instances[0] = mesh.clone("instance-1");
    this.instances[1] = mesh.clone("instance-2");
    this.spawnPlace = mesh.position.x + mesh.getBoundingInfo().boundingBox.extendSize.x*2;

    this.threshold = mesh.position.x - mesh.getBoundingInfo().boundingBox.extendSize.x;
    this.instances[1].position.x = this.spawnPlace;

    mesh.setEnabled(false);

    scene.onBeforeRenderObservable.add(() => {
      for (let i = 0; i < this.instances.length; i++) {
        const rightEdge = this.instances[i].position.x + mesh.getBoundingInfo().boundingBox.extendSize.x;

          this.instances[i].position.x -= 0.1;

        if (rightEdge <= this.threshold) {
          this.instances[i].position.x = this.spawnPlace;
        }
      }
    })
  }
}

PS: I’m pretty new at gaming code at all, so any advice would be nice! :grin:

1 Like

Hi there, I think an issue is that when a mesh is moved past the threshold, the code is assuming that the mesh is exactly at the threshold. E.G. if you add twice the mesh’s width to its position then it should be positioned right next to the other mesh, on the opposite side of it:

if (rightEdge <= this.threshold) {
    this.instances[i].position.x += this.mesh.getBoundingInfo().boundingBox.extendSize.x * 4;
}

Hey @Blake thank you! The solution you’ve provided not worked, but you said a thing that turns up a light on my mind:

“I think an issue is that when a mesh is moved past the threshold, the code is assuming that the mesh is exactly at the threshold”

This make me think that the incoming slide rightEdge isn’t exactly at spawnPlace, and changing the if to get the other slide position to snap make it works. That’s the change I’ve done on if:

const temp = this.instances[i];
this.instances[i] = this.instances[i+1];
this.instances[i+1] = temp;
this.instances[i+1].position.x = this.instances[i].position.x + mesh.getBoundingInfo().boundingBox.extendSize.x * 2;

But despite it worked and makes a lot of sense, I don’t know exactly why the previous solution don’t work, I mean, theoretically if the speed and the update rate of the slides are the same, it shouldn’t always work or never work? Why it worked only on “even” validations? :thinking:

Also with this solution I get that, when changing the slides, I’m facing a 1 frame lost, maybe this isn’t a good solution at all :confused:

1 Like

Hmm, I think when the first mesh is re-spawned it creates the gap, then when the second mesh is re-spawned it closes the gap, then when the first mesh is re-spawned it creates the gap again, and so on. So the gap exists during the time between when the first mesh is re-spawned and the second mesh is re-spawned… I think…

Also you might need more than two meshes if they aren’t big enough to fill the screen… Hard to say but if you post it in a playground (it can be in typescript) I can try to help more. :+1:

2 Likes

Hey @Blake I’m really sorry for don’t answer before, we’re finishing a project here on my job and I can’t make the playground before. But I manage to do it, here it is: Babylon.js Playground :grin:

Let me know if you can feel the frame lost :thinking:

2 Likes

No worries, the animation seems smooth to me, but I did notice that the mesh’s edge is calculated before incrementing the mesh’s position (instead of afterwards), which I expect is causing a one frame delay in detecting when the mesh has reached the threshold for re-spawning.

One more thing is that since the meshes are right next to each other, we can simply add twice the width to the position when re-spawning (it should work the same either way, but makes the code a little leaner).

Here is the playground with these small changes for example.

Edit: ooh, one more thing is that if we multiply the velocity 0.1 by scene.getAnimationRatio() then differences or fluctuations in the FPS will be accounted for (e.g. at 30 FPS the velocity would be multiplied by 2, keeping the amount of change per millisecond constant).

1 Like

I just see that I can’t feel the frame lost too on windows, for some reason on linux this happens, but really thank you @Blake for your help and the advice, this helped me a lot! :grin:

2 Likes