Libgdx之Animation 动画

一个好的游戏总归需要动画,Libgdx提供了Animation类来管理控制动画。
Animation: 储存了一组TextureRegion,然后顺序播放。例如在主角奔跑、跳跃的时候都需要用到Animation。每一个TextureRegion都是一帧,多帧组成了一组动画。

Animation的简单说明

Libgdx之Animation 动画_第1张图片    
上面的两幅图来自官方的wiki。 每个红色方框代表这一帧动画,代表了一个角色的一个跑步过程。我们将会用TextureRegion中split方法来切割这个图片。
在Animation中有一个参数 frameDuration 这个代表了每一帧图片在屏幕上显示的时间。1/frameDuration 就是帧率,也就是一秒钟显示多少幅图片。

Animationd 播放模式

  • NORMAL:这个不用说了,就是正常的播放模式。
  • REVERSED:反向播放,从后向前播放,这个就像人物倒退的跑。
  • LOOP:持续播放,这个比较常用。
  • LOOP_REVERSED:持续倒退播放。
  • LOOP_PINGPONG: 向前播放几张图片,再向后播放几帧图片。
    这里要注意一下,默认的初始化方法中只有一个是要初始化播放模式的,其余的默认都是PlayMode.NORMAL。这时可以通过setPlayMode方法来设置或者要通过获取关键帧的时候指定public TextureRegion getKeyFrame (float stateTime, boolean looping),如果此处设置为true,那么就设置PlayMode.LOOP

stateTime 的说明

在很多示例代码中都设置了这个stateTime,现在说说我的理解,stateTime就是一个时间计数器,初始化为stateTime=0

    /** Returns the current frame number. * @param stateTime * @return current frame number */
    public int getKeyFrameIndex (float stateTime) {
        if (keyFrames.length == 1) return 0;

        int frameNumber = (int)(stateTime / frameDuration);
        switch (playMode) {
        case NORMAL:
            frameNumber = Math.min(keyFrames.length - 1, frameNumber);
            break;
        case LOOP:
            frameNumber = frameNumber % keyFrames.length;
            break;
        case LOOP_PINGPONG:
            frameNumber = frameNumber % ((keyFrames.length * 2) - 2);
            if (frameNumber >= keyFrames.length) frameNumber = keyFrames.length - 2 - (frameNumber - keyFrames.length);
            break;
        case LOOP_RANDOM:
            int lastFrameNumber = (int) ((lastStateTime) / frameDuration);
            if (lastFrameNumber != frameNumber) {
                frameNumber = MathUtils.random(keyFrames.length - 1);
            } else {
                frameNumber = this.lastFrameNumber;
            }
            break;
        case REVERSED:
            frameNumber = Math.max(keyFrames.length - frameNumber - 1, 0);
            break;
        case LOOP_REVERSED:
            frameNumber = frameNumber % keyFrames.length;
            frameNumber = keyFrames.length - frameNumber - 1;
            break;
        }

        lastFrameNumber = frameNumber;
        lastStateTime = stateTime;

        return frameNumber;
    }

通过源码可以指定stateTime计算从开始播放动画开始,我们要计算经过多少个FPS时我们应该显示下一帧动画。

下面是测试代码

private static final String TAG = AnimationTest.class.getSimpleName();

    private static final int FRAME_COLS = 6; // 用来做动画的图片有6*5
    private static final int FRAME_ROWS = 5; // #2

    Animation walkAnimation; // 定义Animation对象,用来装载TextureRegion
    Animation reverseWalkAnimation;
    Texture walkSheet; // 装载6*5的图片
    TextureRegion[] walkFrames;
    SpriteBatch spriteBatch;
    TextureRegion currentFrame; // 记录关键帧,即当前要在batch画出的TextureRegion
    Vector2 postion;
    Direction direction;

    float stateTime; // 记录动画时间

    @Override
    public void create() {
        walkSheet = new Texture(Gdx.files.internal("sprite-animation1.png")); // #9
        TextureRegion[][] tmp = TextureRegion.split(walkSheet, walkSheet.getWidth() / FRAME_COLS, walkSheet.getHeight() / FRAME_ROWS); // #10
        walkFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS];
        int index = 0;
        for (int i = 0; i < FRAME_ROWS; i++) {
            for (int j = 0; j < FRAME_COLS; j++) {
                walkFrames[index++] = tmp[i][j];
            }
        }
        walkAnimation = new Animation(0.025f, walkFrames); // #11
        spriteBatch = new SpriteBatch(); // #12
        postion = new Vector2(50, 50);
        direction = Direction.RIGHT;
        stateTime = 0f; // #13

        Gdx.app.log(TAG, "frameDuration=" + walkAnimation.getFrameDuration());
        Gdx.app.log(TAG, "frameDuration=" + walkAnimation.getAnimationDuration());
    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(0.39f, 0.58f, 0.92f, 1.0f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);// #14

        stateTime += Gdx.graphics.getDeltaTime(); // #15
        if (direction == Direction.RIGHT) {
            postion.x += 50 * Gdx.graphics.getDeltaTime();
            walkAnimation.setPlayMode(PlayMode.LOOP);
        } else if (direction == Direction.LEFT) {
            postion.x -= 50 * Gdx.graphics.getDeltaTime();
            walkAnimation.setPlayMode(PlayMode.REVERSED);
        }

        if (postion.x + walkFrames[0].getRegionWidth() > Gdx.graphics.getWidth() - 50) {
            direction = Direction.LEFT;
        } else if (postion.x < 50) {
            direction = Direction.RIGHT;
        }
        currentFrame = walkAnimation.getKeyFrame(stateTime, true); // #16
        spriteBatch.begin();
        spriteBatch.draw(currentFrame, postion.x, postion.y); // #17
        spriteBatch.end();
    }

    @Override
    public void dispose() {
        walkSheet.dispose();
    }

    enum Direction {
        LEFT, RIGHT
    }

动画比较难展示,大家自己来运行就可以。下面是log输出

AnimationTest: frameDuration=0.025
AnimationTest: frameDuration=0.75

你可能感兴趣的:(libgdx)