android游戏开发框架libgdx的使用(二十三)—使用Universal Tween Engine实现动画效果
转载声明:http://www.cnblogs.com/htynkn/archive/2012/08/28/libgdx_23.html
libgdx的ui库可以实现一些动画效果,但是做游戏来说可能有些不足。Universal Tween Engine是一个纯java实现的动画库。
地址:http://code.google.com/p/java-universal-tween-engine/
只要能够用float表示的一切java对象它可以让它动画化,可以使用于Libgdx、Android、Swing等等。
Universal Tween Engine使用一般流程
使用Universal Tween Engine最重要的一个步骤就是实现TweenAccessor接口,这个接口定义了getValues和setValues方法。
然后Engine中注册对应的接口。然后定义一些动画效果并添加到管理器中。最后用update方法更新时间。
具体的可以参考一下Wiki:http://code.google.com/p/java-universal-tween-engine/wiki/GetStarted
在libgdx中实现简单动画
我比较喜欢使用Stage,所以下面的例子都是Stage中的。
首先实现TweenAccessor接口,我没有区分对待,比如给Image写一个,再给Button写个啥的。我直接给Actor写了一个,这样都可以用。
getValues和setValues中我定义了3中操作:只修改X值;只修改Y值;修改X和Y值。
public static final int POSITION_X = 1; public static final int POSITION_Y = 2; public static final int POSITION_XY = 3;
这里注意一下getValues的返回值,你修改或者操作了几个值就返回几。
代码如下:
package com.cnblogs.htynkn; import aurelienribon.tweenengine.TweenAccessor; import com.badlogic.gdx.scenes.scene2d.Actor; public class ActorAccessor implements TweenAccessor { public static final int POSITION_X = 1; public static final int POSITION_Y = 2; public static final int POSITION_XY = 3; @Override public int getValues(Actor target, int tweenType, float[] returnValues) { switch (tweenType) { case POSITION_X: returnValues[0] = target.x; return 1; case POSITION_Y: returnValues[0] = target.y; return 1; case POSITION_XY: returnValues[0] = target.x; returnValues[1] = target.y; return 2; default: assert false; return -1; } } @Override public void setValues(Actor target, int tweenType, float[] newValues) { switch (tweenType) { case POSITION_X: target.x = newValues[0]; break; case POSITION_Y: target.y = newValues[0]; break; case POSITION_XY: target.x = newValues[0]; target.y = newValues[1]; break; default: assert false; break; } } }
然后来写具体的动画和绘制部分。为了方便演示我编写一个随着点击移动的小图标的例子。
先声明一个动画管理器
private TweenManager tweenManager = new TweenManager();
然后将我们的Image注册一下
Tween.registerAccessor(Image.class, new ActorAccessor());
同时实现InputProcessor接口以接收触碰事件。
在touchDown方法中添加
@Override public boolean touchDown(int x, int y, int pointer, int button) { Vector3 vector3 = new Vector3(x, y, 0); stage.getCamera().unproject(vector3); Tween.to(image, ActorAccessor.POSITION_XY, 1.0f).ease(Bounce.OUT) .target(vector3.x, vector3.y).start(tweenManager); return false; }
说明一下,因为Stage的坐标和默认的Input的坐标不一致,所以通过unproject转化一下。
Tween.to(image, ActorAccessor.POSITION_XY, 1.0f)代表操作image对象移动。target(vector3.x, vector3.y)代表移动的目标。
ease(Bounce.OUT)声明了缓冲效果,具体的效果可以参考http://robertpenner.com/easing/easing_demo.html
start(tweenManager)启动管理器。
在render方法中添加
tweenManager.update(Gdx.graphics.getDeltaTime());
让管理器的时间更新。
完整代码:
package com.cnblogs.htynkn; import aurelienribon.tweenengine.Tween; import aurelienribon.tweenengine.TweenManager; import aurelienribon.tweenengine.equations.Bounce; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.InputMultiplexer; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Image; public class App implements ApplicationListener, InputProcessor { Stage stage; private TweenManager tweenManager = new TweenManager(); Image image; @Override public void create() { stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true); TextureAtlas atlas = new TextureAtlas("packer/test.pack"); image = new Image(atlas.findRegion("news")); image.x = 20; image.y = 20; stage.addActor(image); Tween.registerAccessor(Image.class, new ActorAccessor()); InputMultiplexer multiplexer = new InputMultiplexer(); multiplexer.addProcessor(this); multiplexer.addProcessor(stage); Gdx.input.setInputProcessor(multiplexer); } @Override public void dispose() { } @Override public void render() { tweenManager.update(Gdx.graphics.getDeltaTime()); Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); stage.act(Gdx.graphics.getDeltaTime()); stage.draw(); } @Override public void resize(int width, int height) { } @Override public void pause() { } @Override public void resume() { } @Override public boolean keyDown(int keycode) { // TODO Auto-generated method stub return false; } @Override public boolean keyUp(int keycode) { // TODO Auto-generated method stub return false; } @Override public boolean keyTyped(char character) { // TODO Auto-generated method stub return false; } @Override public boolean touchDown(int x, int y, int pointer, int button) { Vector3 vector3 = new Vector3(x, y, 0); stage.getCamera().unproject(vector3); Tween.to(image, ActorAccessor.POSITION_XY, 1.0f).ease(Bounce.OUT) .target(vector3.x, vector3.y).start(tweenManager); return false; } @Override public boolean touchUp(int x, int y, int pointer, int button) { // TODO Auto-generated method stub return false; } @Override public boolean touchDragged(int x, int y, int pointer) { // TODO Auto-generated method stub return false; } @Override public boolean touchMoved(int x, int y) { // TODO Auto-generated method stub return false; } @Override public boolean scrolled(int amount) { // TODO Auto-generated method stub return false; } }
因为是动画效果,这里就不贴出了,文章末尾会有一个小视频的。
使用TimeLine实现更多动画效果
上面只是一个简单的移动效果,但就动画而言这个显然是不够的。如果希望实现一个渐渐显示的效果怎么办?
还是想想TweenAccessor接口,只要float类型的值就行了。所以同样的我们可以实现修改透明程度、大小等等实现更多的效果。
我最终选用了六种效果:
public static final int POS_XY = 1; public static final int CPOS_XY = 2; public static final int SCALE_XY = 3; public static final int ROTATION = 4; public static final int OPACITY = 5; public static final int COLOR = 6;
实现修改X和Y值,修改X和Y值(包括对象自身大小),修改缩放,修改旋转,修改透明,修改颜色。
代码如下:
package com.cnblogs.htynkn; import aurelienribon.tweenengine.TweenAccessor; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.scenes.scene2d.Actor; public class ActorAccessor implements TweenAccessor { public static final int POS_XY = 1; public static final int CPOS_XY = 2; public static final int SCALE_XY = 3; public static final int ROTATION = 4; public static final int OPACITY = 5; public static final int TINT = 6; @Override public int getValues(Actor target, int tweenType, float[] returnValues) { switch (tweenType) { case POS_XY: returnValues[0] = target.x; returnValues[1] = target.y; return 2; case CPOS_XY: returnValues[0] = target.x + target.width / 2; returnValues[1] = target.y + target.height / 2; return 2; case SCALE_XY: returnValues[0] = target.scaleX; returnValues[1] = target.scaleY; return 2; case ROTATION: returnValues[0] = target.rotation; return 1; case OPACITY: returnValues[0] = target.color.a; return 1; case TINT: returnValues[0] = target.color.r; returnValues[1] = target.color.g; returnValues[2] = target.color.b; return 3; default: assert false; return -1; } } @Override public void setValues(Actor target, int tweenType, float[] newValues) { switch (tweenType) { case POS_XY: target.x = newValues[0]; target.y = newValues[1]; break; case CPOS_XY: target.x = newValues[0] - target.width / 2; target.y = newValues[1] - target.height / 2; break; case SCALE_XY: target.scaleX = newValues[0]; target.scaleY = newValues[1]; break; case ROTATION: target.rotation = newValues[0]; break; case OPACITY: Color c = target.color; c.set(c.r, c.g, c.b, newValues[0]); target.color = c; break; case TINT: c = target.color; c.set(newValues[0], newValues[1], newValues[2], c.a); target.color = c; break; default: assert false; } } }
因为Actor中的color是final,所以不能修改,自己改一下源代码吧。
TimeLine是Universal Tween Engine中的一大利器,可以实现平行和顺序动画。
比如
Timeline.createSequence() .beginSequence() .push(Tween.to(image, ActorAccessor.POS_XY, 1.0f).target(100, 100)) .push(Tween.to(image, ActorAccessor.POS_XY, 1.0f).target(200, 20)).start(tweenManager);
就表示先移动到100,100处在移动到200,20处。
再比如
Timeline.createParallel() .beginParallel() .push(Tween.to(image, ActorAccessor.CPOS_XY, 1.0f).target( vector3.x, vector3.y)) .push(Tween.to(image, ActorAccessor.ROTATION, 1.0f).target(360)) .push(Tween.to(image, ActorAccessor.SCALE_XY, 1.0f).target( 1.5f, 1.5f)).end().start(tweenManager);
实现的就是一般移动一般旋转和放大的效果。
效果:
效果是一段视频 通过最上方的转载声明 查看原帖吧


浙公网安备 33010602011771号