使用Libgdx進行遊戲開發-動畫

原文地址:http://www.cnblogs.com/mignet/p/libgdx_game_development_12.html

打包的素材:http://files.cnblogs.com/mignet/animate.7z

在這一章我們將通過動畫來豐富我們的遊戲效果。

使用action來操作actor:

很多同學應該都很清楚action是什麼東東,所以這裏僅僅舉個最常見的例子。

moveTo (x, y);
moveTo (x, y, duration);
moveTo (x, y, duration, interpolation);
rotateTo (rotation);
rotateTo (rotation, duration);
rotateTo (rotation, duration, interpolation);

來過連續動作:

複製代碼
Actor actor = new Actor();
float x = 100.0f, y = 100.0f, rotation = 0.0f, duration = 1.0f;
actor.addAction(sequence(
moveTo(x, y),
rotateTo(rotation),
delay(duration),
parallel(moveBy(50.0f, 0.0f, 5.0f),
rotateBy(90.0f, 5.0f, Interpolation.swingOut))));
複製代碼

Interpolation插值算法和前文提到的一樣。現在,發現actor+action的威力了嗎,哈哈

動作列表:

•add(): This adds an action to an actor.
•alpha(): This sets the alpha value of an actor's color.
•color(): This sets the color of an actor.
•fadeIn() and fadeOut(): These are convenience actions to set the alpha value of an actor's color to 1 or 0, respectively.
•hide(): This sets the visibility of an actor to false.
•layout(): This sets the actor's layout to enabled or disabled.
•moveBy() and moveTo(): These move an actor by a relative amount or to a specific location.
•removeActor(): This removes the actor to which this action is attached. Alternatively, another actor that is to be removed can be specified.
•rotateBy() and rotateTo(): These rotate an actor by a relative amount or to a specific angle of rotation.
•run(): This runs a Runnable (the code will be executed in a separate thread).
•scaleBy() and scaleTo(): These scale an actor by a relative amount or to a specific scale.
• show(): This sets the visibility of an actor to true.
• sizeBy() and sizeTo(): These resize an actor by a relative amount or to a specific size.
• touchable(): This sets the touchability of an actor(refer to Touchable enumerator).
• visible(): This sets the visibility of an actor.

控制執行的順序和時間:

• after(): This waits for other actions of an actor to finish before its action is executed. Note that this action will only wait for other actions that were already added to an actor prior to this.
• delay(): This delays the execution of an action.
• forever(): This repeats an action forever.
• parallel():This executes a list of actions at the same time.
• repeat(): This repeats an action for a given number of times.
• sequence(): This executes a list of actions one after another.

讓菜單屏幕動起來:

動畫效果:首先金幣和兔子頭是看不見的,接着金幣淡入和比例從0%提高到100%,這樣看起來好像是跳出了水面到中心屏幕上一樣,短暫的停頓之後,兔子頭出現在右上角,兔子頭移動,就好像它是跳躍到它前面的其他的岩石上。

首先,修改MenuScreen:

複製代碼
private Table buildObjectsLayer() {
        Table layer = new Table();
        // + Coins
        imgCoins = new Image(skinCanyonBunny, "coins");
        layer.addActor(imgCoins);
        imgCoins.setOrigin(imgCoins.getWidth() / 2,
                imgCoins.getHeight() / 2);
                imgCoins.addAction(sequence(
                moveTo(135, -20),
                scaleTo(0, 0),
                fadeOut(0),
                delay(2.5f),
                parallel(moveBy(0, 100, 0.5f, Interpolation.swingOut),
                scaleTo(1.0f, 1.0f, 0.25f, Interpolation.linear),
                alpha(1.0f, 0.5f))));
        // + Bunny
        imgBunny = new Image(skinCanyonBunny, "bunny");
        layer.addActor(imgBunny);
        imgBunny.addAction(sequence(
                moveTo(655, 510),
                delay(4.0f),
                moveBy(-70, -100, 0.5f, Interpolation.fade),
                moveBy(-100, -50, 0.5f, Interpolation.fade),
                moveBy(-150, -300, 1.0f, Interpolation.elasticIn)));
        return layer;
    }
複製代碼

讓menu和Option動起來:

添加MenuScreen:

