#Testin杯#Mkey libgdx游戏引擎教程(十五)在Libgdx中仿微信帮助滑动效果(附源码)

137
回复
499815
查看
  [复制链接]

30

主题

350

帖子

1089

安币

Android大神

Rank: 6Rank: 6

QQ达人

版主推荐 发表于 2012-7-26 16:56:46 | 显示全部楼层 |阅读模式
本帖最后由 耒佲請ぁ留埗 于 2012-8-3 11:45 编辑


以下系列教程按讲课顺序排列,也是推荐阅读的顺序

第一讲:libgdx游戏引擎教程(一)性能优良的游戏引擎—libgdx http://www.apkbus.com/android-57355-1-1.html

第二讲: libgdx游戏引擎教程(二) ApplicationListener,着手第一个程序http://www.apkbus.com/android-57372-1-1.html

第三讲:libgdx游戏引擎教程()libgdx粒子系统的使用 http://www.apkbus.com/android-57456-1-1.html

外篇一:libgdx游戏引擎教程外篇(一)优美的自定义进度条(附源码) http://www.apkbus.com/android-57523-1-1.html

第四讲:libgdx游戏引擎教程(四) 游戏正式开始,资源异步加载(附源码)http://www.apkbus.com/android-57716-1-1.html

第五讲 libgdx游戏引擎教程(五)多游戏界面的实现(一)附源码 http://www.apkbus.com/android-57936-1-1.html

第六讲 libgdx游戏引擎教程(六)多游戏界面的实现(二)附源码 http://www.apkbus.com/android-57991-1-1.html  

第七讲 libgdx游戏引擎教程(七) 在libgdx中拦截Android按键事件 http://www.apkbus.com/android-58030-1-1.html  

外篇二: libgdx游戏引擎教程外篇(二)libgdx移植俄罗斯方块(附源码) http://www.apkbus.com/android-58102-1-1.html   

实战一:libgdx游戏引擎教程实战篇(一)移植俄罗斯方块(附源码) http://www.apkbus.com/android-58404-1-1.html  

实战二:libgdx游戏引擎教程实战篇(二)移植俄罗斯方块(附源码) http://www.apkbus.com/android-58408-1-1.html  

实战三:libgdx游戏引擎教程实战篇(三)移植俄罗斯方块(附源码) http://www.apkbus.com/android-58414-1-1.html  

实战四:libgdx游戏引擎教程实战篇(四)移植俄罗斯方块(附源码) http://www.apkbus.com/android-58418-1-1.html  

实战五:libgdx游戏引擎教程实战篇(五)移植俄罗斯方块(附源码) http://www.apkbus.com/android-58419-1-1.html

实战六:libgdx游戏引擎教程实战篇(六)移植俄罗斯方块(附源码) http://www.apkbus.com/android-58760-1-1.html

第八讲 libgdx游戏引擎教程(八) libgdx中的用户手势识别(一)附源码 http://www.apkbus.com/android-58933-1-1.html

第九讲 libgdx游戏引擎教程(九) libgdx中的用户手势识别(二)附源码 http://www.apkbus.com/android-59152-1-1.html

外篇三: libgdx游戏引擎教程外篇(三) 优美的自定义对话框(附源码) http://www.apkbus.com/android-59654-1-1.html  

第十讲:  libgdx游戏引擎教程(十)演员类的复杂动画(一)(附源码) http://www.apkbus.com/android-59998-1-2.html

第十一讲:libgdx游戏引擎教程(十一)演员类的复杂动画(二)(附源码) http://www.apkbus.com/android-60053-1-1.html

第十二讲:libgdx游戏引擎教程(十二)演员类的复杂动画(三)(附源码) http://www.apkbus.com/android-60194-1-1.html   

第十三讲: libgdx游戏引擎教程(十三)演员类的用户交互功能详解(附源码)  http://www.apkbus.com/android-60457-1-1.html

第十四讲:libgdx游戏引擎教程(十四)libgdx中常用的控件(附源码) http://www.apkbus.com/android-60569-1-1.html

最新更新 第十五讲 :libgdx游戏引擎教程(十五)在Libgdx中仿微信帮助滑动效果(附源码) http://www.apkbus.com/android-60822-1-1.html


下面提到的可视化版的libgdx图片打包工具:TexturePacker:


本讲源代码下载:





这一讲我们来尝试用Libgdx来实现实现高仿launcher拖动效果。我们在第一次打开一个程序的时候总是会出现像这样的类似帮助的界面:


