android游戏开发框架libgdx的使用(二十三)—使用Universal Tween Engine实现动画效果

28 8月

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2012/08/28/libgdx_23/

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值。

publicstaticfinalint POSITION_X =1;
publicstaticfinalint POSITION_Y =2;
publicstaticfinalint POSITION_XY =3;

 

这里注意一下getValues的返回值,你修改或者操作了几个值就返回几。

代码如下:

package com.cnblogs.htynkn;

import aurelienribon.tweenengine.TweenAccessor;

import com.badlogic.gdx.scenes.scene2d.Actor;

publicclass ActorAccessor implements TweenAccessor {

publicstaticfinalint POSITION_X =1;
publicstaticfinalint POSITION_Y =2;
publicstaticfinalint POSITION_XY =3;

@Override
publicintgetValues(Actor target,int tweenType,float[] returnValues) {
switch (tweenType) {
case POSITION_X:
returnValues[0] = target.x;
return1;
case POSITION_Y:
returnValues[0] = target.y;
return1;
case POSITION_XY:
returnValues[0] = target.x;
returnValues[1] = target.y;
return2;
default:
assertfalse;
return -1;
}
}

@Override
publicvoidsetValues(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:
assertfalse;
break;
}
}
}

然后来写具体的动画和绘制部分。为了方便演示我编写一个随着点击移动的小图标的例子。

我的图标是news。声明image和stage的绘制和原来一样。

先声明一个动画管理器

private TweenManager tweenManager =new TweenManager();

然后将我们的Image注册一下

Tween.registerAccessor(Image.class,new ActorAccessor());

同时实现InputProcessor接口以接收触碰事件。

在touchDown方法中添加

@Override
publicbooleantouchDown(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);
returnfalse;
}

说明一下,因为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;

publicclass App implements ApplicationListener, InputProcessor {
Stage stage;
private TweenManager tweenManager =new TweenManager();
Image image;

@Override
publicvoidcreate() {
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
publicvoiddispose() {

}

@Override
publicvoidrender() {
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
publicvoidresize(int width,int height) {
}

@Override
publicvoidpause() {
}

@Override
publicvoidresume() {
}

@Override
publicbooleankeyDown(int keycode) {
// TODO Auto-generated method stub
returnfalse;
}

@Override
publicbooleankeyUp(int keycode) {
// TODO Auto-generated method stub
returnfalse;
}

@Override
publicbooleankeyTyped(char character) {
// TODO Auto-generated method stub
returnfalse;
}

@Override
publicbooleantouchDown(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);
returnfalse;
}

@Override
publicbooleantouchUp(int x,int y,int pointer,int button) {
// TODO Auto-generated method stub
returnfalse;
}

@Override
publicbooleantouchDragged(int x,int y,int pointer) {
// TODO Auto-generated method stub
returnfalse;
}

@Override
publicbooleantouchMoved(int x,int y) {
// TODO Auto-generated method stub
returnfalse;
}

@Override
publicbooleanscrolled(int amount) {
// TODO Auto-generated method stub
returnfalse;
}
}

因为是动画效果,这里就不贴出了,文章末尾会有一个小视频的。

使用TimeLine实现更多动画效果

上面只是一个简单的移动效果,但就动画而言这个显然是不够的。如果希望实现一个渐渐显示的效果怎么办?

还是想想TweenAccessor接口,只要float类型的值就行了。所以同样的我们可以实现修改透明程度、大小等等实现更多的效果。

我最终选用了六种效果:

publicstaticfinalint POS_XY =1;
publicstaticfinalint CPOS_XY =2;
publicstaticfinalint SCALE_XY =3;
publicstaticfinalint ROTATION =4;
publicstaticfinalint OPACITY =5;
publicstaticfinalint 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;

publicclass ActorAccessor implements TweenAccessor {
publicstaticfinalint POS_XY =1;
publicstaticfinalint CPOS_XY =2;
publicstaticfinalint SCALE_XY =3;
publicstaticfinalint ROTATION =4;
publicstaticfinalint OPACITY =5;
publicstaticfinalint TINT =6;

@Override
publicintgetValues(Actor target,int tweenType,float[] returnValues) {
switch (tweenType) {
case POS_XY:
returnValues[0] = target.x;
returnValues[1] = target.y;
return2;

case CPOS_XY:
returnValues[0] = target.x + target.width /2;
returnValues[1] = target.y + target.height /2;
return2;

case SCALE_XY:
returnValues[0] = target.scaleX;
returnValues[1] = target.scaleY;
return2;

case ROTATION:
returnValues[0] = target.rotation;
return1;
case OPACITY:
returnValues[0] = target.color.a;
return1;

case TINT:
returnValues[0] = target.color.r;
returnValues[1] = target.color.g;
returnValues[2] = target.color.b;
return3;

default:
assertfalse;
return -1;
}
}

@Override
publicvoidsetValues(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:
assertfalse;
}
}
}

因为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);

实现的就是一般移动一般旋转和放大的效果。

效果:

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2012/08/28/libgdx_23/

发表评论

您的电子邮箱地址不会被公开。