複製代碼
    private void showMenuButtons(boolean visible) {
        float moveDuration = 1.0f;
        Interpolation moveEasing = Interpolation.swing;
        float delayOptionsButton = 0.25f;
        float moveX = 300 * (visible ? -1 : 1);
        float moveY = 0 * (visible ? -1 : 1);
        final Touchable touchEnabled = visible ? Touchable.enabled
                : Touchable.disabled;
        btnMenuPlay.addAction(moveBy(moveX, moveY, moveDuration, moveEasing));
        btnMenuOptions.addAction(sequence(delay(delayOptionsButton),
                moveBy(moveX, moveY, moveDuration, moveEasing)));
        SequenceAction seq = sequence();
        if (visible)
            seq.addAction(delay(delayOptionsButton + moveDuration));
        seq.addAction(run(new Runnable() {
            public void run() {
                btnMenuPlay.setTouchable(touchEnabled);
                btnMenuOptions.setTouchable(touchEnabled);
            }
        }));
        stage.addAction(seq);
    }

    private void showOptionsWindow(boolean visible, boolean animated) {
        float alphaTo = visible ? 0.8f : 0.0f;
        float duration = animated ? 1.0f : 0.0f;
        Touchable touchEnabled = visible ? Touchable.enabled
                : Touchable.disabled;
        winOptions.addAction(sequence(touchable(touchEnabled),
                alpha(alphaTo, duration)));
    }
複製代碼

修改:

複製代碼
private Table buildOptionsWindowLayer () {
...
// Make options window slightly transparent
winOptions.setColor(1, 1, 1, 0.8f);
// Hide options window by default
showOptionsWindow(false, false);
if (debugEnabled) winOptions.debug();
// Let TableLayout recalculate widget sizes and positions
winOptions.pack();
// Move options window to bottom right corner
winOptions.setPosition(Constants.VIEWPORT_GUI_WIDTH
- winOptions.getWidth() - 50, 50);
return winOptions;
}
private void onOptionsClicked () {
  loadSettings();
  showMenuButtons(false);
  showOptionsWindow(true, true);
}
private void onCancelClicked () {
  showMenuButtons(true);
  showOptionsWindow(false, true);
  AudioManager.instance.onSettingsUpdated();
}
複製代碼

使用的圖像序列動畫:

用texture packer把序列圖片打包。

Libgdx播放動畫的不同模式:

• NORMAL: This plays the animation once (first frame to last)
• REVERSED: This plays the animation once (last frame to first)
• LOOP: This plays the animation in a loop (first frame to last)
• LOOP_REVERSED: This plays the animation in a loop (last frame to first)
• LOOP_PINGPONG: This plays the animation in a loop (first frame, to last,to first)
• LOOP_RANDOM: This plays the animation in a loop (random frames)

給遊戲場景增加動畫:

這三個動畫將分別使用不同的模式:

1. The first animation animCopterTransform plays all frames once (play mode:NORMAL; frame progression: 01, 02, 03, 04, 05).
2. The second animation animCopterRotate plays the last two frames in a ping-pong loop

(play mode: LOOP_PINGPONG; frame progression: 04, 05, 05,04, [restart at first frame]).
3. Lastly, the third animation animCopterTransformBack is simply the reverse of the first animation (play mode: REVERSED; frame progression: 05, 04, 03,02, 01).

首先,在Assets添加素材:

複製代碼
public class AssetGoldCoin {
        public final AtlasRegion goldCoin;
        public final Animation animGoldCoin;
        
        public AssetGoldCoin(TextureAtlas atlas) {
            goldCoin = atlas.findRegion("item_gold_coin");
            // Animation: Gold Coin
            Array<AtlasRegion> regions =
            atlas.findRegions("anim_gold_coin");
            AtlasRegion region = regions.first();
            for (int i = 0; i < 10; i++)
            regions.insert(0, region);
            animGoldCoin = new Animation(1.0f / 20.0f, regions,
            Animation.LOOP_PINGPONG);
        }
    }

public class AssetBunny {
        public final AtlasRegion head;
        public final Animation animNormal;
        public final Animation animCopterTransform;
        public final Animation animCopterTransformBack;
        public final Animation animCopterRotate;

        public AssetBunny(TextureAtlas atlas) {
            head = atlas.findRegion("bunny_head");
            Array<AtlasRegion> regions = null;
            AtlasRegion region = null;
            // Animation: Bunny Normal
            regions = atlas.findRegions("anim_bunny_normal");
            animNormal = new Animation(1.0f / 10.0f, regions,
            Animation.LOOP_PINGPONG);
            // Animation: Bunny Copter - knot ears
            regions = atlas.findRegions("anim_bunny_copter");
            animCopterTransform = new Animation(1.0f / 10.0f, regions);
            // Animation: Bunny Copter - unknot ears
            regions = atlas.findRegions("anim_bunny_copter");
            animCopterTransformBack = new Animation(1.0f / 10.0f, regions,
            Animation.REVERSED);
            // Animation: Bunny Copter - rotate ears
            regions = new Array<AtlasRegion>();
            regions.add(atlas.findRegion("anim_bunny_copter", 4));
            regions.add(atlas.findRegion("anim_bunny_copter", 5));
            animCopterRotate = new Animation(1.0f / 15.0f, regions);
        }
    }
複製代碼

修改AbstractGameObject:

複製代碼
    public float stateTime;
    public Animation animation;

    public void setAnimation(Animation animation) {
        this.animation = animation;
        stateTime = 0;
    }