这样的界面可以用来提供用户操作帮助或者介绍软件新版本特性,现在越来越多的软件都加入了这样的界面。对于我们写游戏用的libgdx,当然我们可以用SDK中的ViewPager并置于一个Activity来实现这一功能(相当于前面我介绍过的AndroidApplication和Activity的混用),但是我在DDMS的内存监控中发现这种方法占用的内存比较多,对于我们游戏这种需要有严格内存管理的程序而言显然是不合算的,而且我前面也和大家提到过,在Libgdx中使用AndroidApplication和Activity混用的切换不是非常流畅,所以我们需要用Screen来实现同样的功能
本讲的代码在十四讲的基础上进行修改,首先我们需要再添加一个按钮,用于进入我们将要编写的一个仿Launcher的Screen里面。另外我们将这个AndroidApplication在Manifest中从强制横屏改为强制竖屏,方便显示,不过这样的话我们曾经加入的Dialog显示就不太正确了,大家可以自行修改。


画红圈的就是我们新加入的按钮。然后我们新建一个Screen,用来仿launcher滑动的效果,初步工作我就在下面直接贴出来,后面复杂的工作我们再一步步来,重要的地方我都在里面做好了注释。这里使用了TexturePacker工具将几张图片打包然后一次性载入,具体如何使用大家可以查看官方文档或者查看巴士内一篇帖子:


我用这个可视化工具打包这次我们要用的图片:





这里建议大家用可视化版本的,极其方便,我会在附件中上传。
  1. public class PagerScreen implements GestureListener, Screen,InputProcessor{
  2.         TextureAtlas pager;
  3.         SpriteBatch batch;
  4.         //只有在第一次启动的时候需要将资源初始化
  5.         boolean hasini;
  6.         TextureRegion[] pages;
  7.         LibgdxActivity activity;
  8.         //用来存储长和宽的值
  9.         int min;
  10.         int max;
  11.         //用来标记第一张图片的位置,可以为负,无法显示的部分就不会被画出
  12.         int position;
  13.         //循环遍历用
  14.         int i;
  15.         
  16.         @Override
  17.         public void dispose() {
  18.                 // TODO Auto-generated method stub

  19.         }

  20.         @Override
  21.         public void hide() {
  22.                 // TODO Auto-generated method stub

  23.         }

  24.         @Override
  25.         public void pause() {
  26.                 // TODO Auto-generated method stub

  27.         }

  28.         @Override
  29.         public void render(float arg0) {
  30.                 // TODO Auto-generated method stub
  31.                 Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  32.                 Gdx.gl.glClearColor(0f,0f,0f,0f);
  33.                 batch.begin();
  34.                 for(i=0;i<pages.length;i++)
  35.                         batch.draw(pages[i],position+i*min, 0,min,max);
  36.                 batch.end();
  37.         }

  38.         @Override
  39.         public void resize(int arg0, int arg1) {
  40.                 // TODO Auto-generated method stub

  41.         }

  42.         @Override
  43.         public void resume() {
  44.                 // TODO Auto-generated method stub

  45.         }
  46.         
  47.         public PagerScreen(LibgdxActivity activity) {
  48.                 super();
  49.                 this.activity=activity;
  50.                 // TODO Auto-generated constructor stub
  51.         }

  52.         @Override
  53.         public void show() {
  54.                 // TODO Auto-generated method stub
  55.                 max=Gdx.graphics.getHeight()>Gdx.graphics.getWidth()?Gdx.graphics.getHeight():Gdx.graphics.getWidth();
  56.                 min=Gdx.graphics.getHeight()<Gdx.graphics.getWidth()?Gdx.graphics.getHeight():Gdx.graphics.getWidth();
  57.                 if(!hasini){
  58.                         batch=new SpriteBatch();
  59.                         //这里使用了TexturePacker工具将几张图片打包然后一次性载入,具体如何使用大家可以查看官方文档。
  60.                         pages=new TextureRegion[5];
  61.                         pager=new TextureAtlas(Gdx.files.internal("pack"));
  62.                         pages[0]=pager.findRegion("1");
  63.                         pages[1]=pager.findRegion("2");
  64.                         pages[2]=pager.findRegion("3");
  65.                         pages[3]=pager.findRegion("4");
  66.                         pages[4]=pager.findRegion("5");
  67.                         hasini=true;               
  68.                 }
  69.                 //将当前Screen加入按键和手势监听队列
  70.                 InputMultiplexer multiplexer = new InputMultiplexer();
  71.                 multiplexer.addProcessor(this);
  72.                 multiplexer.addProcessor(new GestureDetector(this));
  73.                 Gdx.input.setInputProcessor(multiplexer);        }

  74.         @Override
  75.         public boolean fling(float arg0, float arg1) {
  76.                 // TODO Auto-generated method stub
  77.                 return false;
  78.         }

  79.         @Override
  80.         public boolean longPress(int arg0, int arg1) {
  81.                 // TODO Auto-generated method stub
  82.                 return false;
  83.         }

  84.         @Override
  85.         public boolean pan(int arg0, int arg1, int arg2, int arg3) {
  86.                 // TODO Auto-generated method stub
  87.                 return false;
  88.         }

  89.         @Override
  90.         public boolean pinch(Vector2 arg0, Vector2 arg1, Vector2 arg2, Vector2 arg3) {
  91.                 // TODO Auto-generated method stub
  92.                 return false;
  93.         }

  94.         @Override
  95.         public boolean tap(int arg0, int arg1, int arg2) {
  96.                 // TODO Auto-generated method stub
  97.                 return false;
  98.         }

  99.         @Override
  100.         public boolean touchDown(int arg0, int arg1, int arg2) {
  101.                 // TODO Auto-generated method stub
  102.                 return false;
  103.         }

  104.         @Override
  105.         public boolean zoom(float arg0, float arg1) {
  106.                 // TODO Auto-generated method stub
  107.                 return false;
  108.         }

  109.         @Override
  110.         public boolean keyDown(int arg0) {
  111.                 // TODO Auto-generated method stub
  112.                 //返回键按下的时候返回上一界面
  113.                 if(arg0==Input.Keys.BACK)
  114.                         activity.ag.setScreen(activity.mg);
  115.                 return false;
  116.         }

  117.         @Override
  118.         public boolean keyTyped(char arg0) {
  119.                 // TODO Auto-generated method stub
  120.                 return false;
  121.         }

  122.         @Override
  123.         public boolean keyUp(int arg0) {
  124.                 // TODO Auto-generated method stub
  125.                 return false;
  126.         }

  127.         @Override
  128.         public boolean scrolled(int arg0) {
  129.                 // TODO Auto-generated method stub
  130.                 return false;
  131.         }

  132.         @Override
  133.         public boolean touchDown(int arg0, int arg1, int arg2, int arg3) {
  134.                 // TODO Auto-generated method stub
  135.                 return false;
  136.         }

  137.         @Override
  138.         public boolean touchDragged(int arg0, int arg1, int arg2) {
  139.                 // TODO Auto-generated method stub
  140.                 return false;
  141.         }

  142.         @Override
  143.         public boolean touchMoved(int arg0, int arg1) {
  144.                 // TODO Auto-generated method stub
  145.                 return false;
  146.         }

  147.         @Override
  148.         public boolean touchUp(int arg0, int arg1, int arg2, int arg3) {
  149.                 // TODO Auto-generated method stub
  150.                 return false;
  151.         }

  152. }
