转自:http://www.apkbus.com/android-60822-1-1.html
下面提到的可视化版的libgdx图片打包工具:TexturePacker:
TexturePacker.rar(5.71 MB, 下载次数: 163)
本讲源代码下载:
edu.nju.wsj.libgdx.rar(4.41 MB, 下载次数: 285)
这一讲我们来尝试用Libgdx来实现
实现高仿launcher拖动效果。我们在第一次打开一个程序的时候总是会出现像这样的类似帮助的界面:
![1.png 1.png](http://www.apkbus.com/data/attachment/forum/201207/26/1639549mcdw3w69tw9ltwk.png)
这样的界面可以用来提供用户操作帮助或者介绍软件新版本特性,现在越来越多的软件都加入了这样的界面。对于我们写游戏用的libgdx,当然我们可以用SDK中的ViewPager并置于一个Activity来实现这一功能(相当于前面我介绍过的AndroidApplication和Activity的混用),但是我在DDMS的内存监控中发现这种方法占用的内存比较多,对于我们游戏这种需要有严格内存管理的程序而言显然是不合算的,而且我前面也和大家提到过,在Libgdx中使用AndroidApplication和Activity混用的切换不是非常流畅,所以我们需要用Screen来实现同样的功能。
本讲的代码在十四讲的基础上进行修改,首先我们需要再添加一个按钮,用于进入我们将要编写的一个仿Launcher的Screen里面。另外我们将这个AndroidApplication在Manifest中从强制横屏改为强制竖屏,方便显示,不过这样的话我们曾经加入的Dialog显示就不太正确了,大家可以自行修改。
![3.png 3.png](http://www.apkbus.com/data/attachment/forum/201207/26/163955mnzi0im93av2839w.png)
画红圈的就是我们新加入的按钮。然后我们新建一个Screen,用来仿launcher滑动的效果,初步工作我就在下面直接贴出来,后面复杂的工作我们再一步步来,重要的地方我都在里面做好了注释。这里使用了TexturePacker工具将几张图片打包然后一次性载入,具体如何使用大家可以查看官方文档或者查看巴士内一篇帖子:
我用这个可视化工具打包这次我们要用的图片:
这里建议大家用可视化版本的,极其方便,我会在附件中上传。
- public class PagerScreen implements GestureListener, Screen,InputProcessor{
- TextureAtlas pager;
- SpriteBatch batch;
- //只有在第一次启动的时候需要将资源初始化
- boolean hasini;
- TextureRegion[] pages;
- LibgdxActivity activity;
- //用来存储长和宽的值
- int min;
- int max;
- //用来标记第一张图片的位置,可以为负,无法显示的部分就不会被画出
- int position;
- //循环遍历用
- int i;
- @Override
- public void dispose() {
- // TODO Auto-generated method stub
- }
- @Override
- public void hide() {
- // TODO Auto-generated method stub
- }
- @Override
- public void pause() {
- // TODO Auto-generated method stub
- }
- @Override
- public void render(float arg0) {
- // TODO Auto-generated method stub
- Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- Gdx.gl.glClearColor(0f,0f,0f,0f);
- batch.begin();
- for(i=0;i<pages.length;i++)
- batch.draw(pages[i],position+i*min, 0,min,max);
- batch.end();
- }
- @Override
- public void resize(int arg0, int arg1) {
- // TODO Auto-generated method stub
- }
- @Override
- public void resume() {
- // TODO Auto-generated method stub
- }
- public PagerScreen(LibgdxActivity activity) {
- super();
- this.activity=activity;
- // TODO Auto-generated constructor stub
- }
- @Override
- public void show() {
- // TODO Auto-generated method stub
- max=Gdx.graphics.getHeight()>Gdx.graphics.getWidth()?Gdx.graphics.getHeight():Gdx.graphics.getWidth();
- min=Gdx.graphics.getHeight()<Gdx.graphics.getWidth()?Gdx.graphics.getHeight():Gdx.graphics.getWidth();
- if(!hasini){
- batch=new SpriteBatch();
- //这里使用了TexturePacker工具将几张图片打包然后一次性载入,具体如何使用大家可以查看官方文档。
- pages=new TextureRegion[5];
- pager=new TextureAtlas(Gdx.files.internal("pack"));
- pages[0]=pager.findRegion("1");
- pages[1]=pager.findRegion("2");
- pages[2]=pager.findRegion("3");
- pages[3]=pager.findRegion("4");
- pages[4]=pager.findRegion("5");
- hasini=true;
- }
- //将当前Screen加入按键和手势监听队列
- InputMultiplexer multiplexer = new InputMultiplexer();
- multiplexer.addProcessor(this);
- multiplexer.addProcessor(new GestureDetector(this));
- Gdx.input.setInputProcessor(multiplexer); }
- @Override
- public boolean fling(float arg0, float arg1) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean longPress(int arg0, int arg1) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean pan(int arg0, int arg1, int arg2, int arg3) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean pinch(Vector2 arg0, Vector2 arg1, Vector2 arg2, Vector2 arg3) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean tap(int arg0, int arg1, int arg2) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean touchDown(int arg0, int arg1, int arg2) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean zoom(float arg0, float arg1) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean keyDown(int arg0) {
- // TODO Auto-generated method stub
- //返回键按下的时候返回上一界面
- if(arg0==Input.Keys.BACK)
- activity.ag.setScreen(activity.mg);
- return false;
- }
- @Override
- public boolean keyTyped(char arg0) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean keyUp(int arg0) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean scrolled(int arg0) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean touchDown(int arg0, int arg1, int arg2, int arg3) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean touchDragged(int arg0, int arg1, int arg2) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean touchMoved(int arg0, int arg1) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean touchUp(int arg0, int arg1, int arg2, int arg3) {
- // TODO Auto-generated method stub
- return false;
- }
- }
设置MyGame.java中新加入的按钮被按下时启动这个
Screen,具体代码稍作修改大家可以看源码:
- toPager = new Button( new ButtonStyle(n1, n2, n3, 0f, 0f, 0f, 0f), "Start");
- toPager.setClickListener(new ClickListener() {
- @Override
- public void click(Actor arg0, float arg1, float arg2) {
- // TODO Auto-generated method stub
- activity.ag.setScreen(activity.ps);
- }
- });
- toPager.x=Gdx.graphics.getWidth()/3;
- toPager.y=Gdx.graphics.getWidth()/3;
- stage.addActor(toPager);
运行一下,并按下刚才我们加入的那个按钮,看看效果:
这时候我们还是不能翻动。我们这个Screen还实现了GestureListener这个接口,我们在pan()函数中监听手势翻动作用,并且做出相应的处理.我们考虑一下极端情况,用于标记第一张图片位置的变量position最大值无非就是0,显示后面的图片的时候,这张图片的位置左移,其值一定小于0,但是又不能小于一定值,position的最小值对应于最后一张图片在最右侧并且无法继续右移。下面要用到这个范围,不然会出很严重的问题。
再介绍一下pan()这个回调函数中的四个参数:
- public boolean pan(int arg0, int arg1, int arg2, int arg3);
前两个参数指的是当前触摸点的x,y值,后两个标记当前用户手指的分别在x,y方向的移动速度。这里我们只用第一个参数x。简单的原理如下:用户的每次手势都会触发touchDown()方法,我们在touchDown()中存储当前按下的位置的x值,然后滑动手势开始后我们不停更新前一个位置,并且将position的大小做出相应的改变,改变量为当前位置的x值减去前一个位置的x值。我们先在PageScreen.java中添加相应的标记当前触摸点和上一个触摸点的x值的变量。
- float prex;
- float currentx;
在touchDown()函数中标记currentx:
- currentx=arg0;
在pan()函数中做出相应的处理,当然首先应该满足我们上面提到过的,postion有最大值和最小值,不可能超过这个范围,这一点非常重要。
- @Override
- public boolean pan(int arg0, int arg1, int arg2, int arg3) {
- // TODO Auto-generated method stub
- //position应该有一定的范围
- System.out.println(position);
- if(position<=0&&position>=-(pages.length-1)*min){
- prex=currentx;
- currentx=arg0;
- if(position+currentx-prex<=0&&position+currentx-prex>=-(pages.length-1)*min)
- position+=currentx-prex;
- else{
- if(position+currentx-prex>0)
- position=0;
- if(position+currentx-prex<-(pages.length-1)*min)
- position=-(pages.length-1)*min;
- }
- }
- return false;
- }
运行一下,看看效果
:
我们发现,完全可以正常滑动了,不过还有一个小问题,整个页面的显示完全依赖我们的滑动,而不是像我们需要仿的Launcher滑动有个自动吸附的功能,也就是当滑动到一定程度的时候会自动跳转到下一个页面。因此我们还需要做进一步的处理
。这里我们认为一张图片翻过一半的时候就应该跳转到下一张图片。我们在render()函数中实现这个效果,在手指按下的时候不回弹,手指松开后进行回弹的动作。我们需要在PageScreen.java中添加一个变量,用于回弹的标记:
- float targetposition;
修改后的render()函数如下,复杂的地方下面都做了注释:
- @Override
- public void render(float arg0) {
- // TODO Auto-generated method stub
- Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- Gdx.gl.glClearColor(0f,0f,0f,0f);
- batch.begin();
- for(i=0;i<pages.length;i++)
- batch.draw(pages[i],position+i*min, 0,min,max);
- batch.end();
- //用户放手时才进行回弹
- if(!Gdx.input.isTouched()){
- //巧妙的用一个取整数的函数来表示一张图片翻过一半的时候就应该跳转到下一张图片的效果
- targetposition=(int)((position-0.5f*min)/min)*min;
- if(targetposition<position){
- //注意不能越界,min/480f是一个因子,用于分辨率适配,让回弹速度和分辨率搭配得协调一些
- if(position-20*min/480f<targetposition)
- position=targetposition;
- else
- position-=20*min/480f;
- }
- if(targetposition>position)
- //注意不能越界
- if(position+20*min/480f>targetposition)
- position=targetposition;
- else
- position+=20*min/480f;
- }
- }
运行一下:
功能完全正常效果也不错,而且由于使用了Screen实现,在切换界面的时候非常流畅,我们可以用它来实现libgdx游戏中的帮助效果。