简体   繁体   English

在libGDX游戏中实现视差效果

[英]Achieve parallax effect in libGDX game

I'm working in a game with some friends in which we have a large horizontal world and a OrthographicCamera that shows only 1/3 of it. 我和一些朋友在一个游戏中工作,我们有一个大的水平世界和一个仅显示1/3的OrthographicCamera This camera it's moved when the horizontal position of the player change so the camera only move to the left and to the right. 当摄像机的水平位置发生变化时,此摄像机会移动,因此摄像机仅向左和向右移动。

Some of the objects showed in the game are near the player point-of-view but others are far away (for example, islands). 游戏中显示的一些物体靠近玩家的观点,但其他物体距离较远(例如岛屿)。 With this in consideration, we cannot set fixed positions for elements and move only the camera. 考虑到这一点,我们不能为元素设置固定位置并仅移动相机。 We need to achieve a parallax effect taking in consideration the distance of the elements. 考虑到元素的距离,我们需要实现视差效果。

Here is a simple image to explain it better: 这是一个简单的图像,可以更好地解释它: 在此输入图像描述 The viewport to the left shows 3 objects of the game. 左侧的视口显示了游戏的3个对象。 The green one is near the player, the red ellipse is far and the yellow one is in the middle. 绿色的是靠近玩家,红色椭圆是远的,黄色的是在中间。 In the viewport to the right the camera has been moved to the right so all the objects disappear to the left. 在右侧的视口中,摄像机已向右移动,因此所有对象都消失在左侧。 The thing is that the relative movement of the green rectangle is greater than the movement of the yellow. 问题是绿色矩形的相对运动大于黄色的运动。 In the same way, movement of yellow object is greater than red object movement. 同样,黄色物体的运动大于红色物体的运动。

I created all my assets scaled taking in consideration how far they are but now, how can I simulate this perspective using libGDX? 我创建了所有我的资产,考虑到它们的范围,但现在,我如何使用libGDX模拟这个视角? Is there any class to do it? 有没有课可以做? If I have to set elements position in each iteration, how could I calculate the right position? 如果我必须在每次迭代中设置元素位置,我该如何计算正确的位置?

Note that the example below is not tested as I am just recalling how I did it. 请注意,下面的示例未经过测试,因为我只是回忆起我是如何做到的。 The idea is simple - create layers with an extra layer for each with initial positions and velocity and move them. 这个想法很简单 - 创建具有额外层的图层,每个图层具有初始位置和速度并移动它们。 If a layer goes off the edge, put another one (that is why we create an extra layer) at the opposite edge. 如果一个图层离开边缘,则在另一边添加另一个图层(这就是我们创建一个额外图层的原因)。

Say you have a parallax object that takes initial positions, size, and velocity- 假设您有一个视差对象,它具有初始位置,大小和速度 -

public class Parallax extends DynamicGameObject {

    public float width, height; // Use setter/getter if you prefer

    public Parallax(float x, float y, float width, float height, float velocityX, float velocityY) {

        super(x, y, width, height);
        velocity.set(velocityX, velocityY);
        this.width = width;
        this.height = height;

    }

    public void update(float deltaTime) {
        position.add(velocity.x * deltaTime, velocity.y * deltaTime);
    }

    public void setPosition(float x, float y) {
        position.set(x, y);
    }
}

DynamicGameObject is taken from SuperJumper demo- DynamicGameObject取自SuperJumper演示 -

public class DynamicGameObject extends GameObject {

    public final Vector2 velocity;
    public final Vector2 accel;

    public DynamicGameObject(float x, float y, float width, float height) {
        super(x, y, width, height);
        velocity = new Vector2();
        accel = new Vector2();
    }
}

GameObject as well- 游戏对象以及 -

public class GameObject {

    public final Vector2 position;
    public final Rectangle bounds;