复制代码
设置MyGame.java中新加入的按钮被按下时启动这个Screen,具体代码稍作修改大家可以看源码:
  1. toPager = new Button( new ButtonStyle(n1, n2, n3, 0f, 0f, 0f, 0f), "Start");
  2.                         toPager.setClickListener(new ClickListener() {
  3.                                 
  4.                                 @Override
  5.                                 public void click(Actor arg0, float arg1, float arg2) {
  6.                                         // TODO Auto-generated method stub
  7.                                         activity.ag.setScreen(activity.ps);
  8.                                 }
  9.                         });
  10.                         toPager.x=Gdx.graphics.getWidth()/3;
  11.                         toPager.y=Gdx.graphics.getWidth()/3;
  12.                         stage.addActor(toPager);
复制代码
运行一下,并按下刚才我们加入的那个按钮,看看效果:




这时候我们还是不能翻动。我们这个Screen还实现了GestureListener这个接口,我们在pan()函数中监听手势翻动作用,并且做出相应的处理.我们考虑一下极端情况,用于标记第一张图片位置的变量position最大值无非就是0,显示后面的图片的时候,这张图片的位置左移,其值一定小于0,但是又不能小于一定值,position的最小值对应于最后一张图片在最右侧并且无法继续右移。下面要用到这个范围,不然会出很严重的问题。


再介绍一下pan()这个回调函数中的四个参数:
  1. 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值的变量。
  1. float prex;
  2. float currentx;
复制代码
在touchDown()函数中标记currentx:
  1. currentx=arg0;
复制代码
在pan()函数中做出相应的处理,当然首先应该满足我们上面提到过的,postion有最大值和最小值,不可能超过这个范围,这一点非常重要。
  1. @Override
  2.         public boolean pan(int arg0, int arg1, int arg2, int arg3) {
  3.                 // TODO Auto-generated method stub
  4.                 //position应该有一定的范围
  5.                 System.out.println(position);
  6.                 if(position<=0&&position>=-(pages.length-1)*min){
  7.                         prex=currentx;
  8.                         currentx=arg0;
  9.                         if(position+currentx-prex<=0&&position+currentx-prex>=-(pages.length-1)*min)
  10.                                 position+=currentx-prex;
  11.                         else{
  12.                                 if(position+currentx-prex>0)
  13.                                         position=0;
  14.                                 if(position+currentx-prex<-(pages.length-1)*min)
  15.                                         position=-(pages.length-1)*min;
  16.                                        
  17.                         }
  18.                 }
  19.                 return false;
  20.         }

复制代码
运行一下,看看效果:



我们发现,完全可以正常滑动了,不过还有一个小问题,整个页面的显示完全依赖我们的滑动,而不是像我们需要仿的Launcher滑动有个自动吸附的功能,也就是当滑动到一定程度的时候会自动跳转到下一个页面。因此我们还需要做进一步的处理这里我们认为一张图片翻过一半的时候就应该跳转到下一张图片。我们在render()函数中实现这个效果,在手指按下的时候不回弹,手指松开后进行回弹的动作。我们需要在PageScreen.java中添加一个变量,用于回弹的标记:
  1. float targetposition;
复制代码
修改后的render()函数如下,复杂的地方下面都做了注释:
  1. @Override
  2.         public void render(float arg0) {
  3.                 // TODO Auto-generated method stub
  4.                 Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  5.                 Gdx.gl.glClearColor(0f,0f,0f,0f);
  6.                 batch.begin();
  7.                 for(i=0;i<pages.length;i++)
  8.                         batch.draw(pages[i],position+i*min, 0,min,max);
  9.                 batch.end();
  10.                 //用户放手时才进行回弹
  11.                 if(!Gdx.input.isTouched()){
  12.                         //巧妙的用一个取整数的函数来表示一张图片翻过一半的时候就应该跳转到下一张图片的效果
  13.                         targetposition=(int)((position-0.5f*min)/min)*min;
  14.                         if(targetposition<position){
  15.                                 //注意不能越界,min/480f是一个因子,用于分辨率适配,让回弹速度和分辨率搭配得协调一些
  16.                                 if(position-20*min/480f<targetposition)
  17.                                         position=targetposition;
  18.                                 else
  19.                                         position-=20*min/480f;
  20.                         }
  21.                         if(targetposition>position)
  22.                                 //注意不能越界
  23.                                 if(position+20*min/480f>targetposition)
  24.                                         position=targetposition;
  25.                                 else
  26.                                         position+=20*min/480f;
  27.                 }
  28.         }
复制代码
运行一下:




功能完全正常效果也不错,而且由于使用了Screen实现,在切换界面的时候非常流畅,我们可以用它来实现libgdx游戏中的帮助效果。


Testin ID:ilovemkey@gmail.com 总的而言这个平台真的非常好用!我正是用这个平台发现了现在写的这个应用的一些内存管理方面的问题。另外建议能够在测试报告中看到某一台机型在整个执行过程中的cpu和内存占用的变化情况,这样可以更快地锁定问题。感谢Itestin让测试变得轻松了太多太多!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
君见一叶舟,出没风波里

61

主题

425

帖子

2533

安币

Android大神

Rank: 6Rank: 6

QQ达人

发表于 2012-7-26 17:00:00 | 显示全部楼层
我顶,我顶,再顶,最后顶顶你的fei,哈哈哈

30

主题

350

帖子

1089

安币

Android大神

Rank: 6Rank: 6

QQ达人

 楼主| 发表于 2012-7-26 17:01:02 | 显示全部楼层
zyz 发表于 2012-7-26 17:00
我顶,我顶,再顶,最后顶顶你的fei,哈哈哈

{:4_137:}fei你妹
君见一叶舟,出没风波里

12

主题

57

帖子

151

安币

程序猿

Rank: 2

发表于 2012-7-26 17:01:10 | 显示全部楼层
有才有才太有才了{:soso_e179:}

30

主题

350

帖子

1089

安币

Android大神

Rank: 6Rank: 6

QQ达人

 楼主| 发表于 2012-7-26 17:01:38 | 显示全部楼层
红太郎在绵阳 发表于 2012-7-26 17:01
有才有才太有才了

艳姐来了!!!艳姐来了!!!{:Skateboard:}
君见一叶舟,出没风波里

61

主题

425

帖子

2533

安币

Android大神

Rank: 6Rank: 6

QQ达人

发表于 2012-7-26 17:07:57 | 显示全部楼层
耒佲請ぁ留埗 发表于 2012-7-26 17:01
fei你妹

哥们,是你叫大家来顶的啊。
哈哈哈
android的人生是?

30

主题

350

帖子

1089

安币

Android大神

Rank: 6Rank: 6

QQ达人

 楼主| 发表于 2012-7-26 17:08:37 | 显示全部楼层
zyz 发表于 2012-7-26 17:07
哥们,是你叫大家来顶的啊。
哈哈哈

{:Black Line:}不要揭穿我啦
君见一叶舟,出没风波里

61

主题

425

帖子

2533

安币

Android大神

Rank: 6Rank: 6

QQ达人

发表于 2012-7-26 17:09:04 | 显示全部楼层
哥们,弄得不错,我也觉得testin杯是你的,
向你学习啊
android的人生是?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )