[libGDX游戏开发教程]使用libGDX进行游戏开发(12)-Actor与Action

 

《使用Libgdx进行游戏开发》是一个系列,这是终章。所有文章连接都在这里


[libgdx游戏开发教程]使用Libgdx进行游戏开发(1)-游戏设计

[libgdx游戏开发教程]使用Libgdx进行游戏开发(2)-游戏框架搭建

[libgdx游戏开发教程]使用Libgdx进行游戏开发(3)-给游戏添加一些控制功能

[libgdx游戏开发教程]使用Libgdx进行游戏开发(4)-素材管理

[libGDX游戏开发教程]使用Libgdx进行游戏开发(5)-关卡加载

[libgdx游戏开发教程]使用Libgdx进行游戏开发(6)-添加主角和道具

[libgdx游戏开发教程]使用Libgdx进行游戏开发(7)-屏幕布局的最佳实践

[libgdx游戏开发教程]使用Libgdx进行游戏开发(8)-没有美工的程序员,能够依赖的还有粒子系统

[libgdx游戏开发教程]使用Libgdx进行游戏开发(9)-场景过渡

[libgdx游戏开发教程]使用Libgdx进行游戏开发(10)-音乐音效不求人,程序员也可以DIY

[libgdx游戏开发教程]使用Libgdx进行游戏开发(11)-高级编程技巧

[libGDX游戏开发教程]使用libGDX进行游戏开发(12)-动画


本章素材下载: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的威力了吗,哈哈

Libgdx支持的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: 只播放一次 (first frame to last)
• REVERSED: 这个也是播放一次,不过是从后往前 (last frame to first)
• LOOP: 循环播放(first frame to last)
• LOOP_REVERSED: 从后往前循环播放 (last frame to first)
• LOOP_PINGPONG: 像乒乓球一样来回播放 (first frame, to last,to first)
• LOOP_RANDOM: 随机循环播放 (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); }

好,终于完成了,跑起来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值