java-universal-tween-engine

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


1
2
3
public static final int POSITION_X = 1;
	public static final int POSITION_Y = 2;
	public static final int POSITION_XY = 3;


 

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

代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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;
		}
	}
}


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

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

先声明一个动画管理器


1
private TweenManager tweenManager = new TweenManager();


然后将我们的Image注册一下


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


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

在touchDown方法中添加


1
2
3
4
5
6
7
8
9
@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方法中添加


1
tweenManager.update(Gdx.graphics.getDeltaTime());


让管理器的时间更新。

完整代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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类型的值就行了。所以同样的我们可以实现修改透明程度、大小等等实现更多的效果。

我最终选用了六种效果:


1
2
3
4
5
6
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值(包括对象自身大小),修改缩放,修改旋转,修改透明,修改颜色。

代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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中的一大利器,可以实现平行和顺序动画。

比如


1
2
3
4
5
6
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处。

再比如


1
2
3
4
5
6
7
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);


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




你可能感兴趣的:(android,源码分析,libgdx)