LibGDX - Problem placing a texture following coordinates on a Tilemap

35 Views Asked by At

I'm doing a little java game as a school project. I've created a tilemap with the Tiled tool, and the map is displayed correctly. On my map I want to make waterfall animations, and to do this I've placed object layers in the tilemap which I then retrieve in Java (object coordinates on the map, sizes, etc.).

The problem comes here: I load an image in the form of a texture that was also used to make my tilemap, which I split to get the right tiles and place at the object coordinates, but the texture is displayed outside the map. For testing purposes, I'm trying to place the texture at the coordinates of my mouse.

I found out on the internet that you have to use a camera.unproject and indeed it works but only without the setToOrtho.

So I'm asking stack overflow for help, thank you!

Here's the code on github for those who want to run full tests:

https://github.com/UniLasalle-Amiens/TP_JAVA-Boats-Management

else:

public class MyGdxGame extends ApplicationAdapter {

    private static final int TILESET_COLS = 26, TILESET_ROWS = 15, TILE_WIDTH = 32, TILE_HEIGHT = 32;

    private AssetManager assetManager;

    private TiledMap map;

    private Texture tileSheet;

    private OrthogonalTiledMapRenderer tilemapRenderer;

    // Camera
    private OrthographicCamera camera;

    private SpriteBatch batch;
    private BitmapFont font;

    // Animation des chûtes d'eau
    private Animation<TextureRegion> waterFallAnimation;
    private List<Rectangle> waterFallRectangles = new LinkedList<Rectangle>();
    private float _waterFallStateTime = 0;

    @Override
    public void create() {
        batch = new SpriteBatch();

        // Asset manager
        assetManager = new AssetManager();
        assetManager.setLoader(TiledMap.class, new TmxMapLoader(new InternalFileHandleResolver()));
        assetManager.load("Map.tmx", TiledMap.class);

        // Chargement de la texture 32x32.png
        assetManager.setLoader(Texture.class, new TextureLoader(new InternalFileHandleResolver()));
        assetManager.load("Tiles/32x32.png", Texture.class);

        assetManager.finishLoading();

        map = assetManager.get("Map.tmx");
        tileSheet = assetManager.get("Tiles/32x32.png");

        // Mise en place de la caméra dans la scène
        camera = new OrthographicCamera();
        camera.setToOrtho(false);
        camera.update();

        // Rendu de la map
        tilemapRenderer = new OrthogonalTiledMapRenderer(map);

        // Mettre la fenêtre en mode plein écran
        Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode());

        // Rendre le fenêtre redimensionnable
        Gdx.graphics.setResizable(true);

        // Animation des chûtes d'eau
        TextureRegion[][] waterFallTmp = TextureRegion.split(tileSheet, TILE_WIDTH, TILE_HEIGHT);
        TextureRegion[] waterFallFrames = new TextureRegion[3];

        waterFallFrames[0] = waterFallTmp[10][14];
        waterFallFrames[1] = waterFallTmp[10][15];
        waterFallFrames[2] = waterFallTmp[10][16];

        waterFallAnimation = new Animation<TextureRegion>(0.150f, waterFallFrames);

        // Récupération du groupe d'object Layers
        MapGroupLayer objectsGroupLayer = (MapGroupLayer) map.getLayers().get("ObjectsLayers");

        // Récupération de l'object Layer "Waterfall"
        MapLayer waterFallLayer = objectsGroupLayer.getLayers().get("Waterfall");

        // Récupération des objets de l'object Layer "Waterfall"
        MapObjects waterFallObjects = waterFallLayer.getObjects();

        batch.begin();
        for (MapObject object : waterFallObjects) {
            // RectangleMapObject rectangleMapObject = (RectangleMapObject) object;
            // waterFallRectangles.add(rectangleMapObject.getRectangle());

            batch.draw(waterFallFrames[0], object.getProperties().get("x", Float.class),
                    object.getProperties().get("y", Float.class),
                    object.getProperties().get("width", Float.class),
                    object.getProperties().get("height", Float.class));
        }
        batch.end();
    }

    @Override
    public void render() {
        ScreenUtils.clear(0, 0, 0, 1);

        camera.update();
        // batch.setProjectionMatrix(camera.combined);

        tilemapRenderer.setView(camera);
        tilemapRenderer.render();

        // Gestion de l'animation des chûtes d'eau
        _waterFallStateTime += Gdx.graphics.getDeltaTime();

        TextureRegion currentFrame = waterFallAnimation.getKeyFrame(_waterFallStateTime, true);

        // Mouse position
        Vector3 mousePosition = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
        Vector3 vc = camera.unproject(mousePosition);

        batch.begin();
        batch.draw(currentFrame, vc.x, vc.y);
        batch.end();

        // batch.begin();

        // for (Rectangle rectangle : waterFallRectangles)
        // batch.draw(currentFrame, rectangle.x / 4, rectangle.y / 3, rectangle.width /
        // 2, rectangle.height / 2);

        // batch.end();
    }

    /**
     * Called when the {@link Application} is destroyed. Preceded by a call to
     * pause().
     * <p>
     * LibGDX recommends disposing of assets in this method.
     * </p>
     */
    @Override
    public void dispose() {
        map.dispose();
        tilemapRenderer.dispose();

        batch.dispose();

        tileSheet.dispose();
    }
}

I think this is due to a scaling problem because if you remove the camera.setToOrtho, the texture follows the image correctly but when this line is added, it looks like the ratio of the coordinates is multiplied by 2, 3 or maybe even 4.

1

There are 1 best solutions below

1
bornander On

Setting full-screen mode in the create method of your ApplicationAdapter (MyGdxGame) breaks things in this case as some things are expected to already be initialized there.

If you remove

// Mettre la fenêtre en mode plein écran
Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode());

// Rendre le fenêtre redimensionnable
Gdx.graphics.setResizable(true);

from the create method and instead change your DesktopLauncher to

Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
config.setForegroundFPS(60);
config.setTitle("Boats-Management");
config.setWindowIcon("icon.png");
// Add this line
config.setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode());
new Lwjgl3Application(new MyGdxGame(), config);

all relevant things should be initialize when you hit create.

In addition to doing this I would change the camera setup so that it shows set number of tiles wide and maintains the aspect ratio:

// Mise en place de la caméra dans la scène
float aspectRatio = Gdx.graphics.getWidth() / (float) Gdx.graphics.getHeight();
float tilesWide = 65 * TILE_WIDTH;
camera = new OrthographicCamera(tilesWide, tilesWide / aspectRatio);
camera.position.set(camera.viewportWidth / 2.0f, camera.viewportHeight  /2.0f, 1.0f);
camera.update();

Change the 65 to whatever looks good in your game.

Lastly, you should tell your SpriteBatch to use a projection when rendering, in your render method:

// Add this line
batch.setProjectionMatrix(camera.combined); 
batch.begin();
batch.draw(currentFrame, vc.x, vc.y);
batch.end();