Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setScale() is broken in AtlasSprite and ParticleEffect #7303

Open
6 tasks done
raeleus opened this issue Dec 19, 2023 · 0 comments
Open
6 tasks done

setScale() is broken in AtlasSprite and ParticleEffect #7303

raeleus opened this issue Dec 19, 2023 · 0 comments

Comments

@raeleus
Copy link
Contributor

raeleus commented Dec 19, 2023

Issue details

A common problem when dealing with physics is that the simulation often uses meters instead of pixels as a unit of measurement. That means you should use an appropriate Viewport with world units and scale your sprites down by a Pixels Per Meter ratio. In Sprite, this would be sprite.setScale(1 / PPM).

That usually works, however the issue is that this does not work for sprites created from a TextureAtlas and the atlas was set to stripwhitespace. AtlasSprite handles most of the adjustments necessary for other transformations, but Sprite#getVertices() is not overridden. This method handles the localized position of the Sprite after scaling. So when the user scales down the sprite, the Sprite is drawn in the incorrect position.

Upon further investigation, I found that there is a similar problem with ParticleEffect. It turns out that ParticleEffect does not implement AtlasSprite at all, causing even more issues. This one is a little more complicated because Particle extends Sprite directly and is tightly paired with the functionality of ParticleEmitter. Note that the problems with ParticleEffect persist even if you just set the scale in the particle effect file.

In the end, you could just say that you shouldn't use the stripwhitespace option (and potentially rotate too). However, that is not documented and seems like an important oversight.

Reproduction steps/code

Create a texture atlas with the stripwhitespacex and stripwhitespacey options activated. Make sure to also use images with a lot of whitespace to make a noticeable difference. You may use code like this to reproduce:

package com.ray3k.testparticle;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;

public class Core extends ApplicationAdapter {
    private SpriteBatch batch;
    private ParticleEffect particleEffect;
    private TextureAtlas textureAtlas;
    private Viewport viewport;
    private static final float PPM = 20f;
    private static final Vector2 vector2 = new Vector2();

    private Sprite sprite;

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

        //load texture atlas with stripwhitespace activated
        textureAtlas = new TextureAtlas(Gdx.files.internal("textures/textures.atlas"));
        particleEffect.load(Gdx.files.internal("particles/dust.p"), textureAtlas, "game/");

        //load texture atlas with stripwhitespace deactivated
//        textureAtlas = new TextureAtlas(Gdx.files.internal("textures2/textures.atlas"));
//        particleEffect.load(Gdx.files.internal("particles/dust.p"), textureAtlas, "game/");

        particleEffect.scaleEffect(1f / PPM);

        viewport = new FitViewport(1024f / PPM, 576f / PPM);

        sprite = textureAtlas.createSprite("game/particle-smoke-4");
        sprite.setScale(1f / PPM);
    }

    @Override
    public void render() {
        particleEffect.update(Gdx.graphics.getDeltaTime());

        vector2.set(Gdx.input.getX(), Gdx.input.getY());
        viewport.unproject(vector2);
        particleEffect.setPosition(vector2.x, vector2.y);
        sprite.setCenter(viewport.getWorldWidth() / 2, viewport.getWorldHeight() / 2);

        ScreenUtils.clear(Color.LIGHT_GRAY);
        viewport.apply();
        batch.setProjectionMatrix(viewport.getCamera().combined);
        batch.begin();
        particleEffect.draw(batch);
        sprite.draw(batch);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
        viewport.update(width, height, true);
    }

    @Override
    public void dispose() {
        textureAtlas.dispose();
        particleEffect.dispose();
        batch.dispose();
    }
}

You may also use my atlas from my latest jam game as reference:
textures.zip
particles.zip

This version does not use stripwhitespace and works as intended:
textures2.zip

Incorrect positioning with stripwhitespace:
image

Correct positioning without stripwhitespace:
image

Version of libGDX and/or relevant dependencies

1.12.1

Please select the affected platforms

  • Android
  • iOS
  • HTML/GWT
  • Windows
  • Linux
  • macOS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant