#Testin杯#Mkey libgdx游戏引擎教程实战篇(六)移植俄罗斯方块(附源码)

163
回复
1115960
查看
  [复制链接]

30

主题

350

帖子

1089

安币

Android大神

Rank: 6Rank: 6

QQ达人

原创 发表于 2012-7-12 18:07:23 | 显示全部楼层 |阅读模式
本帖最后由 耒佲請ぁ留埗 于 2012-8-3 11:31 编辑



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

第一讲: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


移植素材SDK版本俄罗斯方块源码下载:


本讲移植后的源码:


  我们今天继续上次 俄罗斯方块移植第五讲的内容,在第四讲基本结束的时候,我们已经基本实现了游戏的功能,但一些最主要的功能都没有添加进去,如存档,退出提示等等。

   为了体现libgdx和SDK版本的不同,我们先添加一个粒子系统的效果。不然我们为什么要用游戏引擎做游戏?就是因为它在游戏开发方面比SDK更强大,否则我们直接用SDK开发好了。这个效果已经在第三讲实现过了,没有看过的同学可以看看。我们直接把这段代码复制进来。(复制到UiScreen的render()函数里,当然对应新增加的变量要自行添加,对应的particle.p和particle.png放到asset文件夹下)。





   粒子效果出来了。我们继续下一步的工作。我们接下来需要原SDK版下方滑动开始的效果,首先对照一下,下方是原SDK版本的开始界面,注意看到下方有一个可以滑动用于开始游戏的滑块。

        


    我们将原来SDK版本的中构成滑块的图片资源经过修改后复制到新的libgdx版本中去,放在工程的assets文件夹下



注意我们这里把底座图片



    换成一张空的图片(背景透明,png格式),空图片的大小为1024*128(还记得libgdx的要求吗,图片的边长必须是2的幂次),滑块图片我们稍作处理,也变成2的幂次。


         然后我们这里教大家使用Libgdx里面一个很方便的控件,模拟SDK版本中的滑块效果,这是一个封装好的类,Slider。我们先来看看libgdx 0.9.4中的官方文档中是怎么说的。
        
java.lang.Object
  |com.badlogic.gdx.scenes.scene2d.Actor
      |com.badlogic.gdx.scenes.scene2d.ui.Widget
          |com.badlogic.gdx.scenes.scene2d.ui.Slider


我们可以看到,所谓的滑块类Slider也是一个Actor,那么它也要加在舞台stage中绘制


我们来看看Slider的构造函数:




    我们今天用第二种构造函数(其实第三种和第二种的区别只在于第三种在创建时给Slider取了一个名字),至于第一种和第四种的用法大家可以参见官方文档,特别是Skin的用法大家可以看一看,很有帮助。


我们将修改好的UiScreen里关于
  1. Button start;
复制代码
的所有代码全部删掉,因为我们不再需要用这个按钮来触发事件了,我们改用一个滑块类Slider来触发事件,因此我们完全可以抛弃这个按钮了。

我们添加一个Slider变量:
  1. Slider slider;
复制代码
UiScreen.javashow()函数中对它进行初始化,我们根据构造函数的需要传入相应的参数,其中我们用到了libgdx中的一个类,NinePatch,相应的使用可以参见巴士内帖子:

android游戏开发框架libgdx的使用(五)--舞台和常用UI类

http://www.apkbus.com/android-19751-1-1.html

其实我们这里只是简单构造一个NinePatch,所以NinePatch如何使用其实也不用深究了。

这里的Ninepatch的构造函数里面的参数在这里是可以随便设定的,因为我们从Slider构造函数中需要的SliderStyle可以看出:



第一个NinePatch中的图片是底座的图片,而我前面做好的底座的图片其实是一张背景为透明的空图片,所以参数可以随便设定没有任何影响,而第二个参数TextrureRegion是滑块的图片。由此我们可以构造以下语句:
  1. NinePatch n1 = new NinePatch(new Texture(Gdx.files.internal("pla.png")), 14, 14, 18, 18);
  2. bar=new Texture(Gdx.files.internal("btn_blue.png"));
  3. slider=new Slider(0,min,1f,new SliderStyle(n1, new TextureRegion(new Texture(Gdx.files.internal("btn_blue.png")), 0, 0, 100, 96)));