public void update (float deltaTime) {
  stateTime += deltaTime;
if (body == null) {
  updateMotionX(deltaTime);
  updateMotionY(deltaTime);
  // Move to new position
  position.x += velocity.x * deltaTime;
  position.y += velocity.y * deltaTime;
} else {
  position.set(body.getPosition());
  rotation = body.getAngle() * MathUtils.radiansToDegrees;
  }
}
複製代碼

修改GoldCoin:

複製代碼
    private void init() {
        dimension.set(0.5f, 0.5f);
        setAnimation(Assets.instance.goldCoin.animGoldCoin);
        stateTime = MathUtils.random(0.0f, 1.0f);
        // Set bounding box for collision detection
        bounds.set(0, 0, dimension.x, dimension.y);
        collected = false;
    }

    public void render(SpriteBatch batch) {
        if (collected)
            return;
        TextureRegion reg = null;
        reg = animation.getKeyFrame(stateTime, true);
        batch.draw(reg.getTexture(), position.x, position.y, origin.x,
                origin.y, dimension.x, dimension.y, scale.x, scale.y, rotation,
                reg.getRegionX(), reg.getRegionY(), reg.getRegionWidth(),
                reg.getRegionHeight(), false, false);
    }
複製代碼

現在,給兔子頭加動畫,主要是螺旋槳飛行:

這裏用到了狀態機的概念,我們兔子頭就是有限狀態機,也就是說,它在任何時候一定處於有限狀態的某種狀態中,並且在合適的時候進行狀態的切換。

我們來修改BunnyHead:

複製代碼
private Animation animNormal;
private Animation animCopterTransform;
private Animation animCopterTransformBack;
private Animation animCopterRotate;

public void init () {
dimension.set(1, 1);
animNormal = Assets.instance.bunny.animNormal;
animCopterTransform = Assets.instance.bunny.animCopterTransform;
animCopterTransformBack =
Assets.instance.bunny.animCopterTransformBack;
animCopterRotate = Assets.instance.bunny.animCopterRotate;
setAnimation(animNormal);
// Center image on game object
origin.set(dimension.x / 2, dimension.y / 2);
...
}
@Override
    public void update(float deltaTime) {
        super.update(deltaTime);
        if (velocity.x != 0) {
            viewDirection = velocity.x < 0 ? VIEW_DIRECTION.LEFT
                    : VIEW_DIRECTION.RIGHT;
        }
        if (timeLeftFeatherPowerup > 0) {
            if (animation == animCopterTransformBack) {
                // Restart "Transform" animation if another feather power-up
                // was picked up during "TransformBack" animation. Otherwise,
                // the "TransformBack" animation would be stuck while the
                // power-up is still active.
                setAnimation(animCopterTransform);
            }
            timeLeftFeatherPowerup -= deltaTime;
            if (timeLeftFeatherPowerup < 0) {
                // disable power-up
                timeLeftFeatherPowerup = 0;
                setFeatherPowerup(false);
                setAnimation(animCopterTransformBack);
            }
        }
        dustParticles.update(deltaTime);
        // Change animation state according to feather power-up
        if (hasFeatherPowerup) {
            if (animation == animNormal) {
                setAnimation(animCopterTransform);
            } else if (animation == animCopterTransform) {
                if (animation.isAnimationFinished(stateTime))
                    setAnimation(animCopterRotate);
            }
        } else {
            if (animation == animCopterRotate) {
                if (animation.isAnimationFinished(stateTime))
                    setAnimation(animCopterTransformBack);
            } else if (animation == animCopterTransformBack) {
                if (animation.isAnimationFinished(stateTime))
                    setAnimation(animNormal);
            }
        }
    }
@Override
    public void render(SpriteBatch batch) {
        TextureRegion reg = null;
        // Draw Particles
        dustParticles.draw(batch);
        // Apply Skin Color
        batch.setColor(CharacterSkin.values()[GamePreferences.instance.charSkin]
                .getColor());
        float dimCorrectionX = 0;
        float dimCorrectionY = 0;
        if (animation != animNormal) {
            dimCorrectionX = 0.05f;
            dimCorrectionY = 0.2f;
        }
        // Draw image
        reg = animation.getKeyFrame(stateTime, true);
        batch.draw(reg.getTexture(), position.x, position.y, origin.x,
                origin.y, dimension.x + dimCorrectionX, dimension.y
                        + dimCorrectionY, scale.x, scale.y, rotation,
                reg.getRegionX(), reg.getRegionY(), reg.getRegionWidth(),
                reg.getRegionHeight(), viewDirection == VIEW_DIRECTION.LEFT,
                false);
        // Reset color to white
        batch.setColor(1, 1, 1, 1);
    }
複製代碼

呼,終於忙完了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章