LibGdx如何实现背景的循环播放?

4

几天前,我学会了在LibGdx中进行一些滚动操作。现在,我正在尝试做一些相关的事情。我想重复背景。我的滚动跟随着一艘船(是一款太空游戏)。在背景中加载了一个太空照片作为贴图。当船到达背景的边缘时,它继续行驶,没有背景了。我阅读了有关wrap的文章,但我并不真正理解它是如何工作的。我做了以下代码:

    px=new Pixmap(Gdx.files.internal("fondo.jpg"));
    background=new Texture(px);
    background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);

然后,在我的渲染方法中

spriteBatch.begin();
    spriteBatch.draw(background,0,0,500,50);
    drawShip();
spriteBatch.end();

当然,它不起作用,因为它只绘制了一次背景。我不知道如何使包装方法起作用。有人能帮忙吗?

解决方案

我搞定了。这不是一个好的代码,但它可以工作。

首先,我声明了两个相同图像的纹理。

 bck1=new Texture(Gdx.files.internal("fondo.jpg"));
 bck2=new Texture(Gdx.files.internal("fondo.jpg"));

我声明了两个变量来指定每个背景的位置的X值,代码如下:

 int posXBck1=0,posXBck2=0;

然后我在Render()中使用它。

 public void calculoPosicionFondos(){
    posXBck2=posXBck1+ANCHODEFONDO;
    if(cam.position.x>=posXBck2+cam.viewportWidth/2){
        posXBck1=posXBck2;
    }
}

位置说明:

ANCHODEFONDO是我的背景宽度

Cam是一个OtrhoCam。

因此,如果cam处于bck2中(这意味着您不能再看到bck1),它将更改位置,将bck1的位置设置为bck2,并在下一个渲染循环中重新计算bck2

然后只需在您的渲染模式中绘制两个bck。


6
如果你已经找到了解决方案,请将其发布为答案。 - Mike G
4个回答

22

就像Teitus所说,永远不要多次加载纹理!无论如何,你通过包装器已经走在了正确的道路上:


texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);

现在您可以使用带有源位置的绘制方法。源位置是您选择在纹理上绘制的区域。

batch.draw(texture, x, y, srcX, srcY, srcWidth, srcHeight)

若要将纹理从右向左滚动,只需逐步增加 srcX 值。因此,在更新/渲染方法中创建一个递增的整数。

int sourceX = 0;

//render() method

//Increment the variable where to draw from on the image.
sourceX += 10;

//Simply draw it using that variable in the srcX.    
batch.draw(YourTexture, 0, 0, sourceX, 0, screenWidth, screenHeight);
因为您正在将纹理包装起来,它将无限地循环滚动。如果游戏运行时间非常长,源X int 可能会出现问题,因为一个int只能容纳2147483647。虽然需要一些时间,但您可以通过每次数字超过总图像宽度时减去图像宽度来修复它。

由于您正在包装纹理,因此它将无限循环滚动。如果游戏运行了很长时间,则可能会出现sourceX int的问题,因为一个int只能容纳2147483647。尽管需要一些时间,但您可以通过每次数字超过总图像宽度时减去图像宽度来解决这个问题。


10
请不要这样做:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));

那样会使你的大背景纹理加载两次,完全浪费。如果你想保持你的解决方案,请至少这样做:

bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=bkg1;

关于纹理重复。如果你的纹理宽度为500像素,并且你绘制了一个500像素的精灵,你就看不到任何重复。如果你想要它重复2次,就将其绘制成1000像素宽,并使用0-2的纹理坐标。 我不确定spriteBatch如何处理你发布的调用,你可以尝试那个,或者使用一个使用纹理区域并手动设置区域的重载。


你的代码将在bck2中给出bck1的指针,如果你移动bck2,它将移动bck1。 - LeSam
如果您可以“移动”纹理(请参阅API,它没有位置/变换),那将是正确的。这由精灵批处理处理 - 请注意,位置通过参数传递给spriteBatch。 - aacotroneo
请注意:如果使用TextureRegion进行绘图,还需要将TextureRegion的宽度/高度设置为较大的值,以实现所需的重复行为。 - Daryl

1
我看到这是一个相当老的问题,但我认为有一种更简单的方法来实现背景滚动。只需使用Sprite类即可。这里是一个我用于从右到左滚动的分层背景图像的代码片段。
public class LevelLayer 
{
    public float speedScalar = 1;

    private List<Sprite> backgroundSprites = new ArrayList<Sprite>();

    public LevelLayer()
    {

    }

    public void addSpriteLayer(Texture texture, float startingPointX, float y, int repeats)
    {
        for (int k = 0; k < repeats; k++)
        {
          Sprite s = new Sprite(texture);
          s.setX(startingPointX + (k*texture.getWidth()));
          s.setY(y);

          backgroundSprites.add(s);
        }
    }

  public void render(SpriteBatch spriteBatch, float speed)  
  { 
    for (Sprite s : backgroundSprites)
    {
        float delta = s.getX() - (speed * speedScalar);
        s.setX(delta);

        s.draw(spriteBatch);
    }
  }
}

然后您可以使用相同的纹理或一系列纹理,如下所示:

someLayer.addSpriteLayer(sideWalkTexture1, 0, 0, 15);
someLayer.addSpriteLayer(sideWalkTexture2, 15 * sideWalkTexture1.getWidth(), 0, 7);

我在代码中随机更改重复的背景部分,并在它们离开屏幕时创建新的或重置现有的集合。所有图层都进入一个池子,当需要新的图层时就会随机抽取。


-1

解决方案

我想到了一个解决方案。它的代码不是很好看,但可以运行。

首先,我声明了两个使用相同图片的纹理。

 bck1=new Texture(Gdx.files.internal("fondo.jpg"));
 bck2=new Texture(Gdx.files.internal("fondo.jpg"));

同时,我声明了两个变量来指定每个背景位置的X值

 int posXBck1=0,posXBck2=0;

然后我在Render()函数中使用它。

 public void calculoPosicionFondos(){
    posXBck2=posXBck1+ANCHODEFONDO;
    if(cam.position.x>=posXBck2+cam.viewportWidth/2){
        posXBck1=posXBck2;
    }
}

在哪里:

ANCHODEFONDO是我的背景宽度

Cam是一个OtrhoCam。

所以我说,如果相机在bck2中(这意味着你看不到bck1了),它会改变位置,将bck1的位置给予bck2,并在下一个渲染循环中重新计算bck2

然后只需在render()函数中绘制两个背景bck即可


2
我认为只需要一次拥有纹理,并从同一纹理设置两个不同的纹理区域就足够了。 - EpicPandaForce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接