复制代码
这里再顺便解释一下
Slider
构造函数
中的前三个参数的意思。



官方文档中是这样说的:
“Themin and max values determine the range the values of this slider can take on,the steps parameter specifies the distance between individual values. E.g. mincould be 4, max could be 10 and steps could be 0.2, giving you a total of 30values, 4.0 4.2, 4.4 and so on.”

也就是说,min和max值分别代表了这个Slider可以代表的最大值和最小值,而一个Slider最左端的值就是min,最右端的值就是max,至于第三个参数也很好理解,step就是步长,比如step是1,min是10,max是20,那么滑块根据滑动的不同距离就可以取到,10,11,12,13…20等等,从这里我们也可以看出,真正决定滑块每滑动一步在屏幕上移动的距离是和(max-min)和step两个值有关的,step越大,每动一下滑块在屏幕上移动的距离就越远,从某种角度上来说滑动就显得生涩。


   我们现在还没有为Slider添加监听事件,但的的确确这个slider已经构造好了,当然我们还要手动设置一下Slider的长度,在官方文档下有这么一句话:
“Thepreferred width of a slider is 140”

也就是说,默认的Slider长度是140,为了确认这一点,我们先来运行一下,当然运行之前还要把这个Slider加入舞台才能正确显示:
  1. stage.addActor(slider);
复制代码



    我们看到,这个时候我其实已经将滑块滑到底了,但是我们又可以清楚地根据粒子系统的轨迹看出我的手已经滑过了很远的距离,可是滑块依然不再前进,因为它已经滑到底了。另外,我们当前使用的测试机的分辨率是800*480的,即宽就是480,我们对比一下140所在的位置,发现确实差不多在140的位置滑块就滑到头了,为了使滑块横跨整个屏幕,我们添加如下的一条语句:
  1. //把滑块的长度设为宽度。
  2. slider.width=min;
复制代码
再运行一下看看效果:




大家可以看到,这一次是滑动到头了。
但是我们滑动到头以后并没有添加触发事件,因此我们滑动到头以后也不会有任何变化。
我们再查看一下API文档:




我们发现可以给Slider设置一个监听器,监听Slider。
在Slider构造完成后添加监听器:
  1. slider.setValueChangedListener(new ValueChangedListener() {
  2.                         
  3.                         @Override
  4.                         public void changed(Slider arg0, float arg1) {
  5.                                 // TODO Auto-generated method stub
  6.                                 if(!sliderFinished&&(int)arg1==arg0.width){
  7.                                     sliderFinished=true;
  8.                                         activity.tg.setScreen(activity.gs);
  9.                                 }
  10.                         }
  11.                 });
复制代码
    其中我们在UiScreen.java中添加了一个boolean变量sliderFinished,用于标记,作用很显然,就是为了防止重复触发事件,因为在实际操作用,我们手在滑动滑块时很可能在将滑块划到底时手不立即松开,那么就会触发多次事件,这是我们不想看到的,因此,我们做一个标记,保证setScreen的事件只触发一次。
   现在程序中的Slider就添加完毕了,也可以正常使用了,但是我们发现,滑块只划到一半的时候,并不会回到原位,而是停留在该位置,不会自动复位。那么我们就要认为给它复位了。
我们查看Slider的官方文档,发现有如下方法:






   这两个方法可以判断当前Slider是否正在被拖拽或者被按下。我们在UiScreen.java里面处理这些事件,用来实现复位的功能。
我们只要在UiScreen.java的render()函数中加上这么一段代码:
  1. if(!slider.isDragging()&&slider.getValue()>10){
  2.                         slider.setValue(slider.getValue()-10);
  3.                 }
复制代码
   表示在没有拖拽的情况下滑块缓慢复位。

   运行一下,效果正常,在滑块拖动到头的时候进入游戏界面。


   这一讲我们只修改了UiScreen.java这一个源文件,因此我们把这次修改后的完整代码贴出来,其中还有一些小修改,在程序中都做了注释:

修改后的UiScreen.java完整代码:
  1. public class UiScreen implements Screen {
  2.         Texture texture;
  3.         TextureRegion background;
  4.         boolean hasini;
  5.         SpriteBatch batch;
  6.         Stage stage;
  7.         Slider slider;
  8.         int width;
  9.         int height;
  10.         //边长的最大值和最小值
  11.         int max;
  12.         int min;
  13.         Texture tx1;
  14.         Texture tx2;
  15.         Texture tx3;
  16.         Texture bar;
  17.         UiActivity activity;
  18.         
  19.         ParticleEffect particle;
  20.         ParticleEffect tem;
  21.         ParticleEffectPool particlepool;
  22.         ArrayList<ParticleEffect> particlelist;
  23.         boolean sliderFinished;
  24.         
  25.         
  26.         public UiScreen(UiActivity activity){
  27.                 super();
  28.                 this.activity=activity;
  29.                 // TODO Auto-generated constructor stub
  30.         }

  31.         @Override
  32.         public void dispose() {
  33.                 // TODO Auto-generated method stub

  34.         }

  35.         @Override
  36.         public void hide() {
  37.                 // TODO Auto-generated method stub
  38.         }

  39.         @Override
  40.         public void pause() {
  41.                 // TODO Auto-generated method stub
  42.         }

  43.         @Override
  44.         public void render(float arg0) {
  45.                 // TODO Auto-generated method stub
  46.                 Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  47.                 Gdx.gl.glClearColor(0f,0f,0f,0f);
  48.                
  49.                 batch.begin();
  50.                 batch.draw(background,0,0,min,max);
  51.                 batch.end();
  52.                
  53.                 if(!slider.isDragging()&&slider.getValue()>10){
  54.                         slider.setValue(slider.getValue()-10);
  55.                 }
  56.                     if(Gdx.input.isTouched()){
  57.                             //当此触摸点与上一触摸点距离大于一定值的时候触发新的粒子系统,由此减小系统负担
  58.                             tem=particlepool.obtain();
  59.                             tem.setPosition(Gdx.input.getX(),Gdx.graphics.getHeight()-Gdx.input.getY());
  60.                             particlelist.add(tem);
  61.                     }
  62.                     batch.begin();
  63.             for(int i=0;i<particlelist.size();i++){
  64.                     particlelist.get(i).draw(batch, Gdx.graphics.getDeltaTime());
  65.             }
  66.             batch.end();
  67.    
  68.             //清除已经播放完成的粒子系统
  69.             ParticleEffect temparticle;
  70.             for(int i=0;i<particlelist.size();i++){
  71.                     temparticle=particlelist.get(i);
  72.                         if(temparticle.isComplete()){
  73.                                 particlelist.remove(i);
  74.                         }
  75.             }
  76.                
  77.                 //舞台绘制要在背景绘制之后,不然背景会覆盖在按钮表面,我们就看不到按钮了
  78.                 stage.act(Gdx.graphics.getDeltaTime());
  79.                 stage.draw();
  80.         }

  81.         @Override
  82.         public void resize(int arg0, int arg1) {
  83.                 // TODO Auto-generated method stub

  84.         }

  85.         @Override
  86.         public void resume() {
  87.                 // TODO Auto-generated method stub

  88.         }
  89.         

  90.         @Override
  91.         public void show() {
  92.                 // TODO Auto-generated method stub
  93.                
  94.                 //做一个简单的适配。这里解释一下为什么不直接令max=height,原因在于有时候我们从锁屏回到游戏,
  95.                 //从横屏切换到竖屏或者从竖屏切换到横屏的时候,libGdx有时候会来不及切换,也就是说我们可能
  96.                 //getWidth得到的是实际的height值,getHeight得到的是实际的width值,所以这里增加一个长宽哪一个
  97.                 //更大的语句,这样就不会出错了
  98.                 width=Gdx.graphics.getWidth();
  99.                 height=Gdx.graphics.getHeight();
  100.                 max=width>height?width:height;
  101.                 min=width>height?height:width;
  102.                 //再做一个简单的适配
  103.                 if(max>=320&&max<480)
  104.                         max=320;
  105.                 if(max>=480&&max<800)
  106.                         max=480;
  107.                 if(max>=800)
  108.                         max=800;
  109.                
  110.                 //将滑块标记重新初始化
  111.                 sliderFinished=false;
  112.                
  113.                 if(!hasini){
  114.                 batch=new SpriteBatch();
  115.                 stage=new Stage(min,max,true);
  116.                 particle = new ParticleEffect();
  117.                 particle.load(Gdx.files.internal("particle.p"), Gdx.files.internal(""));
  118.                 particlepool=new ParticleEffectPool(particle, 5, 10);
  119.                 particlelist=new ArrayList<ParticleEffect>();
  120.                 texture=new Texture(Gdx.files.internal("background"+max+".jpg"));
  121.                
  122.                

  123.                
  124.                 //重点在这条语句,我们只取了texture的一部分,红色的多余部分我们没有取
  125.                 background=new TextureRegion(texture, 0, 0, min, max);
  126.                
  127.                 NinePatch n1 = new NinePatch(new Texture(Gdx.files.internal("pla.png")), 14, 14, 18, 18);
  128.                 bar=new Texture(Gdx.files.internal("btn_blue.png"));
  129.                
  130.                 slider=new Slider(0,min,1f,new SliderStyle(n1, new TextureRegion(new Texture(Gdx.files.internal("btn_blue.png")), 0, 0, 100, 96)));
  131.                 slider.setValueChangedListener(new ValueChangedListener() {
  132.                         
  133.                         @Override
  134.                         public void changed(Slider arg0, float arg1) {
  135.                                 // TODO Auto-generated method stub
  136.                                 if(!sliderFinished&&(int)arg1==arg0.width){
  137.                                     sliderFinished=true;
  138.                                         activity.tg.setScreen(activity.gs);
  139.                                 }
  140.                         }
  141.                 });
  142.                 //把滑块的长度设为宽度。
  143.                 slider.width=min;
  144.                 stage.addActor(slider);
  145.                 hasini=true;
  146.                 }
  147.                 //这句话是必须的,而且在if(hasini)之外,无论资源是否加载完成,每次显示的时候我们将当前屏幕
  148.                 //设置能够接受用户输入
  149.                 Gdx.input.setInputProcessor(stage);
  150.         }

  151. }