    public GameObject(float x, float y, float width, float height) {
        this.position = new Vector2(x,y);
        this.bounds = new Rectangle(x - width/2f, y - height/2f, width, height);
    }
}

Say we have two layers - one in front and the other goes at back. 假设我们有两层 - 一层在前面,另一层在后面。 We have one texture for each. 我们每个都有一个纹理。 Each texture fills the entire screen. 每个纹理都填满整个屏幕。 We create two instances for each layer so that when one texture starts going off the screen, the other shows up at the edge to fill the gap. 我们为每个图层创建两个实例,以便当一个纹理开始离开屏幕时,另一个纹理显示在边缘以填补空白。 If you have smaller textures, you need to determine first how many textures you need to fill the screen and then create layers with one extra to fill the gap in between. 如果你有较小的纹理,你需要首先确定填充屏幕所需的纹理数量,然后创建一个额外的图层以填补其间的间隙。

We can create an array of parallax layers during world creation- 我们可以在世界创造期间创建一个视差层阵列 -

Array<Parallax> parallaxList = new Array<Parallax>(4);

We can create the layers like this- 我们可以创建像这样的层 -

// Back
/* First parallax for back layer is at 0 x-axis. If you want to move the texture from right to left, the value of BACK_VELOCITY_X should be negative. You can experiment with velocity value for desire pace of movement. We do not want our layer to move on y-axis. Hence, it is set to 0. */

parallaxList.add(new Parallax(0, BACK_TEXTURE_HEIGHT, BACK_TEXTURE_WIDTH, BACK_TEXTURE_HEIGHT, BACK_VELOCITY_X, 0));

/* This one is also for back layer but it is positioned at the right edge of the layer above*/
parallaxList.add(new Parallax(BACK_TEXTURE_WIDTH, BACK_TEXTURE_HEIGHT, BACK_TEXTURE_WIDTH, BACK_TEXTURE_HEIGHT, SOME_VELOCITY_X, 0));

// Front
parallaxList.add(new Parallax(0, 0, FRONT_TEXTURE_WIDTH, FRONT_TEXTURE_HEIGHT, FRONT_VELOCITY_X, 0));
parallaxList.add(new Parallax(FRONT_TEXTURE_WIDTH, 0, FRONT_TEXTURE_WIDTH, FRONT_TEXTURE_HEIGHT, FRONT_VELOCITY_X, 0));

We update the layers on an update call in each frame- 我们在每个框架的更新呼叫中更新图层 -

// In our example, TOTAL_LAYERS is 4
for (int i = 0; i < TOTAL_LAYERS; i++) {

    int tmpInt;
    Parallax parallax = parallaxList.get(i);

    parallax.update(deltaTime);

    // If one layer is off the edge, put it at the right of the next one
    // In this example, layers are moving from right to left
    if (parallax.position.x <= -parallax.width) {

        // We know that parallaxList's indexes 0 and 1 hold the back layers
        // and indexes 2 and 3 have the front layers. You can add additional
        // parameters in Parallax class to indicate a group so that you do not
        // have to determine the group in dirty way like this
        if(i == 0){
            tmpInt = 1;
        } else if(i == 1) {
            tmpInt = 0;
        } else if(i == 2) {
            tmpInt = 3;
        } else {
            tmpInt = 2;
        }

        parallax.setPosition(parallaxList.get(tmpInt).position.x + parallax.width, parallax.position.y);            
    }        
}

You can use an OrthographicCamera and a SpriteBatch to draw the parallax layers. 您可以使用OrthographicCamera和SpriteBatch绘制视差图层。 You can actually use the game camera you have but I think using a separate camera is much cleaner. 你可以实际使用你拥有的游戏相机,但我认为使用单独的相机更清洁。 Anyways, parallax textures are usually big enough to be batched in a separate call so using the game camera most probably will not save you a draw call. 无论如何,视差纹理通常足够大,可以在单独的调用中进行批处理,因此使用游戏相机很可能无法为您节省一个绘制调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM