Fondamentalement, je veux empêcher la caméra de se déplacer en sous-pixels, car je pense que cela conduit à des sprites qui modifient visiblement leurs dimensions, même si c'est très légèrement. (Y a-t-il un meilleur terme pour cela?) Notez qu'il s'agit d'un jeu pixel-art où je veux avoir des graphismes pixelisés nets. Voici un gif qui montre le problème:
Maintenant, ce que j'ai essayé était le suivant: déplacez la caméra, projetez la position actuelle (il s'agit donc des coordonnées de l'écran), puis arrondissez ou transformez en int. Ensuite, convertissez-le en coordonnées mondiales et utilisez-le comme nouvelle position de la caméra. Autant que je sache, cela devrait verrouiller la caméra aux coordonnées réelles de l'écran, et non à des fractions de celles-ci.
Pour une raison quelconque, cependant, la y
valeur de la nouvelle position explose. En quelques secondes, il augmente à quelque chose comme 334756315000
.
Voici un SSCCE (ou un MCVE) basé sur le code du wiki LibGDX :
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
public class PixelMoveCameraTest implements ApplicationListener {
static final int WORLD_WIDTH = 100;
static final int WORLD_HEIGHT = 100;
private OrthographicCamera cam;
private SpriteBatch batch;
private Sprite mapSprite;
private float rotationSpeed;
private Viewport viewport;
private Sprite playerSprite;
private Vector3 newCamPosition;
@Override
public void create() {
rotationSpeed = 0.5f;
playerSprite = new Sprite(new Texture("/path/to/dungeon_guy.png"));
playerSprite.setSize(1f, 1f);
mapSprite = new Sprite(new Texture("/path/to/sc_map.jpg"));
mapSprite.setPosition(0, 0);
mapSprite.setSize(WORLD_WIDTH, WORLD_HEIGHT);
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
// Constructs a new OrthographicCamera, using the given viewport width and height
// Height is multiplied by aspect ratio.
cam = new OrthographicCamera();
cam.position.set(0, 0, 0);
cam.update();
newCamPosition = cam.position.cpy();
viewport = new ExtendViewport(32, 20, cam);
batch = new SpriteBatch();
}
@Override
public void render() {
handleInput();
cam.update();
batch.setProjectionMatrix(cam.combined);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
mapSprite.draw(batch);
playerSprite.draw(batch);
batch.end();
}
private static float MOVEMENT_SPEED = 0.2f;
private void handleInput() {
if (Gdx.input.isKeyPressed(Input.Keys.A)) {
cam.zoom += 0.02;
}
if (Gdx.input.isKeyPressed(Input.Keys.Q)) {
cam.zoom -= 0.02;
}
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
newCamPosition.add(-MOVEMENT_SPEED, 0, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
newCamPosition.add(MOVEMENT_SPEED, 0, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
newCamPosition.add(0, -MOVEMENT_SPEED, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
newCamPosition.add(0, MOVEMENT_SPEED, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.W)) {
cam.rotate(-rotationSpeed, 0, 0, 1);
}
if (Gdx.input.isKeyPressed(Input.Keys.E)) {
cam.rotate(rotationSpeed, 0, 0, 1);
}
cam.zoom = MathUtils.clamp(cam.zoom, 0.1f, 100 / cam.viewportWidth);
float effectiveViewportWidth = cam.viewportWidth * cam.zoom;
float effectiveViewportHeight = cam.viewportHeight * cam.zoom;
cam.position.lerp(newCamPosition, 0.02f);
cam.position.x = MathUtils.clamp(cam.position.x,
effectiveViewportWidth / 2f, 100 - effectiveViewportWidth / 2f);
cam.position.y = MathUtils.clamp(cam.position.y,
effectiveViewportHeight / 2f, 100 - effectiveViewportHeight / 2f);
// if this is false, the "bug" (y increasing a lot) doesn't appear
if (true) {
Vector3 v = viewport.project(cam.position.cpy());
System.out.println(v);
v = viewport.unproject(new Vector3((int) v.x, (int) v.y, v.z));
cam.position.set(v);
}
playerSprite.setPosition(newCamPosition.x, newCamPosition.y);
}
@Override
public void resize(int width, int height) {
viewport.update(width, height);
}
@Override
public void resume() {
}
@Override
public void dispose() {
mapSprite.getTexture().dispose();
batch.dispose();
}
@Override
public void pause() {
}
public static void main(String[] args) {
new Lwjgl3Application(new PixelMoveCameraTest(), new Lwjgl3ApplicationConfiguration());
}
}
et voici lesc_map.jpg
et ledungeon_guy.png
Je serais également intéressé à en apprendre davantage sur des moyens plus simples et / ou meilleurs de résoudre ce problème.