[英]Achieve parallax effect in libGDX game
我和一些朋友在一个游戏中工作,我们有一个大的水平世界和一个仅显示1/3的OrthographicCamera 。 当摄像机的水平位置发生变化时,此摄像机会移动,因此摄像机仅向左和向右移动。
游戏中显示的一些物体靠近玩家的观点,但其他物体距离较远(例如岛屿)。 考虑到这一点,我们不能为元素设置固定位置并仅移动相机。 考虑到元素的距离,我们需要实现视差效果。
这是一个简单的图像,可以更好地解释它: 左侧的视口显示了游戏的3个对象。 绿色的是靠近玩家,红色椭圆是远的,黄色的是在中间。 在右侧的视口中,摄像机已向右移动,因此所有对象都消失在左侧。 问题是绿色矩形的相对运动大于黄色的运动。 同样,黄色物体的运动大于红色物体的运动。
我创建了所有我的资产,考虑到它们的范围,但现在,我如何使用libGDX模拟这个视角? 有没有课可以做? 如果我必须在每次迭代中设置元素位置,我该如何计算正确的位置?
请注意,下面的示例未经过测试,因为我只是回忆起我是如何做到的。 这个想法很简单 - 创建具有额外层的图层,每个图层具有初始位置和速度并移动它们。 如果一个图层离开边缘,则在另一边添加另一个图层(这就是我们创建一个额外图层的原因)。
假设您有一个视差对象,它具有初始位置,大小和速度 -
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取自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();
}
}
游戏对象以及 -
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);
}
}
假设我们有两层 - 一层在前面,另一层在后面。 我们每个都有一个纹理。 每个纹理都填满整个屏幕。 我们为每个图层创建两个实例,以便当一个纹理开始离开屏幕时,另一个纹理显示在边缘以填补空白。 如果你有较小的纹理,你需要首先确定填充屏幕所需的纹理数量,然后创建一个额外的图层以填补其间的间隙。
我们可以在世界创造期间创建一个视差层阵列 -
Array<Parallax> parallaxList = new Array<Parallax>(4);
我们可以创建像这样的层 -
// 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));
我们在每个框架的更新呼叫中更新图层 -
// 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);
}
}
您可以使用OrthographicCamera和SpriteBatch绘制视差图层。 你可以实际使用你拥有的游戏相机,但我认为使用单独的相机更清洁。 无论如何,视差纹理通常足够大,可以在单独的调用中进行批处理,因此使用游戏相机很可能无法为您节省一个绘制调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.