复制代码
    这一讲我们介绍了libgdx中Slider控件的用法。下面几讲我们将继续完善程序,如存档功能等等。


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

本帖子中包含更多资源

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

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

2826

主题

7684

帖子

9600

安币

管理员

Rank: 9Rank: 9Rank: 9

QQ达人最佳新人活跃会员热心会员推广达人灌水之王突出贡献

QQ
发表于 2012-7-12 18:13:31 | 显示全部楼层
这个很棒啊!!!!

0

主题

59

帖子

120

安币

程序猿

Rank: 2

发表于 2012-7-12 18:55:22 | 显示全部楼层
很不错,楼主幸苦啦。。。

2

主题

104

帖子

1029

安币

Android大神

Rank: 6Rank: 6

发表于 2012-7-12 21:02:34 | 显示全部楼层
{:soso_e179:}

39

主题

342

帖子

494

安币

禁止发言

QQ达人

发表于 2012-7-12 22:57:01 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
www.027hsdn.com 武汉电脑回收,武汉二手电脑回收

1

主题

19

帖子

125

安币

程序猿

Rank: 2

发表于 2012-7-13 08:37:08 | 显示全部楼层

这个是什么错误?!

本帖子中包含更多资源

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

x

30

主题

350

帖子

1089

安币

Android大神

Rank: 6Rank: 6

QQ达人

 楼主| 发表于 2012-7-13 09:26:17 | 显示全部楼层
龙歌笑 发表于 2012-7-13 08:37
这个是什么错误?!

你是真的看不懂吗?你没有在Manifest中注册这个activity
君见一叶舟,出没风波里

52

主题

457

帖子

1390

安币

Android大神

Rank: 6Rank: 6

QQ达人

发表于 2012-7-13 09:55:32 | 显示全部楼层
还是很有价值的哦!
项目快结束了,终于可以休息了!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

扫一扫关注我们

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