LibGDX翻转二维精灵动画

LibGDX Flip 2D Sprite Animation

我有一个动画,我想在用户按下键盘上的 'A' 键时翻转播放。动画在文件中面向右侧并正常播放,直到我尝试翻转纹理。

这是当我尝试在玩家方向改变时翻转纹理时发生的情况:

如您所见,动画一开始播放得很好,但当我改变播放器的方向时,它会在翻转帧和未翻转帧之间交替。

这是我的播放器class:

package unit22.game;

import java.util.ArrayList;

import unit22.core.Utils;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class Player {

    private PlayerState state = PlayerState.STANDING;
    private Direction direction = Direction.RIGHT;
    private int x = 0, y = 0, width = 0, height = 0;
    private PlayerInputProcessor inputProcessor;
    private String name;

    private ArrayList<Action> actions;
    private Animation standingAnim;
    private Animation movingAnim;
    private float stateTime;
    private SpriteBatch spriteBatch;

    private Action currentAction;
    private Animation currentAnimation;

    public Player(String name, int x, int y, int width, int height) {
        this.name = name;
        setBounds(x, y, width, height);

        if(getX() > 400) setDirection(Direction.LEFT);

        this.actions = new ArrayList<Action>();

        standingAnim = new Animation(0.06f, Utils.loadTextureAtlas("standing", "textures/characters/animations/" + name + "/").getRegions());
        //movingAnim = new Animation(0.06f, Utils.loadTextureAtlas("moving", "textures/characters/animations/" + name + "/").getRegions());

        stateTime = 0f;
        spriteBatch = new SpriteBatch();
    }

    public void update() {
        stateTime += Gdx.graphics.getDeltaTime();
        switch(state) {
            case STANDING:
                if(currentAnimation != standingAnim)
                    currentAnimation = standingAnim;
                break;
            case MOVING:
                if(currentAnimation != movingAnim)
                    currentAnimation = movingAnim;
                break;
            case ACTING:
                Animation anim = new Animation(0.06f, Utils.loadTextureAtlas(currentAction.getName(), "textures/characters/animations/" + getName() + "/").getRegions());
                if(currentAnimation != anim)
                    currentAnimation = anim;
                break;
        }

    }

    public void render() {
        TextureRegion currentFrame = currentAnimation.getKeyFrame(stateTime, true);

        if(getDirection() == Direction.LEFT) {
            currentFrame.flip(true, false);
        }

        System.out.println("Direction: " + direction + ", Flipped: " + currentFrame.isFlipX());

        spriteBatch.begin();

        spriteBatch.draw(currentFrame, x, y, width, height);

        spriteBatch.end();
    }

    public ArrayList<Action> getActions() {
        return actions;
    }

    public void addAction(Action action) {
        this.actions.add(action);
    }

    public void setActions(ArrayList<Action> actions) {
        this.actions = actions;
    }

    public void setInputProcessor(PlayerInputProcessor inputProcessor) {
        this.inputProcessor = inputProcessor;
    }

    public PlayerInputProcessor getInputProcessor() {
        return inputProcessor;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public Direction getDirection() {
        return direction;
    }

    public PlayerState getState() {
        return state;
    }

    public void setDirection(Direction direction) {
        this.direction = direction;
    }

    public void setState(PlayerState state) {
        this.state = state;
    }

    public int[] getBounds() {
        return new int[] {x, y, width, height};
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    public void setBounds(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

}

在我的渲染方法中,我正在检查玩家的方向是否向左,如果是则翻转当前动画帧。

这是我处理输入的方式:

package unit22.screens;

import unit22.core.Game;
import unit22.core.Screen;
import unit22.game.Direction;
import unit22.game.Player;
import unit22.game.PlayerInputProcessor;

import com.badlogic.gdx.Gdx;

public class Playing extends Screen {

    Player player;

    public Playing(Game game, String name) {
        super(game, name);
    }

    @Override
    public void init() {


        player = new Player("misaka", 100, 100, 188, 380);

        player.setInputProcessor(new PlayerInputProcessor(player) {
            @Override
            public boolean keyTyped(char character) {
                if(getPlayer().getX() <= 14) getPlayer().setX(15);
                if(getPlayer().getX() + getPlayer().getWidth() >= 1024 - getPlayer().getWidth()) getPlayer().setX(1024 - getPlayer().getWidth() - 15);

                if(character == 'a' || character == 'A') {
                    getPlayer().setX((int)(getPlayer().getX() - (900 * Gdx.graphics.getDeltaTime())));
                    if(getPlayer().getDirection() == Direction.RIGHT) {
                        getPlayer().setDirection(Direction.LEFT);
                    }
                }

                if(character == 'd' || character == 'D') {
                    getPlayer().setX((int)(getPlayer().getX() + (900 * Gdx.graphics.getDeltaTime())));
                    if(getPlayer().getDirection() == Direction.LEFT) {
                        getPlayer().setDirection(Direction.RIGHT);
                    }
                }

                return super.keyTyped(character);
            }
        });

        getInputHandle().addProcessor(player.getInputProcessor());
    }

    @Override
    public void render(float delta) {
        super.render(delta);

        player.update();
        player.render();
    }

}

我已经尝试解决这个问题几个小时了,但没有取得任何进展。知道为什么会这样吗?

问题出在这里:

if(getDirection() == Direction.LEFT) {
    currentFrame.flip(true, false);
}

flip 方法永久翻转动画 class 引用的原始 TextureRegion。所以你要么需要确保每次翻转和绘制后都将其翻转回来,要么这样做,我认为这更简单:

不要翻转它,而是在使用 SpriteBatch 绘制时使用负宽度,如下所示:

boolean flip = (getDirection() == Direction.LEFT);
spriteBatch.draw(currentFrame, flip ? x+width : x, y, flip ? -width : width, height);

我知道这个问题很老,但我认为这是更好的解决方案

currentFrame = walkAnimation.getKeyFrame(stateTime, true); 

if(!currentFrame.isFlipX())
   currentFrame.flip(true, false);

  batch.draw(currentFrame,  0,0,0,0); 

如果有人仍然想知道,否定 scaleX 或 scaleY 就像一个魅力,并且不会损害性能(例如 TextureRegion.flip 会)。

示例:

draw(region, x, y, originX, originY, width, float height, 
     (flip ? -1 : 1) * scaleX, float scaleY, float rotation);

我使用下面的代码(在 kotlin 中)翻转我的动画序列:

    if (this.position <= 0f)
    {
        this.speed = - this.speed
        this.position = 0.0f

        this.runAnimation.keyFrames.forEach {
            it.flip(true, false)
        }
    }else if(this.position >= SCREEN_WIDTH / SCALE - width)
    {
        this.speed = - this.speed
        this.position = SCREEN_WIDTH / SCALE - width

        this.runAnimation.keyFrames.forEach {
            it.flip(true, false)
        }
    }

    this.game.batch.begin()
    this.game.batch.draw(currentFrame, this.position, 40f)
    this.game.batch.end()

每次翻转序列时,确保循环每一帧并翻转每一帧:

this.runAnimation.keyFrames.forEach { it.flip(true, false) }

请记住,帧会永远翻转,所以如果你想return返回,你应该再次翻转(flip = true)!