现在的位置: 首页 > 综合 > 正文

使用Libgdx进行游戏开发-动画

2014年02月06日 ⁄ 综合 ⁄ 共 10111字 ⁄ 字号 评论关闭

原文地址: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);
    }
复制代码

呼,终于忙完了。

抱歉!评论已关闭.